]> 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 %    Rec601Luminance  0.298839R + 0.586811G + 0.114350B
2103 %    Rec709Luma       0.21260R' + 0.71520G' + 0.07220B'
2104 %    Rec709Luminance  0.21260R + 0.71520G + 0.07220B
2105 %    Brightness       max(R, G, B)
2106 %    Lightness        (min(R, G, B) + max(R, G, B)) / 2.0
2107 %    RMS              (R'^2 + G'^2 + B'^2) / 3.0
2108 %    Average          (R' + G' + B') / 3.0
2109 %
2110 %  The format of the GetPixelIntensity method is:
2111 %
2112 %      MagickRealType GetPixelIntensity(const Image *image,
2113 %        const Quantum *pixel)
2114 %
2115 %  A description of each parameter follows:
2116 %
2117 %    o image: the image.
2118 %
2119 %    o pixel: Specifies a pointer to a Quantum structure.
2120 %
2121 */
2122
2123 static inline MagickRealType MagickMax(const MagickRealType x,
2124   const MagickRealType y)
2125 {
2126   if (x > y)
2127     return(x);
2128   return(y);
2129 }
2130
2131 static inline MagickRealType MagickMin(const MagickRealType x,
2132   const MagickRealType y)
2133 {
2134   if (x < y)
2135     return(x);
2136   return(y);
2137 }
2138
2139 MagickExport MagickRealType GetPixelIntensity(const Image *restrict image,
2140   const Quantum *restrict pixel)
2141 {
2142   MagickRealType
2143     blue,
2144     green,
2145     red,
2146     intensity;
2147
2148   if (image->colorspace == GRAYColorspace)
2149     return((MagickRealType) pixel[image->channel_map[GrayPixelChannel].offset]);
2150   red=(MagickRealType) pixel[image->channel_map[RedPixelChannel].offset];
2151   green=(MagickRealType) pixel[image->channel_map[GreenPixelChannel].offset];
2152   blue=(MagickRealType) pixel[image->channel_map[BluePixelChannel].offset];
2153   switch (image->intensity)
2154   {
2155     case AveragePixelIntensityMethod:
2156     {
2157       intensity=(red+green+blue)/3.0;
2158       break;
2159     }
2160     case BrightnessPixelIntensityMethod:
2161     {
2162       intensity=MagickMax(MagickMax(red,green),blue);
2163       break;
2164     }
2165     case LightnessPixelIntensityMethod:
2166     {
2167       intensity=MagickMin(MagickMin(red,green),blue);
2168       break;
2169     }
2170     case Rec601LumaPixelIntensityMethod:
2171     {
2172       intensity=0.298839f*red+0.586811f*green+0.114350f*blue;
2173       break;
2174     }
2175     case Rec601LuminancePixelIntensityMethod:
2176     {
2177       if (image->colorspace == sRGBColorspace)
2178         {
2179           red=DecodePixelGamma(red);
2180           green=DecodePixelGamma(green);
2181           blue=DecodePixelGamma(blue);
2182         }
2183       intensity=0.298839f*red+0.586811f*green+0.114350f*blue;
2184       break;
2185     }
2186     case Rec709LumaPixelIntensityMethod:
2187     default:
2188     {
2189       intensity=0.21260f*red+0.71520f*green+0.07220f*blue;
2190       break;
2191     }
2192     case Rec709LuminancePixelIntensityMethod:
2193     {
2194       if (image->colorspace == sRGBColorspace)
2195         {
2196           red=DecodePixelGamma(red);
2197           green=DecodePixelGamma(green);
2198           blue=DecodePixelGamma(blue);
2199         }
2200       intensity=0.21260f*red+0.71520f*green+0.07220f*blue;
2201       break;
2202     }
2203     case RMSPixelIntensityMethod:
2204     {
2205       intensity=(MagickRealType) sqrt((double) red*red+green*green+blue*blue);
2206       break;
2207     }
2208   }
2209   return(intensity);
2210 }
2211 \f
2212 /*
2213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214 %                                                                             %
2215 %                                                                             %
2216 %                                                                             %
2217 %   I m p o r t I m a g e P i x e l s                                         %
2218 %                                                                             %
2219 %                                                                             %
2220 %                                                                             %
2221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222 %
2223 %  ImportImagePixels() accepts pixel data and stores in the image at the
2224 %  location you specify.  The method returns MagickTrue on success otherwise
2225 %  MagickFalse if an error is encountered.  The pixel data can be either char,
2226 %  Quantum, short int, unsigned int, unsigned long long, float, or double in
2227 %  the order specified by map.
2228 %
2229 %  Suppose your want to upload the first scanline of a 640x480 image from
2230 %  character data in red-green-blue order:
2231 %
2232 %      ImportImagePixels(image,0,0,640,1,"RGB",CharPixel,pixels);
2233 %
2234 %  The format of the ImportImagePixels method is:
2235 %
2236 %      MagickBooleanType ImportImagePixels(Image *image,const ssize_t x,
2237 %        const ssize_t y,const size_t width,const size_t height,
2238 %        const char *map,const StorageType type,const void *pixels,
2239 %        ExceptionInfo *exception)
2240 %
2241 %  A description of each parameter follows:
2242 %
2243 %    o image: the image.
2244 %
2245 %    o x,y,width,height:  These values define the perimeter
2246 %      of a region of pixels you want to define.
2247 %
2248 %    o map:  This string reflects the expected ordering of the pixel array.
2249 %      It can be any combination or order of R = red, G = green, B = blue,
2250 %      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
2251 %      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
2252 %      P = pad.
2253 %
2254 %    o type: Define the data type of the pixels.  Float and double types are
2255 %      normalized to [0..1] otherwise [0..QuantumRange].  Choose from these
2256 %      types: CharPixel (char *), DoublePixel (double *), FloatPixel (float *),
2257 %      LongPixel (unsigned int *), LongLongPixel (unsigned long long *),
2258 %      QuantumPixel (Quantum *), or ShortPixel (unsigned short *).
2259 %
2260 %    o pixels: This array of values contain the pixel components as defined by
2261 %      map and type.  You must preallocate this array where the expected
2262 %      length varies depending on the values of width, height, map, and type.
2263 %
2264 %    o exception: return any errors or warnings in this structure.
2265 %
2266 */
2267
2268 static void ImportCharPixel(Image *image,const RectangleInfo *roi,
2269   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2270   ExceptionInfo *exception)
2271 {
2272   register const unsigned char
2273     *restrict p;
2274
2275   register Quantum
2276     *restrict q;
2277
2278   register ssize_t
2279     x;
2280
2281   size_t
2282     length;
2283
2284   ssize_t
2285     y;
2286
2287   p=(const unsigned char *) pixels;
2288   if (LocaleCompare(map,"BGR") == 0)
2289     {
2290       for (y=0; y < (ssize_t) roi->height; y++)
2291       {
2292         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2293         if (q == (Quantum *) NULL)
2294           break;
2295         for (x=0; x < (ssize_t) roi->width; x++)
2296         {
2297           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2298           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2299           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2300           q+=GetPixelChannels(image);
2301         }
2302         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2303           break;
2304       }
2305       return;
2306     }
2307   if (LocaleCompare(map,"BGRA") == 0)
2308     {
2309       for (y=0; y < (ssize_t) roi->height; y++)
2310       {
2311         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2312         if (q == (Quantum *) NULL)
2313           break;
2314         for (x=0; x < (ssize_t) roi->width; x++)
2315         {
2316           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2317           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2318           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2319           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2320           q+=GetPixelChannels(image);
2321         }
2322         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2323           break;
2324       }
2325       return;
2326     }
2327   if (LocaleCompare(map,"BGRO") == 0)
2328     {
2329       for (y=0; y < (ssize_t) roi->height; y++)
2330       {
2331         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2332         if (q == (Quantum *) NULL)
2333           break;
2334         for (x=0; x < (ssize_t) roi->width; x++)
2335         {
2336           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2337           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2338           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2339           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2340           q+=GetPixelChannels(image);
2341         }
2342         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2343           break;
2344       }
2345       return;
2346     }
2347   if (LocaleCompare(map,"BGRP") == 0)
2348     {
2349       for (y=0; y < (ssize_t) roi->height; y++)
2350       {
2351         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2352         if (q == (Quantum *) NULL)
2353           break;
2354         for (x=0; x < (ssize_t) roi->width; x++)
2355         {
2356           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2357           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2358           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2359           p++;
2360           q+=GetPixelChannels(image);
2361         }
2362         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2363           break;
2364       }
2365       return;
2366     }
2367   if (LocaleCompare(map,"I") == 0)
2368     {
2369       for (y=0; y < (ssize_t) roi->height; y++)
2370       {
2371         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2372         if (q == (Quantum *) NULL)
2373           break;
2374         for (x=0; x < (ssize_t) roi->width; x++)
2375         {
2376           SetPixelGray(image,ScaleCharToQuantum(*p++),q);
2377           q+=GetPixelChannels(image);
2378         }
2379         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2380           break;
2381       }
2382       return;
2383     }
2384   if (LocaleCompare(map,"RGB") == 0)
2385     {
2386       for (y=0; y < (ssize_t) roi->height; y++)
2387       {
2388         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2389         if (q == (Quantum *) NULL)
2390           break;
2391         for (x=0; x < (ssize_t) roi->width; x++)
2392         {
2393           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2394           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2395           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2396           q+=GetPixelChannels(image);
2397         }
2398         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2399           break;
2400       }
2401       return;
2402     }
2403   if (LocaleCompare(map,"RGBA") == 0)
2404     {
2405       for (y=0; y < (ssize_t) roi->height; y++)
2406       {
2407         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2408         if (q == (Quantum *) NULL)
2409           break;
2410         for (x=0; x < (ssize_t) roi->width; x++)
2411         {
2412           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2413           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2414           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2415           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2416           q+=GetPixelChannels(image);
2417         }
2418         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2419           break;
2420       }
2421       return;
2422     }
2423   if (LocaleCompare(map,"RGBO") == 0)
2424     {
2425       for (y=0; y < (ssize_t) roi->height; y++)
2426       {
2427         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2428         if (q == (Quantum *) NULL)
2429           break;
2430         for (x=0; x < (ssize_t) roi->width; x++)
2431         {
2432           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2433           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2434           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2435           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2436           q+=GetPixelChannels(image);
2437         }
2438         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2439           break;
2440       }
2441       return;
2442     }
2443   if (LocaleCompare(map,"RGBP") == 0)
2444     {
2445       for (y=0; y < (ssize_t) roi->height; y++)
2446       {
2447         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2448         if (q == (Quantum *) NULL)
2449           break;
2450         for (x=0; x < (ssize_t) roi->width; x++)
2451         {
2452           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2453           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2454           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2455           p++;
2456           q+=GetPixelChannels(image);
2457         }
2458         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2459           break;
2460       }
2461       return;
2462     }
2463   length=strlen(map);
2464   for (y=0; y < (ssize_t) roi->height; y++)
2465   {
2466     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2467     if (q == (Quantum *) NULL)
2468       break;
2469     for (x=0; x < (ssize_t) roi->width; x++)
2470     {
2471       register ssize_t
2472         i;
2473
2474       for (i=0; i < (ssize_t) length; i++)
2475       {
2476         switch (quantum_map[i])
2477         {
2478           case RedQuantum:
2479           case CyanQuantum:
2480           {
2481             SetPixelRed(image,ScaleCharToQuantum(*p),q);
2482             break;
2483           }
2484           case GreenQuantum:
2485           case MagentaQuantum:
2486           {
2487             SetPixelGreen(image,ScaleCharToQuantum(*p),q);
2488             break;
2489           }
2490           case BlueQuantum:
2491           case YellowQuantum:
2492           {
2493             SetPixelBlue(image,ScaleCharToQuantum(*p),q);
2494             break;
2495           }
2496           case AlphaQuantum:
2497           {
2498             SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
2499             break;
2500           }
2501           case OpacityQuantum:
2502           {
2503             SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
2504             break;
2505           }
2506           case BlackQuantum:
2507           {
2508             SetPixelBlack(image,ScaleCharToQuantum(*p),q);
2509             break;
2510           }
2511           case IndexQuantum:
2512           {
2513             SetPixelGray(image,ScaleCharToQuantum(*p),q);
2514             break;
2515           }
2516           default:
2517             break;
2518         }
2519         p++;
2520       }
2521       q+=GetPixelChannels(image);
2522     }
2523     if (SyncAuthenticPixels(image,exception) == MagickFalse)
2524       break;
2525   }
2526 }
2527
2528 static void ImportDoublePixel(Image *image,const RectangleInfo *roi,
2529   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2530   ExceptionInfo *exception)
2531 {
2532   register const double
2533     *restrict p;
2534
2535   register Quantum
2536     *restrict q;
2537
2538   register ssize_t
2539     x;
2540
2541   size_t
2542     length;
2543
2544   ssize_t
2545     y;
2546
2547   p=(const double *) pixels;
2548   if (LocaleCompare(map,"BGR") == 0)
2549     {
2550       for (y=0; y < (ssize_t) roi->height; y++)
2551       {
2552         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2553         if (q == (Quantum *) NULL)
2554           break;
2555         for (x=0; x < (ssize_t) roi->width; x++)
2556         {
2557           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2558           p++;
2559           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2560           p++;
2561           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2562           p++;
2563           q+=GetPixelChannels(image);
2564         }
2565         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2566           break;
2567       }
2568       return;
2569     }
2570   if (LocaleCompare(map,"BGRA") == 0)
2571     {
2572       for (y=0; y < (ssize_t) roi->height; y++)
2573       {
2574         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2575         if (q == (Quantum *) NULL)
2576           break;
2577         for (x=0; x < (ssize_t) roi->width; x++)
2578         {
2579           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2580           p++;
2581           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2582           p++;
2583           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2584           p++;
2585           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2586           p++;
2587           q+=GetPixelChannels(image);
2588         }
2589         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2590           break;
2591       }
2592       return;
2593     }
2594   if (LocaleCompare(map,"BGRP") == 0)
2595     {
2596       for (y=0; y < (ssize_t) roi->height; y++)
2597       {
2598         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2599         if (q == (Quantum *) NULL)
2600           break;
2601         for (x=0; x < (ssize_t) roi->width; x++)
2602         {
2603           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2604           p++;
2605           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2606           p++;
2607           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2608           p++;
2609           p++;
2610           q+=GetPixelChannels(image);
2611         }
2612         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2613           break;
2614       }
2615       return;
2616     }
2617   if (LocaleCompare(map,"I") == 0)
2618     {
2619       for (y=0; y < (ssize_t) roi->height; y++)
2620       {
2621         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2622         if (q == (Quantum *) NULL)
2623           break;
2624         for (x=0; x < (ssize_t) roi->width; x++)
2625         {
2626           SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2627           p++;
2628           q+=GetPixelChannels(image);
2629         }
2630         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2631           break;
2632       }
2633       return;
2634     }
2635   if (LocaleCompare(map,"RGB") == 0)
2636     {
2637       for (y=0; y < (ssize_t) roi->height; y++)
2638       {
2639         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2640         if (q == (Quantum *) NULL)
2641           break;
2642         for (x=0; x < (ssize_t) roi->width; x++)
2643         {
2644           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2645           p++;
2646           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2647           p++;
2648           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2649           p++;
2650           q+=GetPixelChannels(image);
2651         }
2652         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2653           break;
2654       }
2655       return;
2656     }
2657   if (LocaleCompare(map,"RGBA") == 0)
2658     {
2659       for (y=0; y < (ssize_t) roi->height; y++)
2660       {
2661         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2662         if (q == (Quantum *) NULL)
2663           break;
2664         for (x=0; x < (ssize_t) roi->width; x++)
2665         {
2666           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2667           p++;
2668           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2669           p++;
2670           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2671           p++;
2672           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2673           p++;
2674           q+=GetPixelChannels(image);
2675         }
2676         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2677           break;
2678       }
2679       return;
2680     }
2681   if (LocaleCompare(map,"RGBP") == 0)
2682     {
2683       for (y=0; y < (ssize_t) roi->height; y++)
2684       {
2685         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2686         if (q == (Quantum *) NULL)
2687           break;
2688         for (x=0; x < (ssize_t) roi->width; x++)
2689         {
2690           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2691           p++;
2692           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2693           p++;
2694           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2695           p++;
2696           q+=GetPixelChannels(image);
2697         }
2698         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2699           break;
2700       }
2701       return;
2702     }
2703    length=strlen(map);
2704   for (y=0; y < (ssize_t) roi->height; y++)
2705   {
2706     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2707     if (q == (Quantum *) NULL)
2708       break;
2709     for (x=0; x < (ssize_t) roi->width; x++)
2710     {
2711       register ssize_t
2712         i;
2713
2714       for (i=0; i < (ssize_t) length; i++)
2715       {
2716         switch (quantum_map[i])
2717         {
2718           case RedQuantum:
2719           case CyanQuantum:
2720           {
2721             SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2722             break;
2723           }
2724           case GreenQuantum:
2725           case MagentaQuantum:
2726           {
2727             SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2728             break;
2729           }
2730           case BlueQuantum:
2731           case YellowQuantum:
2732           {
2733             SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2734             break;
2735           }
2736           case AlphaQuantum:
2737           {
2738             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2739             break;
2740           }
2741           case OpacityQuantum:
2742           {
2743             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2744             break;
2745           }
2746           case BlackQuantum:
2747           {
2748             SetPixelBlack(image,ClampToQuantum(QuantumRange*(*p)),q);
2749             break;
2750           }
2751           case IndexQuantum:
2752           {
2753             SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2754             break;
2755           }
2756           default:
2757             break;
2758         }
2759         p++;
2760       }
2761       q+=GetPixelChannels(image);
2762     }
2763     if (SyncAuthenticPixels(image,exception) == MagickFalse)
2764       break;
2765   }
2766 }
2767
2768 static void ImportFloatPixel(Image *image,const RectangleInfo *roi,
2769   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2770   ExceptionInfo *exception)
2771 {
2772   register const float
2773     *restrict p;
2774
2775   register Quantum
2776     *restrict q;
2777
2778   register ssize_t
2779     x;
2780
2781   size_t
2782     length;
2783
2784   ssize_t
2785     y;
2786
2787   p=(const float *) pixels;
2788   if (LocaleCompare(map,"BGR") == 0)
2789     {
2790       for (y=0; y < (ssize_t) roi->height; y++)
2791       {
2792         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2793         if (q == (Quantum *) NULL)
2794           break;
2795         for (x=0; x < (ssize_t) roi->width; x++)
2796         {
2797           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2798           p++;
2799           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2800           p++;
2801           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2802           p++;
2803           q+=GetPixelChannels(image);
2804         }
2805         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2806           break;
2807       }
2808       return;
2809     }
2810   if (LocaleCompare(map,"BGRA") == 0)
2811     {
2812       for (y=0; y < (ssize_t) roi->height; y++)
2813       {
2814         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2815         if (q == (Quantum *) NULL)
2816           break;
2817         for (x=0; x < (ssize_t) roi->width; x++)
2818         {
2819           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2820           p++;
2821           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2822           p++;
2823           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2824           p++;
2825           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2826           p++;
2827           q+=GetPixelChannels(image);
2828         }
2829         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2830           break;
2831       }
2832       return;
2833     }
2834   if (LocaleCompare(map,"BGRP") == 0)
2835     {
2836       for (y=0; y < (ssize_t) roi->height; y++)
2837       {
2838         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2839         if (q == (Quantum *) NULL)
2840           break;
2841         for (x=0; x < (ssize_t) roi->width; x++)
2842         {
2843           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2844           p++;
2845           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2846           p++;
2847           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2848           p++;
2849           p++;
2850           q+=GetPixelChannels(image);
2851         }
2852         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2853           break;
2854       }
2855       return;
2856     }
2857   if (LocaleCompare(map,"I") == 0)
2858     {
2859       for (y=0; y < (ssize_t) roi->height; y++)
2860       {
2861         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2862         if (q == (Quantum *) NULL)
2863           break;
2864         for (x=0; x < (ssize_t) roi->width; x++)
2865         {
2866           SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2867           p++;
2868           q+=GetPixelChannels(image);
2869         }
2870         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2871           break;
2872       }
2873       return;
2874     }
2875   if (LocaleCompare(map,"RGB") == 0)
2876     {
2877       for (y=0; y < (ssize_t) roi->height; y++)
2878       {
2879         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2880         if (q == (Quantum *) NULL)
2881           break;
2882         for (x=0; x < (ssize_t) roi->width; x++)
2883         {
2884           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2885           p++;
2886           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2887           p++;
2888           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2889           p++;
2890           q+=GetPixelChannels(image);
2891         }
2892         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2893           break;
2894       }
2895       return;
2896     }
2897   if (LocaleCompare(map,"RGBA") == 0)
2898     {
2899       for (y=0; y < (ssize_t) roi->height; y++)
2900       {
2901         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2902         if (q == (Quantum *) NULL)
2903           break;
2904         for (x=0; x < (ssize_t) roi->width; x++)
2905         {
2906           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2907           p++;
2908           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2909           p++;
2910           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2911           p++;
2912           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2913           p++;
2914           q+=GetPixelChannels(image);
2915         }
2916         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2917           break;
2918       }
2919       return;
2920     }
2921   if (LocaleCompare(map,"RGBP") == 0)
2922     {
2923       for (y=0; y < (ssize_t) roi->height; y++)
2924       {
2925         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2926         if (q == (Quantum *) NULL)
2927           break;
2928         for (x=0; x < (ssize_t) roi->width; x++)
2929         {
2930           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2931           p++;
2932           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2933           p++;
2934           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2935           p++;
2936           q+=GetPixelChannels(image);
2937         }
2938         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2939           break;
2940       }
2941       return;
2942     }
2943   length=strlen(map);
2944   for (y=0; y < (ssize_t) roi->height; y++)
2945   {
2946     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2947     if (q == (Quantum *) NULL)
2948       break;
2949     for (x=0; x < (ssize_t) roi->width; x++)
2950     {
2951       register ssize_t
2952         i;
2953
2954       for (i=0; i < (ssize_t) length; i++)
2955       {
2956         switch (quantum_map[i])
2957         {
2958           case RedQuantum:
2959           case CyanQuantum:
2960           {
2961             SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2962             break;
2963           }
2964           case GreenQuantum:
2965           case MagentaQuantum:
2966           {
2967             SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2968             break;
2969           }
2970           case BlueQuantum:
2971           case YellowQuantum:
2972           {
2973             SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2974             break;
2975           }
2976           case AlphaQuantum:
2977           {
2978             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2979             break;
2980           }
2981           case OpacityQuantum:
2982           {
2983             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2984             break;
2985           }
2986           case BlackQuantum:
2987           {
2988             SetPixelBlack(image,ClampToQuantum(QuantumRange*(*p)),q);
2989             break;
2990           }
2991           case IndexQuantum:
2992           {
2993             SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2994             break;
2995           }
2996           default:
2997             break;
2998         }
2999         p++;
3000       }
3001       q+=GetPixelChannels(image);
3002     }
3003     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3004       break;
3005   }
3006 }
3007
3008 static void ImportLongPixel(Image *image,const RectangleInfo *roi,
3009   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3010   ExceptionInfo *exception)
3011 {
3012   register const unsigned int
3013     *restrict p;
3014
3015   register Quantum
3016     *restrict q;
3017
3018   register ssize_t
3019     x;
3020
3021   size_t
3022     length;
3023
3024   ssize_t
3025     y;
3026
3027   p=(const unsigned int *) pixels;
3028   if (LocaleCompare(map,"BGR") == 0)
3029     {
3030       for (y=0; y < (ssize_t) roi->height; y++)
3031       {
3032         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3033         if (q == (Quantum *) NULL)
3034           break;
3035         for (x=0; x < (ssize_t) roi->width; x++)
3036         {
3037           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3038           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3039           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3040           q+=GetPixelChannels(image);
3041         }
3042         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3043           break;
3044       }
3045       return;
3046     }
3047   if (LocaleCompare(map,"BGRA") == 0)
3048     {
3049       for (y=0; y < (ssize_t) roi->height; y++)
3050       {
3051         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3052         if (q == (Quantum *) NULL)
3053           break;
3054         for (x=0; x < (ssize_t) roi->width; x++)
3055         {
3056           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3057           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3058           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3059           SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
3060           q+=GetPixelChannels(image);
3061         }
3062         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3063           break;
3064       }
3065       return;
3066     }
3067   if (LocaleCompare(map,"BGRP") == 0)
3068     {
3069       for (y=0; y < (ssize_t) roi->height; y++)
3070       {
3071         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3072         if (q == (Quantum *) NULL)
3073           break;
3074         for (x=0; x < (ssize_t) roi->width; x++)
3075         {
3076           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3077           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3078           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3079           p++;
3080           q+=GetPixelChannels(image);
3081         }
3082         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3083           break;
3084       }
3085       return;
3086     }
3087   if (LocaleCompare(map,"I") == 0)
3088     {
3089       for (y=0; y < (ssize_t) roi->height; y++)
3090       {
3091         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3092         if (q == (Quantum *) NULL)
3093           break;
3094         for (x=0; x < (ssize_t) roi->width; x++)
3095         {
3096           SetPixelGray(image,ScaleLongToQuantum(*p++),q);
3097           q+=GetPixelChannels(image);
3098         }
3099         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3100           break;
3101       }
3102       return;
3103     }
3104   if (LocaleCompare(map,"RGB") == 0)
3105     {
3106       for (y=0; y < (ssize_t) roi->height; y++)
3107       {
3108         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3109         if (q == (Quantum *) NULL)
3110           break;
3111         for (x=0; x < (ssize_t) roi->width; x++)
3112         {
3113           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3114           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3115           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3116           q+=GetPixelChannels(image);
3117         }
3118         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3119           break;
3120       }
3121       return;
3122     }
3123   if (LocaleCompare(map,"RGBA") == 0)
3124     {
3125       for (y=0; y < (ssize_t) roi->height; y++)
3126       {
3127         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3128         if (q == (Quantum *) NULL)
3129           break;
3130         for (x=0; x < (ssize_t) roi->width; x++)
3131         {
3132           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3133           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3134           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3135           SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
3136           q+=GetPixelChannels(image);
3137         }
3138         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3139           break;
3140       }
3141       return;
3142     }
3143   if (LocaleCompare(map,"RGBP") == 0)
3144     {
3145       for (y=0; y < (ssize_t) roi->height; y++)
3146       {
3147         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3148         if (q == (Quantum *) NULL)
3149           break;
3150         for (x=0; x < (ssize_t) roi->width; x++)
3151         {
3152           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3153           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3154           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3155           p++;
3156           q+=GetPixelChannels(image);
3157         }
3158         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3159           break;
3160       }
3161       return;
3162     }
3163   length=strlen(map);
3164   for (y=0; y < (ssize_t) roi->height; y++)
3165   {
3166     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3167     if (q == (Quantum *) NULL)
3168       break;
3169     for (x=0; x < (ssize_t) roi->width; x++)
3170     {
3171       register ssize_t
3172         i;
3173
3174       for (i=0; i < (ssize_t) length; i++)
3175       {
3176         switch (quantum_map[i])
3177         {
3178           case RedQuantum:
3179           case CyanQuantum:
3180           {
3181             SetPixelRed(image,ScaleLongToQuantum(*p),q);
3182             break;
3183           }
3184           case GreenQuantum:
3185           case MagentaQuantum:
3186           {
3187             SetPixelGreen(image,ScaleLongToQuantum(*p),q);
3188             break;
3189           }
3190           case BlueQuantum:
3191           case YellowQuantum:
3192           {
3193             SetPixelBlue(image,ScaleLongToQuantum(*p),q);
3194             break;
3195           }
3196           case AlphaQuantum:
3197           {
3198             SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
3199             break;
3200           }
3201           case OpacityQuantum:
3202           {
3203             SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
3204             break;
3205           }
3206           case BlackQuantum:
3207           {
3208             SetPixelBlack(image,ScaleLongToQuantum(*p),q);
3209             break;
3210           }
3211           case IndexQuantum:
3212           {
3213             SetPixelGray(image,ScaleLongToQuantum(*p),q);
3214             break;
3215           }
3216           default:
3217             break;
3218         }
3219         p++;
3220       }
3221       q+=GetPixelChannels(image);
3222     }
3223     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3224       break;
3225   }
3226 }
3227
3228 static void ImportLongLongPixel(Image *image,const RectangleInfo *roi,
3229   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3230   ExceptionInfo *exception)
3231 {
3232   register const MagickSizeType
3233     *restrict p;
3234
3235   register Quantum
3236     *restrict q;
3237
3238   register ssize_t
3239     x;
3240
3241   size_t
3242     length;
3243
3244   ssize_t
3245     y;
3246
3247   p=(const MagickSizeType *) pixels;
3248   if (LocaleCompare(map,"BGR") == 0)
3249     {
3250       for (y=0; y < (ssize_t) roi->height; y++)
3251       {
3252         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3253         if (q == (Quantum *) NULL)
3254           break;
3255         for (x=0; x < (ssize_t) roi->width; x++)
3256         {
3257           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3258           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3259           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3260           q+=GetPixelChannels(image);
3261         }
3262         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3263           break;
3264       }
3265       return;
3266     }
3267   if (LocaleCompare(map,"BGRA") == 0)
3268     {
3269       for (y=0; y < (ssize_t) roi->height; y++)
3270       {
3271         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3272         if (q == (Quantum *) NULL)
3273           break;
3274         for (x=0; x < (ssize_t) roi->width; x++)
3275         {
3276           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3277           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3278           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3279           SetPixelAlpha(image,ScaleLongLongToQuantum(*p++),q);
3280           q+=GetPixelChannels(image);
3281         }
3282         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3283           break;
3284       }
3285       return;
3286     }
3287   if (LocaleCompare(map,"BGRP") == 0)
3288     {
3289       for (y=0; y < (ssize_t) roi->height; y++)
3290       {
3291         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3292         if (q == (Quantum *) NULL)
3293           break;
3294         for (x=0; x < (ssize_t) roi->width; x++)
3295         {
3296           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3297           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3298           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3299           p++;
3300           q+=GetPixelChannels(image);
3301         }
3302         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3303           break;
3304       }
3305       return;
3306     }
3307   if (LocaleCompare(map,"I") == 0)
3308     {
3309       for (y=0; y < (ssize_t) roi->height; y++)
3310       {
3311         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3312         if (q == (Quantum *) NULL)
3313           break;
3314         for (x=0; x < (ssize_t) roi->width; x++)
3315         {
3316           SetPixelGray(image,ScaleLongLongToQuantum(*p++),q);
3317           q+=GetPixelChannels(image);
3318         }
3319         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3320           break;
3321       }
3322       return;
3323     }
3324   if (LocaleCompare(map,"RGB") == 0)
3325     {
3326       for (y=0; y < (ssize_t) roi->height; y++)
3327       {
3328         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3329         if (q == (Quantum *) NULL)
3330           break;
3331         for (x=0; x < (ssize_t) roi->width; x++)
3332         {
3333           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3334           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3335           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3336           q+=GetPixelChannels(image);
3337         }
3338         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3339           break;
3340       }
3341       return;
3342     }
3343   if (LocaleCompare(map,"RGBA") == 0)
3344     {
3345       for (y=0; y < (ssize_t) roi->height; y++)
3346       {
3347         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3348         if (q == (Quantum *) NULL)
3349           break;
3350         for (x=0; x < (ssize_t) roi->width; x++)
3351         {
3352           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3353           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3354           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3355           SetPixelAlpha(image,ScaleLongLongToQuantum(*p++),q);
3356           q+=GetPixelChannels(image);
3357         }
3358         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3359           break;
3360       }
3361       return;
3362     }
3363   if (LocaleCompare(map,"RGBP") == 0)
3364     {
3365       for (y=0; y < (ssize_t) roi->height; y++)
3366       {
3367         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3368         if (q == (Quantum *) NULL)
3369           break;
3370         for (x=0; x < (ssize_t) roi->width; x++)
3371         {
3372           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3373           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3374           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3375           p++;
3376           q+=GetPixelChannels(image);
3377         }
3378         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3379           break;
3380       }
3381       return;
3382     }
3383   length=strlen(map);
3384   for (y=0; y < (ssize_t) roi->height; y++)
3385   {
3386     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3387     if (q == (Quantum *) NULL)
3388       break;
3389     for (x=0; x < (ssize_t) roi->width; x++)
3390     {
3391       register ssize_t
3392         i;
3393
3394       for (i=0; i < (ssize_t) length; i++)
3395       {
3396         switch (quantum_map[i])
3397         {
3398           case RedQuantum:
3399           case CyanQuantum:
3400           {
3401             SetPixelRed(image,ScaleLongLongToQuantum(*p),q);
3402             break;
3403           }
3404           case GreenQuantum:
3405           case MagentaQuantum:
3406           {
3407             SetPixelGreen(image,ScaleLongLongToQuantum(*p),q);
3408             break;
3409           }
3410           case BlueQuantum:
3411           case YellowQuantum:
3412           {
3413             SetPixelBlue(image,ScaleLongLongToQuantum(*p),q);
3414             break;
3415           }
3416           case AlphaQuantum:
3417           {
3418             SetPixelAlpha(image,ScaleLongLongToQuantum(*p),q);
3419             break;
3420           }
3421           case OpacityQuantum:
3422           {
3423             SetPixelAlpha(image,ScaleLongLongToQuantum(*p),q);
3424             break;
3425           }
3426           case BlackQuantum:
3427           {
3428             SetPixelBlack(image,ScaleLongLongToQuantum(*p),q);
3429             break;
3430           }
3431           case IndexQuantum:
3432           {
3433             SetPixelGray(image,ScaleLongLongToQuantum(*p),q);
3434             break;
3435           }
3436           default:
3437             break;
3438         }
3439         p++;
3440       }
3441       q+=GetPixelChannels(image);
3442     }
3443     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3444       break;
3445   }
3446 }
3447
3448 static void ImportQuantumPixel(Image *image,const RectangleInfo *roi,
3449   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3450   ExceptionInfo *exception)
3451 {
3452   register const Quantum
3453     *restrict p;
3454
3455   register Quantum
3456     *restrict q;
3457
3458   register ssize_t
3459     x;
3460
3461   size_t
3462     length;
3463
3464   ssize_t
3465     y;
3466
3467   p=(const Quantum *) pixels;
3468   if (LocaleCompare(map,"BGR") == 0)
3469     {
3470       for (y=0; y < (ssize_t) roi->height; y++)
3471       {
3472         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3473         if (q == (Quantum *) NULL)
3474           break;
3475         for (x=0; x < (ssize_t) roi->width; x++)
3476         {
3477           SetPixelBlue(image,*p++,q);
3478           SetPixelGreen(image,*p++,q);
3479           SetPixelRed(image,*p++,q);
3480           q+=GetPixelChannels(image);
3481         }
3482         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3483           break;
3484       }
3485       return;
3486     }
3487   if (LocaleCompare(map,"BGRA") == 0)
3488     {
3489       for (y=0; y < (ssize_t) roi->height; y++)
3490       {
3491         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3492         if (q == (Quantum *) NULL)
3493           break;
3494         for (x=0; x < (ssize_t) roi->width; x++)
3495         {
3496           SetPixelBlue(image,*p++,q);
3497           SetPixelGreen(image,*p++,q);
3498           SetPixelRed(image,*p++,q);
3499           SetPixelAlpha(image,*p++,q);
3500           q+=GetPixelChannels(image);
3501         }
3502         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3503           break;
3504       }
3505       return;
3506     }
3507   if (LocaleCompare(map,"BGRP") == 0)
3508     {
3509       for (y=0; y < (ssize_t) roi->height; y++)
3510       {
3511         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3512         if (q == (Quantum *) NULL)
3513           break;
3514         for (x=0; x < (ssize_t) roi->width; x++)
3515         {
3516           SetPixelBlue(image,*p++,q);
3517           SetPixelGreen(image,*p++,q);
3518           SetPixelRed(image,*p++,q);
3519           p++;
3520           q+=GetPixelChannels(image);
3521         }
3522         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3523           break;
3524       }
3525       return;
3526     }
3527   if (LocaleCompare(map,"I") == 0)
3528     {
3529       for (y=0; y < (ssize_t) roi->height; y++)
3530       {
3531         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3532         if (q == (Quantum *) NULL)
3533           break;
3534         for (x=0; x < (ssize_t) roi->width; x++)
3535         {
3536           SetPixelGray(image,*p++,q);
3537           q+=GetPixelChannels(image);
3538         }
3539         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3540           break;
3541       }
3542       return;
3543     }
3544   if (LocaleCompare(map,"RGB") == 0)
3545     {
3546       for (y=0; y < (ssize_t) roi->height; y++)
3547       {
3548         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3549         if (q == (Quantum *) NULL)
3550           break;
3551         for (x=0; x < (ssize_t) roi->width; x++)
3552         {
3553           SetPixelRed(image,*p++,q);
3554           SetPixelGreen(image,*p++,q);
3555           SetPixelBlue(image,*p++,q);
3556           q+=GetPixelChannels(image);
3557         }
3558         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3559           break;
3560       }
3561       return;
3562     }
3563   if (LocaleCompare(map,"RGBA") == 0)
3564     {
3565       for (y=0; y < (ssize_t) roi->height; y++)
3566       {
3567         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3568         if (q == (Quantum *) NULL)
3569           break;
3570         for (x=0; x < (ssize_t) roi->width; x++)
3571         {
3572           SetPixelRed(image,*p++,q);
3573           SetPixelGreen(image,*p++,q);
3574           SetPixelBlue(image,*p++,q);
3575           SetPixelAlpha(image,*p++,q);
3576           q+=GetPixelChannels(image);
3577         }
3578         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3579           break;
3580       }
3581       return;
3582     }
3583   if (LocaleCompare(map,"RGBP") == 0)
3584     {
3585       for (y=0; y < (ssize_t) roi->height; y++)
3586       {
3587         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3588         if (q == (Quantum *) NULL)
3589           break;
3590         for (x=0; x < (ssize_t) roi->width; x++)
3591         {
3592           SetPixelRed(image,*p++,q);
3593           SetPixelGreen(image,*p++,q);
3594           SetPixelBlue(image,*p++,q);
3595           p++;
3596           q+=GetPixelChannels(image);
3597         }
3598         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3599           break;
3600       }
3601       return;
3602     }
3603   length=strlen(map);
3604   for (y=0; y < (ssize_t) roi->height; y++)
3605   {
3606     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3607     if (q == (Quantum *) NULL)
3608       break;
3609     for (x=0; x < (ssize_t) roi->width; x++)
3610     {
3611       register ssize_t
3612         i;
3613
3614       for (i=0; i < (ssize_t) length; i++)
3615       {
3616         switch (quantum_map[i])
3617         {
3618           case RedQuantum:
3619           case CyanQuantum:
3620           {
3621             SetPixelRed(image,*p,q);
3622             break;
3623           }
3624           case GreenQuantum:
3625           case MagentaQuantum:
3626           {
3627             SetPixelGreen(image,*p,q);
3628             break;
3629           }
3630           case BlueQuantum:
3631           case YellowQuantum:
3632           {
3633             SetPixelBlue(image,*p,q);
3634             break;
3635           }
3636           case AlphaQuantum:
3637           {
3638             SetPixelAlpha(image,*p,q);
3639             break;
3640           }
3641           case OpacityQuantum:
3642           {
3643             SetPixelAlpha(image,*p,q);
3644             break;
3645           }
3646           case BlackQuantum:
3647           {
3648             SetPixelBlack(image,*p,q);
3649             break;
3650           }
3651           case IndexQuantum:
3652           {
3653             SetPixelGray(image,*p,q);
3654             break;
3655           }
3656           default:
3657             break;
3658         }
3659         p++;
3660       }
3661       q+=GetPixelChannels(image);
3662     }
3663     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3664       break;
3665   }
3666 }
3667
3668 static void ImportShortPixel(Image *image,const RectangleInfo *roi,
3669   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3670   ExceptionInfo *exception)
3671 {
3672   register const unsigned short
3673     *restrict p;
3674
3675   register Quantum
3676     *restrict q;
3677
3678   register ssize_t
3679     x;
3680
3681   size_t
3682     length;
3683
3684   ssize_t
3685     y;
3686
3687   p=(const unsigned short *) pixels;
3688   if (LocaleCompare(map,"BGR") == 0)
3689     {
3690       for (y=0; y < (ssize_t) roi->height; y++)
3691       {
3692         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3693         if (q == (Quantum *) NULL)
3694           break;
3695         for (x=0; x < (ssize_t) roi->width; x++)
3696         {
3697           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3698           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3699           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3700           q+=GetPixelChannels(image);
3701         }
3702         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3703           break;
3704       }
3705       return;
3706     }
3707   if (LocaleCompare(map,"BGRA") == 0)
3708     {
3709       for (y=0; y < (ssize_t) roi->height; y++)
3710       {
3711         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3712         if (q == (Quantum *) NULL)
3713           break;
3714         for (x=0; x < (ssize_t) roi->width; x++)
3715         {
3716           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3717           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3718           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3719           SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
3720           q+=GetPixelChannels(image);
3721         }
3722         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3723           break;
3724       }
3725       return;
3726     }
3727   if (LocaleCompare(map,"BGRP") == 0)
3728     {
3729       for (y=0; y < (ssize_t) roi->height; y++)
3730       {
3731         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3732         if (q == (Quantum *) NULL)
3733           break;
3734         for (x=0; x < (ssize_t) roi->width; x++)
3735         {
3736           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3737           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3738           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3739           p++;
3740           q+=GetPixelChannels(image);
3741         }
3742         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3743           break;
3744       }
3745       return;
3746     }
3747   if (LocaleCompare(map,"I") == 0)
3748     {
3749       for (y=0; y < (ssize_t) roi->height; y++)
3750       {
3751         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3752         if (q == (Quantum *) NULL)
3753           break;
3754         for (x=0; x < (ssize_t) roi->width; x++)
3755         {
3756           SetPixelGray(image,ScaleShortToQuantum(*p++),q);
3757           q+=GetPixelChannels(image);
3758         }
3759         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3760           break;
3761       }
3762       return;
3763     }
3764   if (LocaleCompare(map,"RGB") == 0)
3765     {
3766       for (y=0; y < (ssize_t) roi->height; y++)
3767       {
3768         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3769         if (q == (Quantum *) NULL)
3770           break;
3771         for (x=0; x < (ssize_t) roi->width; x++)
3772         {
3773           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3774           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3775           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3776           q+=GetPixelChannels(image);
3777         }
3778         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3779           break;
3780       }
3781       return;
3782     }
3783   if (LocaleCompare(map,"RGBA") == 0)
3784     {
3785       for (y=0; y < (ssize_t) roi->height; y++)
3786       {
3787         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3788         if (q == (Quantum *) NULL)
3789           break;
3790         for (x=0; x < (ssize_t) roi->width; x++)
3791         {
3792           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3793           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3794           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3795           SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
3796           q+=GetPixelChannels(image);
3797         }
3798         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3799           break;
3800       }
3801       return;
3802     }
3803   if (LocaleCompare(map,"RGBP") == 0)
3804     {
3805       for (y=0; y < (ssize_t) roi->height; y++)
3806       {
3807         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3808         if (q == (Quantum *) NULL)
3809           break;
3810         for (x=0; x < (ssize_t) roi->width; x++)
3811         {
3812           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3813           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3814           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3815           p++;
3816           q+=GetPixelChannels(image);
3817         }
3818         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3819           break;
3820       }
3821       return;
3822     }
3823   length=strlen(map);
3824   for (y=0; y < (ssize_t) roi->height; y++)
3825   {
3826     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3827     if (q == (Quantum *) NULL)
3828       break;
3829     for (x=0; x < (ssize_t) roi->width; x++)
3830     {
3831       register ssize_t
3832         i;
3833
3834       for (i=0; i < (ssize_t) length; i++)
3835       {
3836         switch (quantum_map[i])
3837         {
3838           case RedQuantum:
3839           case CyanQuantum:
3840           {
3841             SetPixelRed(image,ScaleShortToQuantum(*p),q);
3842             break;
3843           }
3844           case GreenQuantum:
3845           case MagentaQuantum:
3846           {
3847             SetPixelGreen(image,ScaleShortToQuantum(*p),q);
3848             break;
3849           }
3850           case BlueQuantum:
3851           case YellowQuantum:
3852           {
3853             SetPixelBlue(image,ScaleShortToQuantum(*p),q);
3854             break;
3855           }
3856           case AlphaQuantum:
3857           {
3858             SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
3859             break;
3860           }
3861           case OpacityQuantum:
3862           {
3863             SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
3864             break;
3865           }
3866           case BlackQuantum:
3867           {
3868             SetPixelBlack(image,ScaleShortToQuantum(*p),q);
3869             break;
3870           }
3871           case IndexQuantum:
3872           {
3873             SetPixelGray(image,ScaleShortToQuantum(*p),q);
3874             break;
3875           }
3876           default:
3877             break;
3878         }
3879         p++;
3880       }
3881       q+=GetPixelChannels(image);
3882     }
3883     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3884       break;
3885   }
3886 }
3887
3888 MagickExport MagickBooleanType ImportImagePixels(Image *image,const ssize_t x,
3889   const ssize_t y,const size_t width,const size_t height,const char *map,
3890   const StorageType type,const void *pixels,ExceptionInfo *exception)
3891 {
3892   QuantumType
3893     *quantum_map;
3894
3895   RectangleInfo
3896     roi;
3897
3898   register ssize_t
3899     i;
3900
3901   size_t
3902     length;
3903
3904   /*
3905     Allocate image structure.
3906   */
3907   assert(image != (Image *) NULL);
3908   assert(image->signature == MagickSignature);
3909   if (image->debug != MagickFalse)
3910     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911   length=strlen(map);
3912   quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
3913   if (quantum_map == (QuantumType *) NULL)
3914     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3915       image->filename);
3916   for (i=0; i < (ssize_t) length; i++)
3917   {
3918     switch (map[i])
3919     {
3920       case 'a':
3921       case 'A':
3922       {
3923         quantum_map[i]=AlphaQuantum;
3924         image->alpha_trait=BlendPixelTrait;
3925         break;
3926       }
3927       case 'B':
3928       case 'b':
3929       {
3930         quantum_map[i]=BlueQuantum;
3931         break;
3932       }
3933       case 'C':
3934       case 'c':
3935       {
3936         quantum_map[i]=CyanQuantum;
3937         (void) SetImageColorspace(image,CMYKColorspace,exception);
3938         break;
3939       }
3940       case 'g':
3941       case 'G':
3942       {
3943         quantum_map[i]=GreenQuantum;
3944         break;
3945       }
3946       case 'K':
3947       case 'k':
3948       {
3949         quantum_map[i]=BlackQuantum;
3950         (void) SetImageColorspace(image,CMYKColorspace,exception);
3951         break;
3952       }
3953       case 'I':
3954       case 'i':
3955       {
3956         quantum_map[i]=IndexQuantum;
3957         (void) SetImageColorspace(image,GRAYColorspace,exception);
3958         break;
3959       }
3960       case 'm':
3961       case 'M':
3962       {
3963         quantum_map[i]=MagentaQuantum;
3964         (void) SetImageColorspace(image,CMYKColorspace,exception);
3965         break;
3966       }
3967       case 'O':
3968       case 'o':
3969       {
3970         quantum_map[i]=OpacityQuantum;
3971         image->alpha_trait=BlendPixelTrait;
3972         break;
3973       }
3974       case 'P':
3975       case 'p':
3976       {
3977         quantum_map[i]=UndefinedQuantum;
3978         break;
3979       }
3980       case 'R':
3981       case 'r':
3982       {
3983         quantum_map[i]=RedQuantum;
3984         break;
3985       }
3986       case 'Y':
3987       case 'y':
3988       {
3989         quantum_map[i]=YellowQuantum;
3990         (void) SetImageColorspace(image,CMYKColorspace,exception);
3991         break;
3992       }
3993       default:
3994       {
3995         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
3996         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
3997           "UnrecognizedPixelMap","`%s'",map);
3998         return(MagickFalse);
3999       }
4000     }
4001   }
4002   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4003     return(MagickFalse);
4004   /*
4005     Transfer the pixels from the pixel data to the image.
4006   */
4007   roi.width=width;
4008   roi.height=height;
4009   roi.x=x;
4010   roi.y=y;
4011   switch (type)
4012   {
4013     case CharPixel:
4014     {
4015       ImportCharPixel(image,&roi,map,quantum_map,pixels,exception);
4016       break;
4017     }
4018     case DoublePixel:
4019     {
4020       ImportDoublePixel(image,&roi,map,quantum_map,pixels,exception);
4021       break;
4022     }
4023     case FloatPixel:
4024     {
4025       ImportFloatPixel(image,&roi,map,quantum_map,pixels,exception);
4026       break;
4027     }
4028     case LongPixel:
4029     {
4030       ImportLongPixel(image,&roi,map,quantum_map,pixels,exception);
4031       break;
4032     }
4033     case LongLongPixel:
4034     {
4035       ImportLongLongPixel(image,&roi,map,quantum_map,pixels,exception);
4036       break;
4037     }
4038     case QuantumPixel:
4039     {
4040       ImportQuantumPixel(image,&roi,map,quantum_map,pixels,exception);
4041       break;
4042     }
4043     case ShortPixel:
4044     {
4045       ImportShortPixel(image,&roi,map,quantum_map,pixels,exception);
4046       break;
4047     }
4048     default:
4049     {
4050       quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
4051       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
4052         "UnrecognizedPixelMap","`%s'",map);
4053       break;
4054     }
4055   }
4056   quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
4057   return(MagickTrue);
4058 }
4059 \f
4060 /*
4061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4062 %                                                                             %
4063 %                                                                             %
4064 %                                                                             %
4065 +   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                         %
4066 %                                                                             %
4067 %                                                                             %
4068 %                                                                             %
4069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4070 %
4071 %  InitializePixelChannelMap() defines the standard pixel component map.
4072 %
4073 %  The format of the InitializePixelChannelMap() method is:
4074 %
4075 %      void InitializePixelChannelMap(Image *image)
4076 %
4077 %  A description of each parameter follows:
4078 %
4079 %    o image: the image.
4080 %
4081 */
4082 MagickExport void InitializePixelChannelMap(Image *image)
4083 {
4084   PixelTrait
4085     trait;
4086
4087   register ssize_t
4088     i;
4089
4090   ssize_t
4091     n;
4092
4093   assert(image != (Image *) NULL);
4094   assert(image->signature == MagickSignature);
4095   (void) ResetMagickMemory(image->channel_map,0,MaxPixelChannels*
4096     sizeof(*image->channel_map));
4097   trait=UpdatePixelTrait;
4098   if (image->alpha_trait == BlendPixelTrait)
4099     trait=(PixelTrait) (trait | BlendPixelTrait);
4100   n=0;
4101   if (image->colorspace == GRAYColorspace)
4102     {
4103       SetPixelChannelAttributes(image,BluePixelChannel,trait,n);
4104       SetPixelChannelAttributes(image,GreenPixelChannel,trait,n);
4105       SetPixelChannelAttributes(image,RedPixelChannel,trait,n++);
4106     }
4107   else
4108     {
4109       SetPixelChannelAttributes(image,RedPixelChannel,trait,n++);
4110       SetPixelChannelAttributes(image,GreenPixelChannel,trait,n++);
4111       SetPixelChannelAttributes(image,BluePixelChannel,trait,n++);
4112     }
4113   if (image->colorspace == CMYKColorspace)
4114     SetPixelChannelAttributes(image,BlackPixelChannel,trait,n++);
4115   if (image->alpha_trait != UndefinedPixelTrait)
4116     SetPixelChannelAttributes(image,AlphaPixelChannel,CopyPixelTrait,n++);
4117   if (image->storage_class == PseudoClass)
4118     SetPixelChannelAttributes(image,IndexPixelChannel,CopyPixelTrait,n++);
4119   if (image->mask != MagickFalse)
4120     SetPixelChannelAttributes(image,MaskPixelChannel,CopyPixelTrait,n++);
4121   assert((n+image->number_meta_channels) < MaxPixelChannels);
4122   for (i=0; i < (ssize_t) image->number_meta_channels; i++)
4123     SetPixelChannelAttributes(image,(PixelChannel) (MetaPixelChannel+i),
4124       CopyPixelTrait,n++);
4125   image->number_channels=(size_t) n;
4126   if (image->debug != MagickFalse)
4127     LogPixelChannels(image);
4128   (void) SetImageChannelMask(image,image->channel_mask);
4129 }
4130 \f
4131 /*
4132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4133 %                                                                             %
4134 %                                                                             %
4135 %                                                                             %
4136 %   I n t e r p o l a t e P i x e l C h a n n e l                             %
4137 %                                                                             %
4138 %                                                                             %
4139 %                                                                             %
4140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4141 %
4142 %  InterpolatePixelChannel() applies a pixel interpolation method between a
4143 %  floating point coordinate and the pixels surrounding that coordinate.  No
4144 %  pixel area resampling, or scaling of the result is performed.
4145 %
4146 %  Interpolation is restricted to just the specified channel.
4147 %
4148 %  The format of the InterpolatePixelChannel method is:
4149 %
4150 %      MagickBooleanType InterpolatePixelChannel(const Image *image,
4151 %        const CacheView *image_view,const PixelChannel channel,
4152 %        const PixelInterpolateMethod method,const double x,const double y,
4153 %        double *pixel,ExceptionInfo *exception)
4154 %
4155 %  A description of each parameter follows:
4156 %
4157 %    o image: the image.
4158 %
4159 %    o image_view: the image view.
4160 %
4161 %    o channel: the pixel channel to interpolate.
4162 %
4163 %    o method: the pixel color interpolation method.
4164 %
4165 %    o x,y: A double representing the current (x,y) position of the pixel.
4166 %
4167 %    o pixel: return the interpolated pixel here.
4168 %
4169 %    o exception: return any errors or warnings in this structure.
4170 %
4171 */
4172
4173 static inline void CatromWeights(const double x,double (*weights)[4])
4174 {
4175   double
4176     alpha,
4177     beta,
4178     gamma;
4179
4180   /*
4181     Nicolas Robidoux' 10 flops (4* + 5- + 1+) refactoring of the computation
4182     of the standard four 1D Catmull-Rom weights. The sampling location is
4183     assumed between the second and third input pixel locations, and x is the
4184     position relative to the second input pixel location. Formulas originally
4185     derived for the VIPS (Virtual Image Processing System) library.
4186   */
4187   alpha=(double) 1.0-x;
4188   beta=(double) (-0.5)*x*alpha;
4189   (*weights)[0]=alpha*beta;
4190   (*weights)[3]=x*beta;
4191   /*
4192     The following computation of the inner weights from the outer ones work
4193     for all Keys cubics.
4194   */
4195   gamma=(*weights)[3]-(*weights)[0];
4196   (*weights)[1]=alpha-(*weights)[0]+gamma;
4197   (*weights)[2]=x-(*weights)[3]-gamma;
4198 }
4199
4200 static inline void SplineWeights(const double x,double (*weights)[4])
4201 {
4202   double
4203     alpha,
4204     beta;
4205
4206   /*
4207     Nicolas Robidoux' 12 flops (6* + 5- + 1+) refactoring of the
4208     computation of the standard four 1D cubic B-spline smoothing
4209     weights. The sampling location is assumed between the second and
4210     third input pixel locations, and x is the position relative to the
4211     second input pixel location.
4212   */
4213   alpha=(double) 1.0-x;
4214   (*weights)[3]=(double) (1.0/6.0)*x*x*x;
4215   (*weights)[0]=(double) (1.0/6.0)*alpha*alpha*alpha;
4216   beta=(*weights)[3]-(*weights)[0];
4217   (*weights)[1]=alpha-(*weights)[0]+beta;
4218   (*weights)[2]=x-(*weights)[3]-beta;
4219 }
4220
4221 static inline double MeshInterpolate(const PointInfo *delta,const double p,
4222   const double x,const double y)
4223 {
4224   return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
4225 }
4226
4227 /*
4228 static inline ssize_t NearestNeighbor(const double x)
4229 {
4230   if (x >= 0.0)
4231     return((ssize_t) (x+0.5));
4232   return((ssize_t) (x-0.5));
4233 }
4234 */
4235
4236 MagickExport MagickBooleanType InterpolatePixelChannel(const Image *image,
4237   const CacheView *image_view,const PixelChannel channel,
4238   const PixelInterpolateMethod method,const double x,const double y,
4239   double *pixel,ExceptionInfo *exception)
4240 {
4241   MagickBooleanType
4242     status;
4243
4244   double
4245     alpha[16],
4246     gamma,
4247     pixels[16];
4248
4249   PixelTrait
4250     traits;
4251
4252   register const Quantum
4253     *p;
4254
4255   register ssize_t
4256     i;
4257
4258   ssize_t
4259     x_offset,
4260     y_offset;
4261
4262   PixelInterpolateMethod
4263     interpolate;
4264
4265   assert(image != (Image *) NULL);
4266   assert(image != (Image *) NULL);
4267   assert(image->signature == MagickSignature);
4268   assert(image_view != (CacheView *) NULL);
4269   status=MagickTrue;
4270   *pixel=0.0;
4271   traits=GetPixelChannelTraits(image,channel);
4272   x_offset=(ssize_t) floor(x);
4273   y_offset=(ssize_t) floor(y);
4274   interpolate = method;
4275   if ( interpolate == UndefinedInterpolatePixel )
4276     interpolate = image->interpolate;
4277   switch (interpolate)
4278   {
4279     case AverageInterpolatePixel:        /* nearest 4 neighbours */
4280     case Average9InterpolatePixel:       /* nearest 9 neighbours */
4281     case Average16InterpolatePixel:      /* nearest 16 neighbours */
4282     {
4283       ssize_t
4284         count;
4285
4286       count=2;  /* size of the area to average - default nearest 4 */
4287       if (interpolate == Average9InterpolatePixel)
4288         {
4289           count=3;
4290           x_offset=(ssize_t) (floor(x+0.5)-1);
4291           y_offset=(ssize_t) (floor(y+0.5)-1);
4292         }
4293       else
4294         if (interpolate == Average16InterpolatePixel)
4295           {
4296             count=4;
4297             x_offset--;
4298             y_offset--;
4299           }
4300       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,(size_t) count,(size_t)
4301         count,exception);
4302       if (p == (const Quantum *) NULL)
4303         {
4304           status=MagickFalse;
4305           break;
4306         }
4307       count*=count;   /* Number of pixels to Average */
4308       if ((traits & BlendPixelTrait) == 0)
4309         for (i=0; i < (ssize_t) count; i++)
4310         {
4311           alpha[i]=1.0;
4312           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4313         }
4314       else
4315         for (i=0; i < (ssize_t) count; i++)
4316         {
4317           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4318             GetPixelChannels(image));
4319           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4320         }
4321       for (i=0; i < (ssize_t) count; i++)
4322       {
4323         gamma=PerceptibleReciprocal(alpha[i])/count;
4324         *pixel+=gamma*pixels[i];
4325       }
4326       break;
4327     }
4328     case BilinearInterpolatePixel:
4329     default:
4330     {
4331       PointInfo
4332         delta,
4333         epsilon;
4334
4335       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4336       if (p == (const Quantum *) NULL)
4337         {
4338           status=MagickFalse;
4339           break;
4340         }
4341       if ((traits & BlendPixelTrait) == 0)
4342         for (i=0; i < 4; i++)
4343         {
4344           alpha[i]=1.0;
4345           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4346         }
4347       else
4348         for (i=0; i < 4; i++)
4349         {
4350           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4351             GetPixelChannels(image));
4352           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4353         }
4354       delta.x=x-x_offset;
4355       delta.y=y-y_offset;
4356       epsilon.x=1.0-delta.x;
4357       epsilon.y=1.0-delta.y;
4358       gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
4359         (epsilon.x*alpha[2]+delta.x*alpha[3])));
4360       gamma=PerceptibleReciprocal(gamma);
4361       *pixel=gamma*(epsilon.y*(epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*
4362         (epsilon.x*pixels[2]+delta.x*pixels[3]));
4363       break;
4364     }
4365     case BlendInterpolatePixel:
4366     {
4367       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4368       if (p == (const Quantum *) NULL)
4369         {
4370           status=MagickFalse;
4371           break;
4372         }
4373       if ((traits & BlendPixelTrait) == 0)
4374         for (i=0; i < 4; i++)
4375         {
4376           alpha[i]=1.0;
4377           pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
4378         }
4379       else
4380         for (i=0; i < 4; i++)
4381         {
4382           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4383             GetPixelChannels(image));
4384           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4385         }
4386       gamma=1.0;    /* number of pixels blended together (its variable) */
4387       for (i=0; i <= 1L; i++) {
4388         if ((y-y_offset) >= 0.75)
4389           {
4390             alpha[i]=alpha[i+2];  /* take right pixels */
4391             pixels[i]=pixels[i+2];
4392           }
4393         else
4394           if ((y-y_offset) > 0.25)
4395             {
4396               gamma=2.0;  /* blend both pixels in row */
4397               alpha[i]+=alpha[i+2];  /* add up alpha weights */
4398               pixels[i]+=pixels[i+2];
4399             }
4400       }
4401       if ((x-x_offset) >= 0.75)
4402         {
4403           alpha[0]=alpha[1];  /* take bottom row blend */
4404           pixels[0]=pixels[1];
4405         }
4406       else
4407         if ((x-x_offset) > 0.25)
4408           {
4409             gamma*=2.0;  /* blend both rows */
4410             alpha[0]+=alpha[1];  /* add up alpha weights */
4411             pixels[0]+=pixels[1];
4412           }
4413       if (channel != AlphaPixelChannel)
4414         gamma=PerceptibleReciprocal(alpha[0]); /* (color) 1/alpha_weights */
4415       else
4416         gamma=PerceptibleReciprocal(gamma); /* (alpha) 1/number_of_pixels */
4417       *pixel=gamma*pixels[0];
4418       break;
4419     }
4420     case CatromInterpolatePixel:
4421     {
4422       double
4423         cx[4],
4424         cy[4];
4425
4426       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
4427         exception);
4428       if (p == (const Quantum *) NULL)
4429         {
4430           status=MagickFalse;
4431           break;
4432         }
4433       if ((traits & BlendPixelTrait) == 0)
4434         for (i=0; i < 16; i++)
4435         {
4436           alpha[i]=1.0;
4437           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4438         }
4439       else
4440         for (i=0; i < 16; i++)
4441         {
4442           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4443             GetPixelChannels(image));
4444           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4445         }
4446       CatromWeights((double) (x-x_offset),&cx);
4447       CatromWeights((double) (y-y_offset),&cy);
4448       gamma=(channel == AlphaPixelChannel ? (double) 1.0 :
4449         PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4450         alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4451         alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4452         alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4453         cx[2]*alpha[14]+cx[3]*alpha[15])));
4454       *pixel=gamma*(cy[0]*(cx[0]*pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+
4455         cx[3]*pixels[3])+cy[1]*(cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*
4456         pixels[6]+cx[3]*pixels[7])+cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+
4457         cx[2]*pixels[10]+cx[3]*pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*
4458         pixels[13]+cx[2]*pixels[14]+cx[3]*pixels[15]));
4459       break;
4460     }
4461 #if 0
4462     /* deprecated useless and very slow interpolator */
4463     case FilterInterpolatePixel:
4464     {
4465       CacheView
4466         *filter_view;
4467
4468       Image
4469         *excerpt_image,
4470         *filter_image;
4471
4472       RectangleInfo
4473         geometry;
4474
4475       geometry.width=4L;
4476       geometry.height=4L;
4477       geometry.x=x_offset-1;
4478       geometry.y=y_offset-1;
4479       excerpt_image=ExcerptImage(image,&geometry,exception);
4480       if (excerpt_image == (Image *) NULL)
4481         {
4482           status=MagickFalse;
4483           break;
4484         }
4485       filter_image=ResizeImage(excerpt_image,1,1,image->filter,exception);
4486       excerpt_image=DestroyImage(excerpt_image);
4487       if (filter_image == (Image *) NULL)
4488         break;
4489       filter_view=AcquireVirtualCacheView(filter_image,exception);
4490       p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
4491       if (p == (const Quantum *) NULL)
4492         status=MagickFalse;
4493       else
4494         *pixel=(double) GetPixelChannel(image,channel,p);
4495       filter_view=DestroyCacheView(filter_view);
4496       filter_image=DestroyImage(filter_image);
4497       break;
4498     }
4499 #endif
4500     case IntegerInterpolatePixel:
4501     {
4502       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4503       if (p == (const Quantum *) NULL)
4504         {
4505           status=MagickFalse;
4506           break;
4507         }
4508       *pixel=(double) GetPixelChannel(image,channel,p);
4509       break;
4510     }
4511     case NearestInterpolatePixel:
4512     {
4513       x_offset=(ssize_t) floor(x+0.5);
4514       y_offset=(ssize_t) floor(y+0.5);
4515       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4516       if (p == (const Quantum *) NULL)
4517         {
4518           status=MagickFalse;
4519           break;
4520         }
4521       *pixel=(double) GetPixelChannel(image,channel,p);
4522       break;
4523     }
4524     case MeshInterpolatePixel:
4525     {
4526       PointInfo
4527         delta,
4528         luminance;
4529
4530       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4531       if (p == (const Quantum *) NULL)
4532         {
4533           status=MagickFalse;
4534           break;
4535         }
4536       if ((traits & BlendPixelTrait) == 0)
4537         for (i=0; i < 4; i++)
4538         {
4539           alpha[i]=1.0;
4540           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4541         }
4542       else
4543         for (i=0; i < 4; i++)
4544         {
4545           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4546             GetPixelChannels(image));
4547           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4548         }
4549       delta.x=x-x_offset;
4550       delta.y=y-y_offset;
4551       luminance.x=GetPixelLuminance(image,p)-(double)
4552         GetPixelLuminance(image,p+3*GetPixelChannels(image));
4553       luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
4554         GetPixelLuminance(image,p+2*GetPixelChannels(image));
4555       if (fabs(luminance.x) < fabs(luminance.y))
4556         {
4557           /*
4558             Diagonal 0-3 NW-SE.
4559           */
4560           if (delta.x <= delta.y)
4561             {
4562               /*
4563                 Bottom-left triangle (pixel: 2, diagonal: 0-3).
4564               */
4565               delta.y=1.0-delta.y;
4566               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
4567               gamma=PerceptibleReciprocal(gamma);
4568               *pixel=gamma*MeshInterpolate(&delta,pixels[2],pixels[3],
4569                 pixels[0]);
4570             }
4571           else
4572             {
4573               /*
4574                 Top-right triangle (pixel: 1, diagonal: 0-3).
4575               */
4576               delta.x=1.0-delta.x;
4577               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
4578               gamma=PerceptibleReciprocal(gamma);
4579               *pixel=gamma*MeshInterpolate(&delta,pixels[1],pixels[0],
4580                 pixels[3]);
4581             }
4582         }
4583       else
4584         {
4585           /*
4586             Diagonal 1-2 NE-SW.
4587           */
4588           if (delta.x <= (1.0-delta.y))
4589             {
4590               /*
4591                 Top-left triangle (pixel: 0, diagonal: 1-2).
4592               */
4593               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
4594               gamma=PerceptibleReciprocal(gamma);
4595               *pixel=gamma*MeshInterpolate(&delta,pixels[0],pixels[1],
4596                 pixels[2]);
4597             }
4598           else
4599             {
4600               /*
4601                 Bottom-right triangle (pixel: 3, diagonal: 1-2).
4602               */
4603               delta.x=1.0-delta.x;
4604               delta.y=1.0-delta.y;
4605               gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
4606               gamma=PerceptibleReciprocal(gamma);
4607               *pixel=gamma*MeshInterpolate(&delta,pixels[3],pixels[2],
4608                 pixels[1]);
4609             }
4610         }
4611       break;
4612     }
4613     case SplineInterpolatePixel:
4614     {
4615       double
4616         cx[4],
4617         cy[4];
4618
4619       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
4620         exception);
4621       if (p == (const Quantum *) NULL)
4622         {
4623           status=MagickFalse;
4624           break;
4625         }
4626       if ((traits & BlendPixelTrait) == 0)
4627         for (i=0; i < 16; i++)
4628         {
4629           alpha[i]=1.0;
4630           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4631         }
4632       else
4633         for (i=0; i < 16; i++)
4634         {
4635           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4636             GetPixelChannels(image));
4637           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4638         }
4639       SplineWeights((double) (x-x_offset),&cx);
4640       SplineWeights((double) (y-y_offset),&cy);
4641       gamma=(channel == AlphaPixelChannel ? (double) 1.0 :
4642         PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4643         alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4644         alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4645         alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4646         cx[2]*alpha[14]+cx[3]*alpha[15])));
4647       *pixel=gamma*(cy[0]*(cx[0]*pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+
4648         cx[3]*pixels[3])+cy[1]*(cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*
4649         pixels[6]+cx[3]*pixels[7])+cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+
4650         cx[2]*pixels[10]+cx[3]*pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*
4651         pixels[13]+cx[2]*pixels[14]+cx[3]*pixels[15]));
4652       break;
4653     }
4654   }
4655   return(status);
4656 }
4657 \f
4658 /*
4659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4660 %                                                                             %
4661 %                                                                             %
4662 %                                                                             %
4663 %   I n t e r p o l a t e P i x e l C h a n n e l s                           %
4664 %                                                                             %
4665 %                                                                             %
4666 %                                                                             %
4667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4668 %
4669 %  InterpolatePixelChannels() applies a pixel interpolation method between a
4670 %  floating point coordinate and the pixels surrounding that coordinate.  No
4671 %  pixel area resampling, or scaling of the result is performed.
4672 %
4673 %  Interpolation is restricted to just the current channel setting of the
4674 %  destination image into which the color is to be stored
4675 %
4676 %  The format of the InterpolatePixelChannels method is:
4677 %
4678 %      MagickBooleanType InterpolatePixelChannels(const Image *source,
4679 %        const CacheView *source_view,const Image *destination,
4680 %        const PixelInterpolateMethod method,const double x,const double y,
4681 %        Quantum *pixel,ExceptionInfo *exception)
4682 %
4683 %  A description of each parameter follows:
4684 %
4685 %    o source: the source.
4686 %
4687 %    o source_view: the source view.
4688 %
4689 %    o destination: the destination image, for the interpolated color
4690 %
4691 %    o method: the pixel color interpolation method.
4692 %
4693 %    o x,y: A double representing the current (x,y) position of the pixel.
4694 %
4695 %    o pixel: return the interpolated pixel here.
4696 %
4697 %    o exception: return any errors or warnings in this structure.
4698 %
4699 */
4700 MagickExport MagickBooleanType InterpolatePixelChannels(const Image *source,
4701   const CacheView *source_view,const Image *destination,
4702   const PixelInterpolateMethod method,const double x,const double y,
4703   Quantum *pixel,ExceptionInfo *exception)
4704 {
4705   MagickBooleanType
4706     status;
4707
4708   double
4709     alpha[16],
4710     gamma,
4711     pixels[16];
4712
4713   register const Quantum
4714     *p;
4715
4716   register ssize_t
4717     i;
4718
4719   ssize_t
4720     x_offset,
4721     y_offset;
4722
4723   PixelInterpolateMethod
4724     interpolate;
4725
4726   assert(source != (Image *) NULL);
4727   assert(source != (Image *) NULL);
4728   assert(source->signature == MagickSignature);
4729   assert(source_view != (CacheView *) NULL);
4730   status=MagickTrue;
4731   x_offset=(ssize_t) floor(x);
4732   y_offset=(ssize_t) floor(y);
4733   interpolate = method;
4734   if ( interpolate == UndefinedInterpolatePixel )
4735     interpolate = source->interpolate;
4736   switch (interpolate)
4737   {
4738     case AverageInterpolatePixel:        /* nearest 4 neighbours */
4739     case Average9InterpolatePixel:       /* nearest 9 neighbours */
4740     case Average16InterpolatePixel:      /* nearest 16 neighbours */
4741     {
4742       ssize_t
4743         count;
4744
4745       count=2;  /* size of the area to average - default nearest 4 */
4746       if (interpolate == Average9InterpolatePixel)
4747         {
4748           count=3;
4749           x_offset=(ssize_t) (floor(x+0.5)-1);
4750           y_offset=(ssize_t) (floor(y+0.5)-1);
4751         }
4752       else
4753         if (interpolate == Average16InterpolatePixel)
4754           {
4755             count=4;
4756             x_offset--;
4757             y_offset--;
4758           }
4759       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,(size_t) count,(size_t)
4760         count,exception);
4761       if (p == (const Quantum *) NULL)
4762         {
4763           status=MagickFalse;
4764           break;
4765         }
4766       count*=count;  /* Number of pixels to Average */
4767       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4768       {
4769         double
4770           sum;
4771
4772         register ssize_t
4773           j;
4774
4775         PixelChannel channel=GetPixelChannelChannel(source,i);
4776         PixelTrait traits=GetPixelChannelTraits(source,channel);
4777         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4778           channel);
4779         if ((traits == UndefinedPixelTrait) ||
4780             (destination_traits == UndefinedPixelTrait))
4781           continue;
4782         for (j=0; j < (ssize_t) count; j++)
4783           pixels[j]=(double) p[j*GetPixelChannels(source)+i];
4784         sum=0.0;
4785         if ((traits & BlendPixelTrait) == 0)
4786           {
4787             for (j=0; j < (ssize_t) count; j++)
4788               sum+=pixels[j];
4789             sum/=count;
4790             SetPixelChannel(destination,channel,ClampToQuantum(sum),pixel);
4791             continue;
4792           }
4793         for (j=0; j < (ssize_t) count; j++)
4794         {
4795           alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4796             GetPixelChannels(source));
4797           pixels[j]*=alpha[j];
4798           gamma=PerceptibleReciprocal(alpha[j]);
4799           sum+=gamma*pixels[j];
4800         }
4801         sum/=count;
4802         SetPixelChannel(destination,channel,ClampToQuantum(sum),pixel);
4803       }
4804       break;
4805     }
4806     case BilinearInterpolatePixel:
4807     default:
4808     {
4809       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
4810       if (p == (const Quantum *) NULL)
4811         {
4812           status=MagickFalse;
4813           break;
4814         }
4815       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4816       {
4817         PointInfo
4818           delta,
4819           epsilon;
4820
4821         PixelChannel channel=GetPixelChannelChannel(source,i);
4822         PixelTrait traits=GetPixelChannelTraits(source,channel);
4823         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4824           channel);
4825         if ((traits == UndefinedPixelTrait) ||
4826             (destination_traits == UndefinedPixelTrait))
4827           continue;
4828         delta.x=x-x_offset;
4829         delta.y=y-y_offset;
4830         epsilon.x=1.0-delta.x;
4831         epsilon.y=1.0-delta.y;
4832         pixels[0]=(double) p[i];
4833         pixels[1]=(double) p[GetPixelChannels(source)+i];
4834         pixels[2]=(double) p[2*GetPixelChannels(source)+i];
4835         pixels[3]=(double) p[3*GetPixelChannels(source)+i];
4836         if ((traits & BlendPixelTrait) == 0)
4837           {
4838             gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
4839             gamma=PerceptibleReciprocal(gamma);
4840             SetPixelChannel(destination,channel,ClampToQuantum(gamma*(epsilon.y*
4841               (epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*(epsilon.x*
4842               pixels[2]+delta.x*pixels[3]))),pixel);
4843             continue;
4844           }
4845         alpha[0]=QuantumScale*GetPixelAlpha(source,p);
4846         alpha[1]=QuantumScale*GetPixelAlpha(source,p+GetPixelChannels(source));
4847         alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
4848           GetPixelChannels(source));
4849         alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
4850           GetPixelChannels(source));
4851         pixels[0]*=alpha[0];
4852         pixels[1]*=alpha[1];
4853         pixels[2]*=alpha[2];
4854         pixels[3]*=alpha[3];
4855         gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
4856           (epsilon.x*alpha[2]+delta.x*alpha[3])));
4857         gamma=PerceptibleReciprocal(gamma);
4858         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(epsilon.y*
4859           (epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*(epsilon.x*pixels[2]+
4860           delta.x*pixels[3]))),pixel);
4861       }
4862       break;
4863     }
4864     case BlendInterpolatePixel:
4865     {
4866       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
4867       if (p == (const Quantum *) NULL)
4868         {
4869           status=MagickFalse;
4870           break;
4871         }
4872       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4873       {
4874         register ssize_t
4875           j;
4876
4877         PixelChannel channel=GetPixelChannelChannel(source,i);
4878         PixelTrait traits=GetPixelChannelTraits(source,channel);
4879         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4880           channel);
4881         if ((traits == UndefinedPixelTrait) ||
4882             (destination_traits == UndefinedPixelTrait))
4883           continue;
4884         if ((traits & BlendPixelTrait) == 0)
4885           for (j=0; j < 4; j++)
4886           {
4887             alpha[j]=1.0;
4888             pixels[j]=(MagickRealType) p[j*GetPixelChannels(source)+channel];
4889           }
4890         else
4891           for (j=0; j < 4; j++)
4892           {
4893             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4894               GetPixelChannels(source));
4895             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+channel];
4896           }
4897         gamma=1.0;  /* number of pixels blended together (its variable) */
4898         for (j=0; j <= 1L; j++)
4899         {
4900           if ((y-y_offset) >= 0.75)
4901             {
4902               alpha[j]=alpha[j+2];  /* take right pixels */
4903               pixels[j]=pixels[j+2];
4904             }
4905           else
4906             if ((y-y_offset) > 0.25)
4907               {
4908                 gamma=2.0;              /* blend both pixels in row */
4909                 alpha[j]+=alpha[j+2];  /* add up alpha weights */
4910                 pixels[j]+=pixels[j+2];
4911               }
4912         }
4913         if ((x-x_offset) >= 0.75)
4914           {
4915             alpha[0]=alpha[1];  /* take bottom row blend */
4916             pixels[0]=pixels[1];
4917           }
4918         else
4919            if ((x-x_offset) > 0.25)
4920              {
4921                gamma*=2.0;  /* blend both rows */
4922                alpha[0]+=alpha[1];  /* add up alpha weights */
4923                pixels[0]+=pixels[1];
4924              }
4925         if ((traits & BlendPixelTrait) == 0)
4926           gamma=PerceptibleReciprocal(alpha[0]); /* (color) 1/alpha_weights */
4927         else
4928           gamma=PerceptibleReciprocal(gamma); /* (alpha) 1/number_of_pixels */
4929         SetPixelChannel(destination,channel,ClampToQuantum(gamma*pixels[0]),
4930           pixel);
4931       }
4932       break;
4933     }
4934     case CatromInterpolatePixel:
4935     {
4936       double
4937         cx[4],
4938         cy[4];
4939
4940       p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
4941         exception);
4942       if (p == (const Quantum *) NULL)
4943         {
4944           status=MagickFalse;
4945           break;
4946         }
4947       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4948       {
4949         register ssize_t
4950           j;
4951
4952         PixelChannel channel=GetPixelChannelChannel(source,i);
4953         PixelTrait traits=GetPixelChannelTraits(source,channel);
4954         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4955           channel);
4956         if ((traits == UndefinedPixelTrait) ||
4957             (destination_traits == UndefinedPixelTrait))
4958           continue;
4959         if ((traits & BlendPixelTrait) == 0)
4960           for (j=0; j < 16; j++)
4961           {
4962             alpha[j]=1.0;
4963             pixels[j]=(double) p[j*GetPixelChannels(source)+i];
4964           }
4965         else
4966           for (j=0; j < 16; j++)
4967           {
4968             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4969               GetPixelChannels(source));
4970             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
4971           }
4972         CatromWeights((double) (x-x_offset),&cx);
4973         CatromWeights((double) (y-y_offset),&cy);
4974         gamma=((traits & BlendPixelTrait) ? (double) (1.0) :
4975           PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4976           alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4977           alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4978           alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4979           cx[2]*alpha[14]+cx[3]*alpha[15])));
4980         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(cy[0]*(cx[0]*
4981           pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+cx[3]*pixels[3])+cy[1]*
4982           (cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*pixels[6]+cx[3]*pixels[7])+
4983           cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+cx[2]*pixels[10]+cx[3]*
4984           pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*pixels[13]+cx[2]*
4985           pixels[14]+cx[3]*pixels[15]))),pixel);
4986       }
4987       break;
4988     }
4989 #if 0
4990     /* deprecated useless and very slow interpolator */
4991     case FilterInterpolatePixel:
4992     {
4993       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4994       {
4995         CacheView
4996           *filter_view;
4997
4998         Image
4999           *excerpt_source,
5000           *filter_source;
5001
5002         RectangleInfo
5003           geometry;
5004
5005         PixelChannel channel=GetPixelChannelChannel(source,i);
5006         PixelTrait traits=GetPixelChannelTraits(source,channel);
5007         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5008           channel);
5009         if ((traits == UndefinedPixelTrait) ||
5010             (destination_traits == UndefinedPixelTrait))
5011           continue;
5012         geometry.width=4L;
5013         geometry.height=4L;
5014         geometry.x=x_offset-1;
5015         geometry.y=y_offset-1;
5016         excerpt_source=ExcerptImage(source,&geometry,exception);
5017         if (excerpt_source == (Image *) NULL)
5018           {
5019             status=MagickFalse;
5020             continue;
5021           }
5022         filter_source=ResizeImage(excerpt_source,1,1,source->filter,exception);
5023         excerpt_source=DestroyImage(excerpt_source);
5024         if (filter_source == (Image *) NULL)
5025           continue;
5026         filter_view=AcquireVirtualCacheView(filter_source,exception);
5027         p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
5028         if (p == (const Quantum *) NULL)
5029           status=MagickFalse;
5030         else
5031           {
5032             SetPixelChannel(destination,channel,p[i],pixel);
5033           }
5034         filter_view=DestroyCacheView(filter_view);
5035         filter_source=DestroyImage(filter_source);
5036       }
5037       break;
5038     }
5039 #endif
5040     case IntegerInterpolatePixel:
5041     {
5042       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,1,1,exception);
5043       if (p == (const Quantum *) NULL)
5044         {
5045           status=MagickFalse;
5046           break;
5047         }
5048       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5049       {
5050         PixelChannel channel=GetPixelChannelChannel(source,i);
5051         PixelTrait traits=GetPixelChannelTraits(source,channel);
5052         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5053           channel);
5054         if ((traits == UndefinedPixelTrait) ||
5055             (destination_traits == UndefinedPixelTrait))
5056           continue;
5057         SetPixelChannel(destination,channel,p[i],pixel);
5058       }
5059       break;
5060     }
5061     case NearestInterpolatePixel:
5062     {
5063       x_offset=(ssize_t) floor(x+0.5);
5064       y_offset=(ssize_t) floor(y+0.5);
5065       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,1,1,exception);
5066       if (p == (const Quantum *) NULL)
5067         {
5068           status=MagickFalse;
5069           break;
5070         }
5071       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5072       {
5073         PixelChannel channel=GetPixelChannelChannel(source,i);
5074         PixelTrait traits=GetPixelChannelTraits(source,channel);
5075         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5076           channel);
5077         if ((traits == UndefinedPixelTrait) ||
5078             (destination_traits == UndefinedPixelTrait))
5079           continue;
5080         SetPixelChannel(destination,channel,p[i],pixel);
5081       }
5082       break;
5083     }
5084     case MeshInterpolatePixel:
5085     {
5086       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
5087       if (p == (const Quantum *) NULL)
5088         {
5089           status=MagickFalse;
5090           break;
5091         }
5092       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5093       {
5094         PointInfo
5095           delta,
5096           luminance;
5097
5098         PixelChannel channel=GetPixelChannelChannel(source,i);
5099         PixelTrait traits=GetPixelChannelTraits(source,channel);
5100         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5101           channel);
5102         if ((traits == UndefinedPixelTrait) ||
5103             (destination_traits == UndefinedPixelTrait))
5104           continue;
5105         pixels[0]=(double) p[i];
5106         pixels[1]=(double) p[GetPixelChannels(source)+i];
5107         pixels[2]=(double) p[2*GetPixelChannels(source)+i];
5108         pixels[3]=(double) p[3*GetPixelChannels(source)+i];
5109         if ((traits & BlendPixelTrait) == 0)
5110           {
5111             alpha[0]=1.0;
5112             alpha[1]=1.0;
5113             alpha[2]=1.0;
5114             alpha[3]=1.0;
5115           }
5116         else
5117           {
5118             alpha[0]=QuantumScale*GetPixelAlpha(source,p);
5119             alpha[1]=QuantumScale*GetPixelAlpha(source,p+
5120               GetPixelChannels(source));
5121             alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
5122               GetPixelChannels(source));
5123             alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
5124               GetPixelChannels(source));
5125           }
5126         delta.x=x-x_offset;
5127         delta.y=y-y_offset;
5128         luminance.x=fabs((double) (GetPixelLuminance(source,p)-
5129           GetPixelLuminance(source,p+3*GetPixelChannels(source))));
5130         luminance.y=fabs((double) (GetPixelLuminance(source,p+
5131           GetPixelChannels(source))-GetPixelLuminance(source,p+2*
5132           GetPixelChannels(source))));
5133         if (luminance.x < luminance.y)
5134           {
5135             /*
5136               Diagonal 0-3 NW-SE.
5137             */
5138             if (delta.x <= delta.y)
5139               {
5140                 /*
5141                   Bottom-left triangle (pixel: 2, diagonal: 0-3).
5142                 */
5143                 delta.y=1.0-delta.y;
5144                 gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
5145                 gamma=PerceptibleReciprocal(gamma);
5146                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5147                   MeshInterpolate(&delta,pixels[2],pixels[3],pixels[0])),pixel);
5148               }
5149             else
5150               {
5151                 /*
5152                   Top-right triangle (pixel: 1, diagonal: 0-3).
5153                 */
5154                 delta.x=1.0-delta.x;
5155                 gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
5156                 gamma=PerceptibleReciprocal(gamma);
5157                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5158                   MeshInterpolate(&delta,pixels[1],pixels[0],pixels[3])),pixel);
5159               }
5160           }
5161         else
5162           {
5163             /*
5164               Diagonal 1-2 NE-SW.
5165             */
5166             if (delta.x <= (1.0-delta.y))
5167               {
5168                 /*
5169                   Top-left triangle (pixel: 0, diagonal: 1-2).
5170                 */
5171                 gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
5172                 gamma=PerceptibleReciprocal(gamma);
5173                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5174                   MeshInterpolate(&delta,pixels[0],pixels[1],pixels[2])),pixel);
5175               }
5176             else
5177               {
5178                 /*
5179                   Bottom-right triangle (pixel: 3, diagonal: 1-2).
5180                 */
5181                 delta.x=1.0-delta.x;
5182                 delta.y=1.0-delta.y;
5183                 gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
5184                 gamma=PerceptibleReciprocal(gamma);
5185                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5186                   MeshInterpolate(&delta,pixels[3],pixels[2],pixels[1])),pixel);
5187               }
5188           }
5189       }
5190       break;
5191     }
5192     case SplineInterpolatePixel:
5193     {
5194       double
5195         cx[4],
5196         cy[4];
5197
5198       p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
5199         exception);
5200       if (p == (const Quantum *) NULL)
5201         {
5202           status=MagickFalse;
5203           break;
5204         }
5205       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5206       {
5207         register ssize_t
5208           j;
5209
5210         PixelChannel channel=GetPixelChannelChannel(source,i);
5211         PixelTrait traits=GetPixelChannelTraits(source,channel);
5212         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5213           channel);
5214         if ((traits == UndefinedPixelTrait) ||
5215             (destination_traits == UndefinedPixelTrait))
5216           continue;
5217         if ((traits & BlendPixelTrait) == 0)
5218           for (j=0; j < 16; j++)
5219           {
5220             alpha[j]=1.0;
5221             pixels[j]=(double) p[j*GetPixelChannels(source)+i];
5222           }
5223         else
5224           for (j=0; j < 16; j++)
5225           {
5226             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
5227               GetPixelChannels(source));
5228             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
5229           }
5230         SplineWeights((double) (x-x_offset),&cx);
5231         SplineWeights((double) (y-y_offset),&cy);
5232         gamma=((traits & BlendPixelTrait) ? (double) (1.0) :
5233           PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
5234           alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
5235           alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
5236           alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
5237           cx[2]*alpha[14]+cx[3]*alpha[15])));
5238         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(cy[0]*(cx[0]*
5239           pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+cx[3]*pixels[3])+cy[1]*
5240           (cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*pixels[6]+cx[3]*pixels[7])+
5241           cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+cx[2]*pixels[10]+cx[3]*
5242           pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*pixels[13]+cx[2]*
5243           pixels[14]+cx[3]*pixels[15]))),pixel);
5244       }
5245       break;
5246     }
5247   }
5248   return(status);
5249 }
5250 \f
5251 /*
5252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5253 %                                                                             %
5254 %                                                                             %
5255 %                                                                             %
5256 %   I n t e r p o l a t e P i x e l I n f o                                   %
5257 %                                                                             %
5258 %                                                                             %
5259 %                                                                             %
5260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5261 %
5262 %  InterpolatePixelInfo() applies a pixel interpolation method between a
5263 %  floating point coordinate and the pixels surrounding that coordinate.  No
5264 %  pixel area resampling, or scaling of the result is performed.
5265 %
5266 %  Interpolation is restricted to just RGBKA channels.
5267 %
5268 %  The format of the InterpolatePixelInfo method is:
5269 %
5270 %      MagickBooleanType InterpolatePixelInfo(const Image *image,
5271 %        const CacheView *image_view,const PixelInterpolateMethod method,
5272 %        const double x,const double y,PixelInfo *pixel,
5273 %        ExceptionInfo *exception)
5274 %
5275 %  A description of each parameter follows:
5276 %
5277 %    o image: the image.
5278 %
5279 %    o image_view: the image view.
5280 %
5281 %    o method: the pixel color interpolation method.
5282 %
5283 %    o x,y: A double representing the current (x,y) position of the pixel.
5284 %
5285 %    o pixel: return the interpolated pixel here.
5286 %
5287 %    o exception: return any errors or warnings in this structure.
5288 %
5289 */
5290
5291 static inline void AlphaBlendPixelInfo(const Image *image,
5292   const Quantum *pixel,PixelInfo *pixel_info,double *alpha)
5293 {
5294   if (image->alpha_trait != BlendPixelTrait)
5295     {
5296       *alpha=1.0;
5297       pixel_info->red=(double) GetPixelRed(image,pixel);
5298       pixel_info->green=(double) GetPixelGreen(image,pixel);
5299       pixel_info->blue=(double) GetPixelBlue(image,pixel);
5300       pixel_info->black=0.0;
5301       if (image->colorspace == CMYKColorspace)
5302         pixel_info->black=(double) GetPixelBlack(image,pixel);
5303       pixel_info->alpha=(double) GetPixelAlpha(image,pixel);
5304       return;
5305     }
5306   *alpha=QuantumScale*GetPixelAlpha(image,pixel);
5307   pixel_info->red=(*alpha*GetPixelRed(image,pixel));
5308   pixel_info->green=(*alpha*GetPixelGreen(image,pixel));
5309   pixel_info->blue=(*alpha*GetPixelBlue(image,pixel));
5310   pixel_info->black=0.0;
5311   if (image->colorspace == CMYKColorspace)
5312     pixel_info->black=(*alpha*GetPixelBlack(image,pixel));
5313   pixel_info->alpha=(double) GetPixelAlpha(image,pixel);
5314 }
5315
5316 MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
5317   const CacheView *image_view,const PixelInterpolateMethod method,
5318   const double x,const double y,PixelInfo *pixel,ExceptionInfo *exception)
5319 {
5320   MagickBooleanType
5321     status;
5322
5323   double
5324     alpha[16],
5325     gamma;
5326
5327   PixelInfo
5328     pixels[16];
5329
5330   register const Quantum
5331     *p;
5332
5333   register ssize_t
5334     i;
5335
5336   ssize_t
5337     x_offset,
5338     y_offset;
5339
5340   PixelInterpolateMethod
5341     interpolate;
5342
5343   assert(image != (Image *) NULL);
5344   assert(image->signature == MagickSignature);
5345   assert(image_view != (CacheView *) NULL);
5346   status=MagickTrue;
5347   x_offset=(ssize_t) floor(x);
5348   y_offset=(ssize_t) floor(y);
5349   interpolate = method;
5350   if ( interpolate == UndefinedInterpolatePixel )
5351     interpolate = image->interpolate;
5352   switch (interpolate)
5353   {
5354     case AverageInterpolatePixel:        /* nearest 4 neighbours */
5355     case Average9InterpolatePixel:       /* nearest 9 neighbours */
5356     case Average16InterpolatePixel:      /* nearest 16 neighbours */
5357     {
5358       ssize_t
5359         count;
5360
5361       count=2;  /* size of the area to average - default nearest 4 */
5362       if (interpolate == Average9InterpolatePixel)
5363         {
5364           count=3;
5365           x_offset=(ssize_t) (floor(x+0.5)-1);
5366           y_offset=(ssize_t) (floor(y+0.5)-1);
5367         }
5368       else if (interpolate == Average16InterpolatePixel)
5369         {
5370           count=4;
5371           x_offset--;
5372           y_offset--;
5373         }
5374       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,(size_t) count,(size_t)
5375         count,exception);
5376       if (p == (const Quantum *) NULL)
5377         {
5378           status=MagickFalse;
5379           break;
5380         }
5381       pixel->red=0.0;
5382       pixel->green=0.0;
5383       pixel->blue=0.0;
5384       pixel->black=0.0;
5385       pixel->alpha=0.0;
5386       count*=count;         /* number of pixels - square of size */
5387       for (i=0; i < (ssize_t) count; i++)
5388       {
5389         AlphaBlendPixelInfo(image,p,pixels,alpha);
5390         gamma=PerceptibleReciprocal(alpha[0]);
5391         pixel->red+=gamma*pixels[0].red;
5392         pixel->green+=gamma*pixels[0].green;
5393         pixel->blue+=gamma*pixels[0].blue;
5394         pixel->black+=gamma*pixels[0].black;
5395         pixel->alpha+=pixels[0].alpha;
5396         p += GetPixelChannels(image);
5397       }
5398       gamma=1.0/count;   /* average weighting of each pixel in area */
5399       pixel->red*=gamma;
5400       pixel->green*=gamma;
5401       pixel->blue*=gamma;
5402       pixel->black*=gamma;
5403       pixel->alpha*=gamma;
5404       break;
5405     }
5406     case BackgroundInterpolatePixel:
5407     {
5408       *pixel=image->background_color;  /* Copy PixelInfo Structure  */
5409       break;
5410     }
5411     case BilinearInterpolatePixel:
5412     default:
5413     {
5414       PointInfo
5415         delta,
5416         epsilon;
5417
5418       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5419       if (p == (const Quantum *) NULL)
5420         {
5421           status=MagickFalse;
5422           break;
5423         }
5424       for (i=0; i < 4L; i++)
5425         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5426       delta.x=x-x_offset;
5427       delta.y=y-y_offset;
5428       epsilon.x=1.0-delta.x;
5429       epsilon.y=1.0-delta.y;
5430       gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
5431         (epsilon.x*alpha[2]+delta.x*alpha[3])));
5432       gamma=PerceptibleReciprocal(gamma);
5433       pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
5434         pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
5435       pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
5436         pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
5437         pixels[3].green));
5438       pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
5439         pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
5440         pixels[3].blue));
5441       if (image->colorspace == CMYKColorspace)
5442         pixel->black=gamma*(epsilon.y*(epsilon.x*pixels[0].black+delta.x*
5443           pixels[1].black)+delta.y*(epsilon.x*pixels[2].black+delta.x*
5444           pixels[3].black));
5445       gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
5446       gamma=PerceptibleReciprocal(gamma);
5447       pixel->alpha=(epsilon.y*(epsilon.x*pixels[0].alpha+delta.x*
5448         pixels[1].alpha)+delta.y*(epsilon.x*pixels[2].alpha+delta.x*
5449         pixels[3].alpha));
5450       break;
5451     }
5452     case BlendInterpolatePixel:
5453     {
5454       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5455       if (p == (const Quantum *) NULL)
5456         {
5457           status=MagickFalse;
5458           break;
5459         }
5460       for (i=0; i < 4L; i++)
5461         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5462       gamma=1.0;  /* number of pixels blended together (its variable) */
5463       for (i=0; i <= 1L; i++)
5464       {
5465         if ((y-y_offset) >= 0.75)
5466           {
5467             alpha[i]=alpha[i+2];  /* take right pixels */
5468             pixels[i]=pixels[i+2];
5469           }
5470         else
5471           if ((y-y_offset) > 0.25)
5472             {
5473               gamma=2.0;  /* blend both pixels in row */
5474               alpha[i]+=alpha[i+2];  /* add up alpha weights */
5475               pixels[i].red+=pixels[i+2].red;
5476               pixels[i].green+=pixels[i+2].green;
5477               pixels[i].blue+=pixels[i+2].blue;
5478               pixels[i].black+=pixels[i+2].black;
5479               pixels[i].alpha+=pixels[i+2].alpha;
5480             }
5481       }
5482       if ((x-x_offset) >= 0.75)
5483         {
5484           alpha[0]=alpha[1];
5485           pixels[0]=pixels[1];
5486         }
5487       else
5488         if ((x-x_offset) > 0.25)
5489           {
5490             gamma*=2.0;  /* blend both rows */
5491             alpha[0]+= alpha[1];      /* add up alpha weights */
5492             pixels[0].red+=pixels[1].red;
5493             pixels[0].green+=pixels[1].green;
5494             pixels[0].blue+=pixels[1].blue;
5495             pixels[0].black+=pixels[1].black;
5496             pixels[0].alpha+=pixels[1].alpha;
5497           }
5498       gamma=1.0/gamma;
5499       alpha[0]=PerceptibleReciprocal(alpha[0]);
5500       pixel->red=alpha[0]*pixels[0].red;
5501       pixel->green=alpha[0]*pixels[0].green;  /* divide by sum of alpha */
5502       pixel->blue=alpha[0]*pixels[0].blue;
5503       pixel->black=alpha[0]*pixels[0].black;
5504       pixel->alpha=gamma*pixels[0].alpha;   /* divide by number of pixels */
5505       break;
5506     }
5507     case CatromInterpolatePixel:
5508     {
5509       double
5510         cx[4],
5511         cy[4];
5512
5513       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
5514         exception);
5515       if (p == (const Quantum *) NULL)
5516         {
5517           status=MagickFalse;
5518           break;
5519         }
5520       for (i=0; i < 16L; i++)
5521         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5522       CatromWeights((double) (x-x_offset),&cx);
5523       CatromWeights((double) (y-y_offset),&cy);
5524       pixel->red=(cy[0]*(cx[0]*pixels[0].red+cx[1]*pixels[1].red+cx[2]*
5525         pixels[2].red+cx[3]*pixels[3].red)+cy[1]*(cx[0]*pixels[4].red+cx[1]*
5526         pixels[5].red+cx[2]*pixels[6].red+cx[3]*pixels[7].red)+cy[2]*(cx[0]*
5527         pixels[8].red+cx[1]*pixels[9].red+cx[2]*pixels[10].red+cx[3]*
5528         pixels[11].red)+cy[3]*(cx[0]*pixels[12].red+cx[1]*pixels[13].red+cx[2]*
5529         pixels[14].red+cx[3]*pixels[15].red));
5530       pixel->green=(cy[0]*(cx[0]*pixels[0].green+cx[1]*pixels[1].green+cx[2]*
5531         pixels[2].green+cx[3]*pixels[3].green)+cy[1]*(cx[0]*pixels[4].green+
5532         cx[1]*pixels[5].green+cx[2]*pixels[6].green+cx[3]*pixels[7].green)+
5533         cy[2]*(cx[0]*pixels[8].green+cx[1]*pixels[9].green+cx[2]*
5534         pixels[10].green+cx[3]*pixels[11].green)+cy[3]*(cx[0]*
5535         pixels[12].green+cx[1]*pixels[13].green+cx[2]*pixels[14].green+cx[3]*
5536         pixels[15].green));
5537       pixel->blue=(cy[0]*(cx[0]*pixels[0].blue+cx[1]*pixels[1].blue+cx[2]*
5538         pixels[2].blue+cx[3]*pixels[3].blue)+cy[1]*(cx[0]*pixels[4].blue+cx[1]*
5539         pixels[5].blue+cx[2]*pixels[6].blue+cx[3]*pixels[7].blue)+cy[2]*(cx[0]*
5540         pixels[8].blue+cx[1]*pixels[9].blue+cx[2]*pixels[10].blue+cx[3]*
5541         pixels[11].blue)+cy[3]*(cx[0]*pixels[12].blue+cx[1]*pixels[13].blue+
5542         cx[2]*pixels[14].blue+cx[3]*pixels[15].blue));
5543       if (image->colorspace == CMYKColorspace)
5544         pixel->black=(cy[0]*(cx[0]*pixels[0].black+cx[1]*pixels[1].black+cx[2]*
5545           pixels[2].black+cx[3]*pixels[3].black)+cy[1]*(cx[0]*pixels[4].black+
5546           cx[1]*pixels[5].black+cx[2]*pixels[6].black+cx[3]*pixels[7].black)+
5547           cy[2]*(cx[0]*pixels[8].black+cx[1]*pixels[9].black+cx[2]*
5548           pixels[10].black+cx[3]*pixels[11].black)+cy[3]*(cx[0]*
5549           pixels[12].black+cx[1]*pixels[13].black+cx[2]*pixels[14].black+cx[3]*
5550           pixels[15].black));
5551       pixel->alpha=(cy[0]*(cx[0]*pixels[0].alpha+cx[1]*pixels[1].alpha+cx[2]*
5552         pixels[2].alpha+cx[3]*pixels[3].alpha)+cy[1]*(cx[0]*pixels[4].alpha+
5553         cx[1]*pixels[5].alpha+cx[2]*pixels[6].alpha+cx[3]*pixels[7].alpha)+
5554         cy[2]*(cx[0]*pixels[8].alpha+cx[1]*pixels[9].alpha+cx[2]*
5555         pixels[10].alpha+cx[3]*pixels[11].alpha)+cy[3]*(cx[0]*pixels[12].alpha+
5556         cx[1]*pixels[13].alpha+cx[2]*pixels[14].alpha+cx[3]*pixels[15].alpha));
5557       break;
5558     }
5559 #if 0
5560     /* deprecated useless and very slow interpolator */
5561     case FilterInterpolatePixel:
5562     {
5563       CacheView
5564         *filter_view;
5565
5566       Image
5567         *excerpt_image,
5568         *filter_image;
5569
5570       RectangleInfo
5571         geometry;
5572
5573       geometry.width=4L;
5574       geometry.height=4L;
5575       geometry.x=x_offset-1;
5576       geometry.y=y_offset-1;
5577       excerpt_image=ExcerptImage(image,&geometry,exception);
5578       if (excerpt_image == (Image *) NULL)
5579         {
5580           status=MagickFalse;
5581           break;
5582         }
5583       filter_image=ResizeImage(excerpt_image,1,1,image->filter,exception);
5584       excerpt_image=DestroyImage(excerpt_image);
5585       if (filter_image == (Image *) NULL)
5586         break;
5587       filter_view=AcquireVirtualCacheView(filter_image,exception);
5588       p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
5589       if (p != (const Quantum *) NULL)
5590         GetPixelInfoPixel(image,p,pixel);
5591       filter_view=DestroyCacheView(filter_view);
5592       filter_image=DestroyImage(filter_image);
5593       break;
5594     }
5595 #endif
5596     case IntegerInterpolatePixel:
5597     {
5598       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
5599       if (p == (const Quantum *) NULL)
5600         {
5601           status=MagickFalse;
5602           break;
5603         }
5604       GetPixelInfoPixel(image,p,pixel);
5605       break;
5606     }
5607     case MeshInterpolatePixel:
5608     {
5609       PointInfo
5610         delta,
5611         luminance;
5612
5613       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5614       if (p == (const Quantum *) NULL)
5615         {
5616           status=MagickFalse;
5617           break;
5618         }
5619       delta.x=x-x_offset;
5620       delta.y=y-y_offset;
5621       luminance.x=GetPixelLuminance(image,p)-(double)
5622         GetPixelLuminance(image,p+3*GetPixelChannels(image));
5623       luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
5624         GetPixelLuminance(image,p+2*GetPixelChannels(image));
5625       AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
5626       AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
5627       AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
5628       AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
5629       if (fabs(luminance.x) < fabs(luminance.y))
5630         {
5631           /*
5632             Diagonal 0-3 NW-SE.
5633           */
5634           if (delta.x <= delta.y)
5635             {
5636               /*
5637                 Bottom-left triangle (pixel: 2, diagonal: 0-3).
5638               */
5639               delta.y=1.0-delta.y;
5640               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
5641               gamma=PerceptibleReciprocal(gamma);
5642               pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
5643                 pixels[3].red,pixels[0].red);
5644               pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
5645                 pixels[3].green,pixels[0].green);
5646               pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
5647                 pixels[3].blue,pixels[0].blue);
5648               if (image->colorspace == CMYKColorspace)
5649                 pixel->black=gamma*MeshInterpolate(&delta,pixels[2].black,
5650                   pixels[3].black,pixels[0].black);
5651               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5652               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[2].alpha,
5653                 pixels[3].alpha,pixels[0].alpha);
5654             }
5655           else
5656             {
5657               /*
5658                 Top-right triangle (pixel:1 , diagonal: 0-3).
5659               */
5660               delta.x=1.0-delta.x;
5661               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
5662               gamma=PerceptibleReciprocal(gamma);
5663               pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
5664                 pixels[0].red,pixels[3].red);
5665               pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
5666                 pixels[0].green,pixels[3].green);
5667               pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
5668                 pixels[0].blue,pixels[3].blue);
5669               if (image->colorspace == CMYKColorspace)
5670                 pixel->black=gamma*MeshInterpolate(&delta,pixels[1].black,
5671                   pixels[0].black,pixels[3].black);
5672               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5673               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[1].alpha,
5674                 pixels[0].alpha,pixels[3].alpha);
5675             }
5676         }
5677       else
5678         {
5679           /*
5680             Diagonal 1-2 NE-SW.
5681           */
5682           if (delta.x <= (1.0-delta.y))
5683             {
5684               /*
5685                 Top-left triangle (pixel: 0, diagonal: 1-2).
5686               */
5687               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
5688               gamma=PerceptibleReciprocal(gamma);
5689               pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
5690                 pixels[1].red,pixels[2].red);
5691               pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
5692                 pixels[1].green,pixels[2].green);
5693               pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
5694                 pixels[1].blue,pixels[2].blue);
5695               if (image->colorspace == CMYKColorspace)
5696                 pixel->black=gamma*MeshInterpolate(&delta,pixels[0].black,
5697                   pixels[1].black,pixels[2].black);
5698               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5699               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[0].alpha,
5700                 pixels[1].alpha,pixels[2].alpha);
5701             }
5702           else
5703             {
5704               /*
5705                 Bottom-right triangle (pixel: 3, diagonal: 1-2).
5706               */
5707               delta.x=1.0-delta.x;
5708               delta.y=1.0-delta.y;
5709               gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
5710               gamma=PerceptibleReciprocal(gamma);
5711               pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
5712                 pixels[2].red,pixels[1].red);
5713               pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
5714                 pixels[2].green,pixels[1].green);
5715               pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
5716                 pixels[2].blue,pixels[1].blue);
5717               if (image->colorspace == CMYKColorspace)
5718                 pixel->black=gamma*MeshInterpolate(&delta,pixels[3].black,
5719                   pixels[2].black,pixels[1].black);
5720               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5721               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[3].alpha,
5722                 pixels[2].alpha,pixels[1].alpha);
5723             }
5724         }
5725       break;
5726     }
5727     case NearestInterpolatePixel:
5728     {
5729       x_offset=(ssize_t) floor(x+0.5);
5730       y_offset=(ssize_t) floor(y+0.5);
5731       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
5732       if (p == (const Quantum *) NULL)
5733         {
5734           status=MagickFalse;
5735           break;
5736         }
5737       GetPixelInfoPixel(image,p,pixel);
5738       break;
5739     }
5740     case SplineInterpolatePixel:
5741     {
5742       double
5743         cx[4],
5744         cy[4];
5745
5746       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
5747         exception);
5748       if (p == (const Quantum *) NULL)
5749         {
5750           status=MagickFalse;
5751           break;
5752         }
5753       for (i=0; i < 16L; i++)
5754         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5755       SplineWeights((double) (x-x_offset),&cx);
5756       SplineWeights((double) (y-y_offset),&cy);
5757       pixel->red=(cy[0]*(cx[0]*pixels[0].red+cx[1]*pixels[1].red+cx[2]*
5758         pixels[2].red+cx[3]*pixels[3].red)+cy[1]*(cx[0]*pixels[4].red+cx[1]*
5759         pixels[5].red+cx[2]*pixels[6].red+cx[3]*pixels[7].red)+cy[2]*(cx[0]*
5760         pixels[8].red+cx[1]*pixels[9].red+cx[2]*pixels[10].red+cx[3]*
5761         pixels[11].red)+cy[3]*(cx[0]*pixels[12].red+cx[1]*pixels[13].red+cx[2]*
5762         pixels[14].red+cx[3]*pixels[15].red));
5763       pixel->green=(cy[0]*(cx[0]*pixels[0].green+cx[1]*pixels[1].green+cx[2]*
5764         pixels[2].green+cx[3]*pixels[3].green)+cy[1]*(cx[0]*pixels[4].green+
5765         cx[1]*pixels[5].green+cx[2]*pixels[6].green+cx[3]*pixels[7].green)+
5766         cy[2]*(cx[0]*pixels[8].green+cx[1]*pixels[9].green+cx[2]*
5767         pixels[10].green+cx[3]*pixels[11].green)+cy[3]*(cx[0]*pixels[12].green+
5768         cx[1]*pixels[13].green+cx[2]*pixels[14].green+cx[3]*pixels[15].green));
5769       pixel->blue=(cy[0]*(cx[0]*pixels[0].blue+cx[1]*pixels[1].blue+cx[2]*
5770         pixels[2].blue+cx[3]*pixels[3].blue)+cy[1]*(cx[0]*pixels[4].blue+cx[1]*
5771         pixels[5].blue+cx[2]*pixels[6].blue+cx[3]*pixels[7].blue)+cy[2]*(cx[0]*
5772         pixels[8].blue+cx[1]*pixels[9].blue+cx[2]*pixels[10].blue+cx[3]*
5773         pixels[11].blue)+cy[3]*(cx[0]*pixels[12].blue+cx[1]*pixels[13].blue+
5774         cx[2]*pixels[14].blue+cx[3]*pixels[15].blue));
5775       if (image->colorspace == CMYKColorspace)
5776         pixel->black=(cy[0]*(cx[0]*pixels[0].black+cx[1]*pixels[1].black+cx[2]*
5777           pixels[2].black+cx[3]*pixels[3].black)+cy[1]*(cx[0]*pixels[4].black+
5778           cx[1]*pixels[5].black+cx[2]*pixels[6].black+cx[3]*pixels[7].black)+
5779           cy[2]*(cx[0]*pixels[8].black+cx[1]*pixels[9].black+cx[2]*
5780           pixels[10].black+cx[3]*pixels[11].black)+cy[3]*(cx[0]*
5781           pixels[12].black+cx[1]*pixels[13].black+cx[2]*pixels[14].black+cx[3]*
5782           pixels[15].black));
5783       pixel->alpha=(cy[0]*(cx[0]*pixels[0].alpha+cx[1]*pixels[1].alpha+cx[2]*
5784         pixels[2].alpha+cx[3]*pixels[3].alpha)+cy[1]*(cx[0]*pixels[4].alpha+
5785         cx[1]*pixels[5].alpha+cx[2]*pixels[6].alpha+cx[3]*pixels[7].alpha)+
5786         cy[2]*(cx[0]*pixels[8].alpha+cx[1]*pixels[9].alpha+cx[2]*
5787         pixels[10].alpha+cx[3]*pixels[11].alpha)+cy[3]*(cx[0]*pixels[12].alpha+
5788         cx[1]*pixels[13].alpha+cx[2]*pixels[14].alpha+cx[3]*pixels[15].alpha));
5789       break;
5790     }
5791   }
5792   return(status);
5793 }
5794 \f
5795 /*
5796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5797 %                                                                             %
5798 %                                                                             %
5799 %                                                                             %
5800 +   I s F u z z y E q u i v a l e n c e P i x e l                             %
5801 %                                                                             %
5802 %                                                                             %
5803 %                                                                             %
5804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5805 %
5806 %  IsFuzzyEquivalencePixel() returns MagickTrue if the distance between two
5807 %  pixels is less than the specified distance in a linear three (or four)u
5808 %  dimensional color space.
5809 %
5810 %  The format of the IsFuzzyEquivalencePixel method is:
5811 %
5812 %      void IsFuzzyEquivalencePixel(const Image *source,const Quantum *p,
5813 %        const Image *destination,const Quantum *q)
5814 %
5815 %  A description of each parameter follows:
5816 %
5817 %    o source: the source image.
5818 %
5819 %    o p: Pixel p.
5820 %
5821 %    o destination: the destination image.
5822 %
5823 %    o q: Pixel q.
5824 %
5825 */
5826 MagickExport MagickBooleanType IsFuzzyEquivalencePixel(const Image *source,
5827   const Quantum *p,const Image *destination,const Quantum *q)
5828 {
5829   double
5830     fuzz,
5831     pixel;
5832
5833   register double
5834     distance,
5835     scale;
5836
5837   fuzz=MagickMax(source->fuzz,(double) MagickSQ1_2)*MagickMax(
5838     destination->fuzz,(double) MagickSQ1_2);
5839   scale=1.0;
5840   distance=0.0;
5841   if (source->alpha_trait == BlendPixelTrait)
5842     {
5843       /*
5844         Transparencies are involved - set alpha distance
5845       */
5846       pixel=GetPixelAlpha(source,p)-(double) GetPixelAlpha(destination,q);
5847       distance=pixel*pixel;
5848       if (distance > fuzz)
5849         return(MagickFalse);
5850       /*
5851         Generate a alpha scaling factor to generate a 4D cone on colorspace
5852         Note that if one color is transparent, distance has no color component.
5853       */
5854       scale=QuantumScale*GetPixelAlpha(source,p);
5855       scale*=QuantumScale*GetPixelAlpha(destination,q);
5856       if (scale <= MagickEpsilon)
5857         return(MagickTrue);
5858     }
5859   /*
5860     RGB or CMY color cube
5861   */
5862   distance*=3.0;  /* rescale appropriately */
5863   fuzz*=3.0;
5864   pixel=GetPixelRed(source,p)-(double) GetPixelRed(destination,q);
5865   if ((source->colorspace == HSLColorspace) ||
5866       (source->colorspace == HSBColorspace) ||
5867       (source->colorspace == HWBColorspace))
5868     {
5869       /*
5870         Compute an arc distance for hue.  It should be a vector angle of
5871         'S'/'W' length with 'L'/'B' forming appropriate cones.
5872       */
5873       if (fabs((double) pixel) > (QuantumRange/2))
5874         pixel-=QuantumRange;
5875       pixel*=2;
5876     }
5877   distance+=scale*pixel*pixel;
5878   if (distance > fuzz)
5879     return(MagickFalse);
5880   pixel=GetPixelGreen(source,p)-(double) GetPixelGreen(destination,q);
5881   distance+=scale*pixel*pixel;
5882   if (distance > fuzz)
5883     return(MagickFalse);
5884   pixel=GetPixelBlue(source,p)-(double) GetPixelBlue(destination,q);
5885   distance+=scale*pixel*pixel;
5886   if (distance > fuzz)
5887     return(MagickFalse);
5888   return(MagickTrue);
5889 }
5890 \f
5891 /*
5892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5893 %                                                                             %
5894 %                                                                             %
5895 %                                                                             %
5896 +   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                     %
5897 %                                                                             %
5898 %                                                                             %
5899 %                                                                             %
5900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5901 %
5902 %  IsFuzzyEquivalencePixelInfo() returns true if the distance between two
5903 %  colors is less than the specified distance in a linear three (or four)
5904 %  dimensional color space.
5905 %
5906 %  This implements the equivalent of:
5907 %    fuzz < sqrt(color_distance^2 * u.a*v.a  + alpha_distance^2)
5908 %
5909 %  Which produces a multi-dimensional cone for that colorspace along the
5910 %  transparency vector.
5911 %
5912 %  For example for an RGB:
5913 %    color_distance^2  = ( (u.r-v.r)^2 + (u.g-v.g)^2 + (u.b-v.b)^2 ) / 3
5914 %
5915 %  See http://www.imagemagick.org/Usage/bugs/fuzz_distance/
5916 %
5917 %  Hue colorspace distances need more work.  Hue is not a distance, it is an
5918 %  angle!
5919 %
5920 %  A check that q is in the same color space as p should be made and the
5921 %  appropriate mapping made.  -- Anthony Thyssen  8 December 2010
5922 %
5923 %  The format of the IsFuzzyEquivalencePixelInfo method is:
5924 %
5925 %      MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
5926 %        const PixelInfo *q)
5927 %
5928 %  A description of each parameter follows:
5929 %
5930 %    o p: Pixel p.
5931 %
5932 %    o q: Pixel q.
5933 %
5934 */
5935 MagickExport MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
5936   const PixelInfo *q)
5937 {
5938   double
5939     fuzz,
5940     pixel;
5941
5942   register double
5943     scale,
5944     distance;
5945
5946   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
5947     return(IsPixelInfoEquivalent(p,q));
5948   if (p->fuzz == 0.0)
5949     fuzz=MagickMax(q->fuzz,(double) MagickSQ1_2)*MagickMax(q->fuzz,
5950       (double) MagickSQ1_2);
5951   else if (q->fuzz == 0.0)
5952     fuzz=MagickMax(p->fuzz,(double) MagickSQ1_2)*MagickMax(p->fuzz,
5953       (double) MagickSQ1_2);
5954   else
5955     fuzz=MagickMax(p->fuzz,(double) MagickSQ1_2)*MagickMax(q->fuzz,
5956       (double) MagickSQ1_2);
5957   scale=1.0;
5958   distance=0.0;
5959   if ((p->alpha_trait == BlendPixelTrait) || (q->alpha_trait == BlendPixelTrait))
5960     {
5961       /*
5962         Transparencies are involved - set alpha distance.
5963       */
5964       pixel=(p->alpha_trait == BlendPixelTrait ? p->alpha : OpaqueAlpha)-
5965         (q->alpha_trait == BlendPixelTrait ? q->alpha : OpaqueAlpha);
5966       distance=pixel*pixel;
5967       if (distance > fuzz)
5968         return(MagickFalse);
5969       /*
5970         Generate a alpha scaling factor to generate a 4D cone on colorspace.
5971         If one color is transparent, distance has no color component.
5972       */
5973       if (p->alpha_trait == BlendPixelTrait)
5974         scale=(QuantumScale*p->alpha);
5975       if (q->alpha_trait == BlendPixelTrait)
5976         scale*=(QuantumScale*q->alpha);
5977       if (scale <= MagickEpsilon )
5978         return(MagickTrue);
5979     }
5980   /*
5981     CMYK create a CMY cube with a multi-dimensional cone toward black.
5982   */
5983   if (p->colorspace == CMYKColorspace)
5984     {
5985       pixel=p->black-q->black;
5986       distance+=pixel*pixel*scale;
5987       if (distance > fuzz)
5988         return(MagickFalse);
5989       scale*=(double) (QuantumScale*(QuantumRange-p->black));
5990       scale*=(double) (QuantumScale*(QuantumRange-q->black));
5991     }
5992   /*
5993     RGB or CMY color cube.
5994   */
5995   distance*=3.0;  /* rescale appropriately */
5996   fuzz*=3.0;
5997   pixel=p->red-q->red;
5998   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
5999       (p->colorspace == HWBColorspace))
6000     {
6001       /*
6002         This calculates a arc distance for hue-- it should be a vector angle
6003         of 'S'/'W' length with 'L'/'B' forming appropriate cones.  In other
6004         words this is a hack - Anthony.
6005       */
6006       if (fabs((double) pixel) > (QuantumRange/2))
6007         pixel-=QuantumRange;
6008       pixel*=2;
6009     }
6010   distance+=pixel*pixel*scale;
6011   if (distance > fuzz)
6012     return(MagickFalse);
6013   pixel=p->green-q->green;
6014   distance+=pixel*pixel*scale;
6015   if (distance > fuzz)
6016     return(MagickFalse);
6017   pixel=p->blue-q->blue;
6018   distance+=pixel*pixel*scale;
6019   if (distance > fuzz)
6020     return(MagickFalse);
6021   return(MagickTrue);
6022 }
6023 \f
6024 /*
6025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6026 %                                                                             %
6027 %                                                                             %
6028 %                                                                             %
6029 %   S e t P i x e l C h a n n e l M a p M a s k                               %
6030 %                                                                             %
6031 %                                                                             %
6032 %                                                                             %
6033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6034 %
6035 %  SetPixelChannelMask() sets the pixel channel map from the specified
6036 %  channel mask.
6037 %
6038 %  The format of the SetPixelChannelMask method is:
6039 %
6040 %      void SetPixelChannelMask(Image *image,const ChannelType channel_mask)
6041 %
6042 %  A description of each parameter follows:
6043 %
6044 %    o image: the image.
6045 %
6046 %    o channel_mask: the channel mask.
6047 %
6048 */
6049 MagickExport void SetPixelChannelMask(Image *image,
6050   const ChannelType channel_mask)
6051 {
6052 #define GetChannelBit(mask,bit)  (((size_t) (mask) >> (size_t) (bit)) & 0x01)
6053
6054   register ssize_t
6055     i;
6056
6057   if (image->debug != MagickFalse)
6058     (void) LogMagickEvent(PixelEvent,GetMagickModule(),"%s[%08x]", \
6059       image->filename,channel_mask); \
6060   image->channel_mask=channel_mask;
6061   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
6062   {
6063     PixelChannel channel=GetPixelChannelChannel(image,i);
6064     SetPixelChannelTraits(image,channel,
6065       GetChannelBit(channel_mask,channel) == 0 ? CopyPixelTrait :
6066       image->alpha_trait != BlendPixelTrait || (channel == AlphaPixelChannel) ?
6067       UpdatePixelTrait : (PixelTrait) (UpdatePixelTrait | image->alpha_trait));
6068   }
6069   if (image->storage_class == PseudoClass)
6070     SetPixelChannelTraits(image,IndexPixelChannel,CopyPixelTrait);
6071   if (image->mask != MagickFalse)
6072     SetPixelChannelTraits(image,MaskPixelChannel,CopyPixelTrait);
6073   if (image->debug != MagickFalse)
6074     LogPixelChannels(image);
6075 }
6076 \f
6077 /*
6078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6079 %                                                                             %
6080 %                                                                             %
6081 %                                                                             %
6082 %   S e t P i x e l M e t a C h a n n e l s                                   %
6083 %                                                                             %
6084 %                                                                             %
6085 %                                                                             %
6086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6087 %
6088 %  SetPixelMetaChannels() sets the image meta channels.
6089 %
6090 %  The format of the SetPixelMetaChannels method is:
6091 %
6092 %      MagickBooleanType SetPixelMetaChannels(Image *image,
6093 %        const size_t number_meta_channels,ExceptionInfo *exception)
6094 %
6095 %  A description of each parameter follows:
6096 %
6097 %    o image: the image.
6098 %
6099 %    o number_meta_channels:  the number of meta channels.
6100 %
6101 %    o exception: return any errors or warnings in this structure.
6102 %
6103 */
6104 MagickExport MagickBooleanType SetPixelMetaChannels(Image *image,
6105   const size_t number_meta_channels,ExceptionInfo *exception)
6106 {
6107   image->number_meta_channels=number_meta_channels;
6108   return(SyncImagePixelCache(image,exception));
6109 }