1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                         CCCC  M   M  Y   Y  K   K                           %
7%                        C      MM MM   Y Y   K  K                            %
8%                        C      M M M    Y    KKK                             %
9%                        C      M   M    Y    K  K                            %
10%                         CCCC  M   M    Y    K   K                           %
11%                                                                             %
12%                                                                             %
13%                     Read/Write RAW CMYK Image Format                        %
14%                                                                             %
15%                              Software Design                                %
16%                                   Cristy                                    %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/channel.h"
47#include "MagickCore/colorspace.h"
48#include "MagickCore/constitute.h"
49#include "MagickCore/exception.h"
50#include "MagickCore/exception-private.h"
51#include "MagickCore/image.h"
52#include "MagickCore/image-private.h"
53#include "MagickCore/list.h"
54#include "MagickCore/magick.h"
55#include "MagickCore/memory_.h"
56#include "MagickCore/monitor.h"
57#include "MagickCore/monitor-private.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/quantum-private.h"
60#include "MagickCore/static.h"
61#include "MagickCore/statistic.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/module.h"
64#include "MagickCore/utility.h"
65
66/*
67  Forward declarations.
68*/
69static MagickBooleanType
70  WriteCMYKImage(const ImageInfo *,Image *,ExceptionInfo *);
71
72/*
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74%                                                                             %
75%                                                                             %
76%                                                                             %
77%   R e a d C M Y K I m a g e                                                 %
78%                                                                             %
79%                                                                             %
80%                                                                             %
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82%
83%  ReadCMYKImage() reads an image of raw CMYK or CMYKA samples and returns it.
84%  It allocates the memory necessary for the new Image structure and returns a
85%  pointer to the new image.
86%
87%  The format of the ReadCMYKImage method is:
88%
89%      Image *ReadCMYKImage(const ImageInfo *image_info,
90%        ExceptionInfo *exception)
91%
92%  A description of each parameter follows:
93%
94%    o image_info: the image info.
95%
96%    o exception: return any errors or warnings in this structure.
97%
98*/
99static Image *ReadCMYKImage(const ImageInfo *image_info,
100  ExceptionInfo *exception)
101{
102  const unsigned char
103    *pixels;
104
105  Image
106    *canvas_image,
107    *image;
108
109  MagickBooleanType
110    status;
111
112  MagickOffsetType
113    scene;
114
115  QuantumInfo
116    *quantum_info;
117
118  QuantumType
119    quantum_type;
120
121  register ssize_t
122    i;
123
124  size_t
125    length;
126
127  ssize_t
128    count,
129    y;
130
131  /*
132    Open image file.
133  */
134  assert(image_info != (const ImageInfo *) NULL);
135  assert(image_info->signature == MagickCoreSignature);
136  if (image_info->debug != MagickFalse)
137    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
138      image_info->filename);
139  assert(exception != (ExceptionInfo *) NULL);
140  assert(exception->signature == MagickCoreSignature);
141  image=AcquireImage(image_info,exception);
142  if ((image->columns == 0) || (image->rows == 0))
143    ThrowReaderException(OptionError,"MustSpecifyImageSize");
144  SetImageColorspace(image,CMYKColorspace,exception);
145  if (image_info->interlace != PartitionInterlace)
146    {
147      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
148      if (status == MagickFalse)
149        {
150          image=DestroyImageList(image);
151          return((Image *) NULL);
152        }
153      if (DiscardBlobBytes(image,image->offset) == MagickFalse)
154        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
155          image->filename);
156    }
157  /*
158    Create virtual canvas to support cropping (i.e. image.cmyk[100x100+10+20]).
159  */
160  canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
161    exception);
162  (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
163    exception);
164  quantum_info=AcquireQuantumInfo(image_info,canvas_image);
165  if (quantum_info == (QuantumInfo *) NULL)
166    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
167  quantum_type=CMYKQuantum;
168  if (LocaleCompare(image_info->magick,"CMYKA") == 0)
169    {
170      quantum_type=CMYKAQuantum;
171      image->alpha_trait=BlendPixelTrait;
172    }
173  pixels=(const unsigned char *) NULL;
174  if (image_info->number_scenes != 0)
175    while (image->scene < image_info->scene)
176    {
177      /*
178        Skip to next image.
179      */
180      image->scene++;
181      length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
182      for (y=0; y < (ssize_t) image->rows; y++)
183      {
184        pixels=(const unsigned char *) ReadBlobStream(image,length,
185          GetQuantumPixels(quantum_info),&count);
186        if (count != (ssize_t) length)
187          break;
188      }
189    }
190  count=0;
191  length=0;
192  scene=0;
193  do
194  {
195    /*
196      Read pixels to virtual canvas image then push to image.
197    */
198    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
199      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
200        break;
201    status=SetImageExtent(image,image->columns,image->rows,exception);
202    if (status == MagickFalse)
203      return(DestroyImageList(image));
204    SetImageColorspace(image,CMYKColorspace,exception);
205    switch (image_info->interlace)
206    {
207      case NoInterlace:
208      default:
209      {
210        /*
211          No interlacing:  CMYKCMYKCMYKCMYKCMYKCMYK...
212        */
213        if (scene == 0)
214          {
215            length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
216            pixels=(const unsigned char *) ReadBlobStream(image,length,
217              GetQuantumPixels(quantum_info),&count);
218          }
219        for (y=0; y < (ssize_t) image->extract_info.height; y++)
220        {
221          register const Quantum
222            *magick_restrict p;
223
224          register Quantum
225            *magick_restrict q;
226
227          register ssize_t
228            x;
229
230          if (count != (ssize_t) length)
231            {
232              ThrowFileException(exception,CorruptImageError,
233                "UnexpectedEndOfFile",image->filename);
234              break;
235            }
236          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
237            exception);
238          if (q == (Quantum *) NULL)
239            break;
240          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
241            quantum_info,quantum_type,pixels,exception);
242          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
243            break;
244          if (((y-image->extract_info.y) >= 0) &&
245              ((y-image->extract_info.y) < (ssize_t) image->rows))
246            {
247              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
248                canvas_image->columns,1,exception);
249              q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
250                image->columns,1,exception);
251              if ((p == (const Quantum *) NULL) ||
252                  (q == (Quantum *) NULL))
253                break;
254              for (x=0; x < (ssize_t) image->columns; x++)
255              {
256                SetPixelRed(image,GetPixelRed(canvas_image,p),q);
257                SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
258                SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
259                SetPixelBlack(image,GetPixelBlack(canvas_image,p),q);
260                SetPixelAlpha(image,OpaqueAlpha,q);
261                if (image->alpha_trait != UndefinedPixelTrait)
262                  SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
263                p+=GetPixelChannels(canvas_image);
264                q+=GetPixelChannels(image);
265              }
266              if (SyncAuthenticPixels(image,exception) == MagickFalse)
267                break;
268            }
269          if (image->previous == (Image *) NULL)
270            {
271              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
272                image->rows);
273              if (status == MagickFalse)
274                break;
275            }
276          pixels=(const unsigned char *) ReadBlobStream(image,length,
277            GetQuantumPixels(quantum_info),&count);
278        }
279        break;
280      }
281      case LineInterlace:
282      {
283        static QuantumType
284          quantum_types[5] =
285          {
286            CyanQuantum,
287            MagentaQuantum,
288            YellowQuantum,
289            BlackQuantum,
290            OpacityQuantum
291          };
292
293        /*
294          Line interlacing:  CCC...MMM...YYY...KKK...CCC...MMM...YYY...KKK...
295        */
296        if (scene == 0)
297          {
298            length=GetQuantumExtent(canvas_image,quantum_info,CyanQuantum);
299            pixels=(const unsigned char *) ReadBlobStream(image,length,
300              GetQuantumPixels(quantum_info),&count);
301          }
302        for (y=0; y < (ssize_t) image->extract_info.height; y++)
303        {
304          register const Quantum
305            *magick_restrict p;
306
307          register Quantum
308            *magick_restrict q;
309
310          register ssize_t
311            x;
312
313          if (count != (ssize_t) length)
314            {
315              ThrowFileException(exception,CorruptImageError,
316                "UnexpectedEndOfFile",image->filename);
317              break;
318            }
319          for (i=0; i < (image->alpha_trait != UndefinedPixelTrait ? 5 : 4); i++)
320          {
321            quantum_type=quantum_types[i];
322            q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
323              exception);
324            if (q == (Quantum *) NULL)
325              break;
326            length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
327              quantum_info,quantum_type,pixels,exception);
328            if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
329              break;
330            if (((y-image->extract_info.y) >= 0) &&
331                ((y-image->extract_info.y) < (ssize_t) image->rows))
332              {
333                p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
334                  0,canvas_image->columns,1,exception);
335                q=GetAuthenticPixels(image,0,y-image->extract_info.y,
336                  image->columns,1,exception);
337                if ((p == (const Quantum *) NULL) ||
338                    (q == (Quantum *) NULL))
339                  break;
340                for (x=0; x < (ssize_t) image->columns; x++)
341                {
342                  switch (quantum_type)
343                  {
344                    case CyanQuantum:
345                    {
346                      SetPixelCyan(image,GetPixelCyan(canvas_image,p),q);
347                      break;
348                    }
349                    case MagentaQuantum:
350                    {
351                      SetPixelMagenta(image,GetPixelMagenta(canvas_image,p),q);
352                      break;
353                    }
354                    case YellowQuantum:
355                    {
356                      SetPixelYellow(image,GetPixelYellow(canvas_image,p),q);
357                      break;
358                    }
359                    case BlackQuantum:
360                    {
361                      SetPixelBlack(image,GetPixelBlack(canvas_image,p),q);
362                      break;
363                    }
364                    case OpacityQuantum:
365                    {
366                      SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
367                      break;
368                    }
369                    default:
370                      break;
371                  }
372                  p+=GetPixelChannels(canvas_image);
373                  q+=GetPixelChannels(image);
374                }
375                if (SyncAuthenticPixels(image,exception) == MagickFalse)
376                  break;
377              }
378            pixels=(const unsigned char *) ReadBlobStream(image,length,
379              GetQuantumPixels(quantum_info),&count);
380          }
381          if (image->previous == (Image *) NULL)
382            {
383              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
384                image->rows);
385              if (status == MagickFalse)
386                break;
387            }
388        }
389        break;
390      }
391      case PlaneInterlace:
392      {
393        /*
394          Plane interlacing:  CCCCCC...MMMMMM...YYYYYY...KKKKKK...
395        */
396        if (scene == 0)
397          {
398            length=GetQuantumExtent(canvas_image,quantum_info,CyanQuantum);
399            pixels=(const unsigned char *) ReadBlobStream(image,length,
400              GetQuantumPixels(quantum_info),&count);
401          }
402        for (y=0; y < (ssize_t) image->extract_info.height; y++)
403        {
404          register const Quantum
405            *magick_restrict p;
406
407          register Quantum
408            *magick_restrict q;
409
410          register ssize_t
411            x;
412
413          if (count != (ssize_t) length)
414            {
415              ThrowFileException(exception,CorruptImageError,
416                "UnexpectedEndOfFile",image->filename);
417              break;
418            }
419          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
420            exception);
421          if (q == (Quantum *) NULL)
422            break;
423          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
424            quantum_info,CyanQuantum,pixels,exception);
425          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
426            break;
427          if (((y-image->extract_info.y) >= 0) &&
428              ((y-image->extract_info.y) < (ssize_t) image->rows))
429            {
430              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
431                canvas_image->columns,1,exception);
432              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
433                image->columns,1,exception);
434              if ((p == (const Quantum *) NULL) ||
435                  (q == (Quantum *) NULL))
436                break;
437              for (x=0; x < (ssize_t) image->columns; x++)
438              {
439                SetPixelRed(image,GetPixelRed(canvas_image,p),q);
440                p+=GetPixelChannels(canvas_image);
441                q+=GetPixelChannels(image);
442              }
443              if (SyncAuthenticPixels(image,exception) == MagickFalse)
444                break;
445            }
446          pixels=(const unsigned char *) ReadBlobStream(image,length,
447            GetQuantumPixels(quantum_info),&count);
448        }
449        if (image->previous == (Image *) NULL)
450          {
451            status=SetImageProgress(image,LoadImageTag,1,6);
452            if (status == MagickFalse)
453              break;
454          }
455        for (y=0; y < (ssize_t) image->extract_info.height; y++)
456        {
457          register const Quantum
458            *magick_restrict p;
459
460          register Quantum
461            *magick_restrict q;
462
463          register ssize_t
464            x;
465
466          if (count != (ssize_t) length)
467            {
468              ThrowFileException(exception,CorruptImageError,
469                "UnexpectedEndOfFile",image->filename);
470              break;
471            }
472          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
473            exception);
474          if (q == (Quantum *) NULL)
475            break;
476          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
477            quantum_info,MagentaQuantum,pixels,exception);
478          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
479            break;
480          if (((y-image->extract_info.y) >= 0) &&
481              ((y-image->extract_info.y) < (ssize_t) image->rows))
482            {
483              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
484                canvas_image->columns,1,exception);
485              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
486                image->columns,1,exception);
487              if ((p == (const Quantum *) NULL) ||
488                  (q == (Quantum *) NULL))
489                break;
490              for (x=0; x < (ssize_t) image->columns; x++)
491              {
492                SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
493                p+=GetPixelChannels(canvas_image);
494                q+=GetPixelChannels(image);
495              }
496              if (SyncAuthenticPixels(image,exception) == MagickFalse)
497                break;
498           }
499          pixels=(const unsigned char *) ReadBlobStream(image,length,
500            GetQuantumPixels(quantum_info),&count);
501        }
502        if (image->previous == (Image *) NULL)
503          {
504            status=SetImageProgress(image,LoadImageTag,2,6);
505            if (status == MagickFalse)
506              break;
507          }
508        for (y=0; y < (ssize_t) image->extract_info.height; y++)
509        {
510          register const Quantum
511            *magick_restrict p;
512
513          register Quantum
514            *magick_restrict q;
515
516          register ssize_t
517            x;
518
519          if (count != (ssize_t) length)
520            {
521              ThrowFileException(exception,CorruptImageError,
522                "UnexpectedEndOfFile",image->filename);
523              break;
524            }
525          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
526            exception);
527          if (q == (Quantum *) NULL)
528            break;
529          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
530            quantum_info,YellowQuantum,pixels,exception);
531          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
532            break;
533          if (((y-image->extract_info.y) >= 0) &&
534              ((y-image->extract_info.y) < (ssize_t) image->rows))
535            {
536              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
537                canvas_image->columns,1,exception);
538              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
539                image->columns,1,exception);
540              if ((p == (const Quantum *) NULL) ||
541                  (q == (Quantum *) NULL))
542                break;
543              for (x=0; x < (ssize_t) image->columns; x++)
544              {
545                SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
546                p+=GetPixelChannels(canvas_image);
547                q+=GetPixelChannels(image);
548              }
549              if (SyncAuthenticPixels(image,exception) == MagickFalse)
550                break;
551            }
552          pixels=(const unsigned char *) ReadBlobStream(image,length,
553            GetQuantumPixels(quantum_info),&count);
554        }
555        if (image->previous == (Image *) NULL)
556          {
557            status=SetImageProgress(image,LoadImageTag,3,6);
558            if (status == MagickFalse)
559              break;
560          }
561        for (y=0; y < (ssize_t) image->extract_info.height; y++)
562        {
563          register const Quantum
564            *magick_restrict p;
565
566          register Quantum
567            *magick_restrict q;
568
569          register ssize_t
570            x;
571
572          if (count != (ssize_t) length)
573            {
574              ThrowFileException(exception,CorruptImageError,
575                "UnexpectedEndOfFile",image->filename);
576              break;
577            }
578          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
579            exception);
580          if (q == (Quantum *) NULL)
581            break;
582          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
583            quantum_info,BlackQuantum,pixels,exception);
584          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
585            break;
586          if (((y-image->extract_info.y) >= 0) &&
587              ((y-image->extract_info.y) < (ssize_t) image->rows))
588            {
589              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
590                canvas_image->columns,1,exception);
591              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
592                image->columns,1,exception);
593              if ((p == (const Quantum *) NULL) ||
594                  (q == (Quantum *) NULL))
595                break;
596              for (x=0; x < (ssize_t) image->columns; x++)
597              {
598                SetPixelBlack(image,GetPixelBlack(canvas_image,p),q);
599                p+=GetPixelChannels(canvas_image);
600                q+=GetPixelChannels(image);
601              }
602              if (SyncAuthenticPixels(image,exception) == MagickFalse)
603                break;
604            }
605          pixels=(const unsigned char *) ReadBlobStream(image,length,
606            GetQuantumPixels(quantum_info),&count);
607        }
608        if (image->previous == (Image *) NULL)
609          {
610            status=SetImageProgress(image,LoadImageTag,4,6);
611            if (status == MagickFalse)
612              break;
613          }
614        if (image->alpha_trait != UndefinedPixelTrait)
615          {
616            for (y=0; y < (ssize_t) image->extract_info.height; y++)
617            {
618              register const Quantum
619                *magick_restrict p;
620
621              register Quantum
622                *magick_restrict q;
623
624              register ssize_t
625                x;
626
627              if (count != (ssize_t) length)
628                {
629                  ThrowFileException(exception,CorruptImageError,
630                    "UnexpectedEndOfFile",image->filename);
631                  break;
632                }
633              q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
634                exception);
635              if (q == (Quantum *) NULL)
636                break;
637              length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
638                quantum_info,AlphaQuantum,pixels,exception);
639              if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
640                break;
641              if (((y-image->extract_info.y) >= 0) &&
642                  ((y-image->extract_info.y) < (ssize_t) image->rows))
643                {
644                  p=GetVirtualPixels(canvas_image,
645                    canvas_image->extract_info.x,0,canvas_image->columns,1,
646                    exception);
647                  q=GetAuthenticPixels(image,0,y-image->extract_info.y,
648                    image->columns,1,exception);
649                  if ((p == (const Quantum *) NULL) ||
650                      (q == (Quantum *) NULL))
651                    break;
652                  for (x=0; x < (ssize_t) image->columns; x++)
653                  {
654                    SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
655                    p+=GetPixelChannels(canvas_image);
656                    q+=GetPixelChannels(image);
657                  }
658                  if (SyncAuthenticPixels(image,exception) == MagickFalse)
659                    break;
660                }
661              pixels=(const unsigned char *) ReadBlobStream(image,length,
662                GetQuantumPixels(quantum_info),&count);
663            }
664            if (image->previous == (Image *) NULL)
665              {
666                status=SetImageProgress(image,LoadImageTag,5,6);
667                if (status == MagickFalse)
668                  break;
669              }
670          }
671        if (image->previous == (Image *) NULL)
672          {
673            status=SetImageProgress(image,LoadImageTag,6,6);
674            if (status == MagickFalse)
675              break;
676          }
677        break;
678      }
679      case PartitionInterlace:
680      {
681        /*
682          Partition interlacing:  CCCCCC..., MMMMMM..., YYYYYY..., KKKKKK...
683        */
684        AppendImageFormat("C",image->filename);
685        status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
686        if (status == MagickFalse)
687          {
688            canvas_image=DestroyImageList(canvas_image);
689            image=DestroyImageList(image);
690            return((Image *) NULL);
691          }
692        if (DiscardBlobBytes(image,image->offset) == MagickFalse)
693          ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
694            image->filename);
695        length=GetQuantumExtent(canvas_image,quantum_info,CyanQuantum);
696        for (i=0; i < (ssize_t) scene; i++)
697          for (y=0; y < (ssize_t) image->extract_info.height; y++)
698          {
699            pixels=(const unsigned char *) ReadBlobStream(image,length,
700              GetQuantumPixels(quantum_info),&count);
701            if (count != (ssize_t) length)
702              {
703                ThrowFileException(exception,CorruptImageError,
704                  "UnexpectedEndOfFile",image->filename);
705                break;
706              }
707          }
708        pixels=(const unsigned char *) ReadBlobStream(image,length,
709          GetQuantumPixels(quantum_info),&count);
710        for (y=0; y < (ssize_t) image->extract_info.height; y++)
711        {
712          register const Quantum
713            *magick_restrict p;
714
715          register Quantum
716            *magick_restrict q;
717
718          register ssize_t
719            x;
720
721          if (count != (ssize_t) length)
722            {
723              ThrowFileException(exception,CorruptImageError,
724                "UnexpectedEndOfFile",image->filename);
725              break;
726            }
727          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
728            exception);
729          if (q == (Quantum *) NULL)
730            break;
731          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
732            quantum_info,CyanQuantum,pixels,exception);
733          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
734            break;
735          if (((y-image->extract_info.y) >= 0) &&
736              ((y-image->extract_info.y) < (ssize_t) image->rows))
737            {
738              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
739                canvas_image->columns,1,exception);
740              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
741                image->columns,1,exception);
742              if ((p == (const Quantum *) NULL) ||
743                  (q == (Quantum *) NULL))
744                break;
745              for (x=0; x < (ssize_t) image->columns; x++)
746              {
747                SetPixelRed(image,GetPixelRed(canvas_image,p),q);
748                p+=GetPixelChannels(canvas_image);
749                q+=GetPixelChannels(image);
750              }
751              if (SyncAuthenticPixels(image,exception) == MagickFalse)
752                break;
753            }
754          pixels=(const unsigned char *) ReadBlobStream(image,length,
755            GetQuantumPixels(quantum_info),&count);
756        }
757        if (image->previous == (Image *) NULL)
758          {
759            status=SetImageProgress(image,LoadImageTag,1,5);
760            if (status == MagickFalse)
761              break;
762          }
763        (void) CloseBlob(image);
764        AppendImageFormat("M",image->filename);
765        status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
766        if (status == MagickFalse)
767          {
768            canvas_image=DestroyImageList(canvas_image);
769            image=DestroyImageList(image);
770            return((Image *) NULL);
771          }
772        length=GetQuantumExtent(canvas_image,quantum_info,MagentaQuantum);
773        for (i=0; i < (ssize_t) scene; i++)
774          for (y=0; y < (ssize_t) image->extract_info.height; y++)
775          {
776            pixels=(const unsigned char *) ReadBlobStream(image,length,
777              GetQuantumPixels(quantum_info),&count);
778            if (count != (ssize_t) length)
779              {
780                ThrowFileException(exception,CorruptImageError,
781                  "UnexpectedEndOfFile",image->filename);
782                break;
783              }
784          }
785        pixels=(const unsigned char *) ReadBlobStream(image,length,
786          GetQuantumPixels(quantum_info),&count);
787        for (y=0; y < (ssize_t) image->extract_info.height; y++)
788        {
789          register const Quantum
790            *magick_restrict p;
791
792          register Quantum
793            *magick_restrict q;
794
795          register ssize_t
796            x;
797
798          if (count != (ssize_t) length)
799            {
800              ThrowFileException(exception,CorruptImageError,
801                "UnexpectedEndOfFile",image->filename);
802              break;
803            }
804          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
805            exception);
806          if (q == (Quantum *) NULL)
807            break;
808          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
809            quantum_info,MagentaQuantum,pixels,exception);
810          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
811            break;
812          if (((y-image->extract_info.y) >= 0) &&
813              ((y-image->extract_info.y) < (ssize_t) image->rows))
814            {
815              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
816                canvas_image->columns,1,exception);
817              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
818                image->columns,1,exception);
819              if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
820                break;
821              for (x=0; x < (ssize_t) image->columns; x++)
822              {
823                SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
824                p+=GetPixelChannels(canvas_image);
825                q+=GetPixelChannels(image);
826              }
827              if (SyncAuthenticPixels(image,exception) == MagickFalse)
828                break;
829           }
830          pixels=(const unsigned char *) ReadBlobStream(image,length,
831            GetQuantumPixels(quantum_info),&count);
832        }
833        if (image->previous == (Image *) NULL)
834          {
835            status=SetImageProgress(image,LoadImageTag,2,5);
836            if (status == MagickFalse)
837              break;
838          }
839        (void) CloseBlob(image);
840        AppendImageFormat("Y",image->filename);
841        status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
842        if (status == MagickFalse)
843          {
844            canvas_image=DestroyImageList(canvas_image);
845            image=DestroyImageList(image);
846            return((Image *) NULL);
847          }
848        length=GetQuantumExtent(canvas_image,quantum_info,YellowQuantum);
849        for (i=0; i < (ssize_t) scene; i++)
850          for (y=0; y < (ssize_t) image->extract_info.height; y++)
851          {
852            pixels=(const unsigned char *) ReadBlobStream(image,length,
853              GetQuantumPixels(quantum_info),&count);
854            if (count != (ssize_t) length)
855              {
856                ThrowFileException(exception,CorruptImageError,
857                  "UnexpectedEndOfFile",image->filename);
858                break;
859              }
860          }
861        pixels=(const unsigned char *) ReadBlobStream(image,length,
862          GetQuantumPixels(quantum_info),&count);
863        for (y=0; y < (ssize_t) image->extract_info.height; y++)
864        {
865          register const Quantum
866            *magick_restrict p;
867
868          register Quantum
869            *magick_restrict q;
870
871          register ssize_t
872            x;
873
874          if (count != (ssize_t) length)
875            {
876              ThrowFileException(exception,CorruptImageError,
877                "UnexpectedEndOfFile",image->filename);
878              break;
879            }
880          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
881            exception);
882          if (q == (Quantum *) NULL)
883            break;
884          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
885            quantum_info,YellowQuantum,pixels,exception);
886          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
887            break;
888          if (((y-image->extract_info.y) >= 0) &&
889              ((y-image->extract_info.y) < (ssize_t) image->rows))
890            {
891              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
892                canvas_image->columns,1,exception);
893              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
894                image->columns,1,exception);
895              if ((p == (const Quantum *) NULL) ||
896                  (q == (Quantum *) NULL))
897                break;
898              for (x=0; x < (ssize_t) image->columns; x++)
899              {
900                SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
901                p+=GetPixelChannels(canvas_image);
902                q+=GetPixelChannels(image);
903              }
904              if (SyncAuthenticPixels(image,exception) == MagickFalse)
905                break;
906           }
907          pixels=(const unsigned char *) ReadBlobStream(image,length,
908            GetQuantumPixels(quantum_info),&count);
909        }
910        if (image->previous == (Image *) NULL)
911          {
912            status=SetImageProgress(image,LoadImageTag,3,5);
913            if (status == MagickFalse)
914              break;
915          }
916        (void) CloseBlob(image);
917        AppendImageFormat("K",image->filename);
918        status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
919        if (status == MagickFalse)
920          {
921            canvas_image=DestroyImageList(canvas_image);
922            image=DestroyImageList(image);
923            return((Image *) NULL);
924          }
925        length=GetQuantumExtent(canvas_image,quantum_info,BlackQuantum);
926        for (i=0; i < (ssize_t) scene; i++)
927          for (y=0; y < (ssize_t) image->extract_info.height; y++)
928          {
929            pixels=(const unsigned char *) ReadBlobStream(image,length,
930              GetQuantumPixels(quantum_info),&count);
931            if (count != (ssize_t) length)
932              {
933                ThrowFileException(exception,CorruptImageError,
934                  "UnexpectedEndOfFile",image->filename);
935                break;
936              }
937          }
938        pixels=(const unsigned char *) ReadBlobStream(image,length,
939          GetQuantumPixels(quantum_info),&count);
940        for (y=0; y < (ssize_t) image->extract_info.height; y++)
941        {
942          register const Quantum
943            *magick_restrict p;
944
945          register Quantum
946            *magick_restrict q;
947
948          register ssize_t
949            x;
950
951          if (count != (ssize_t) length)
952            {
953              ThrowFileException(exception,CorruptImageError,
954                "UnexpectedEndOfFile",image->filename);
955              break;
956            }
957          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
958            exception);
959          if (q == (Quantum *) NULL)
960            break;
961          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
962            quantum_info,BlackQuantum,pixels,exception);
963          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
964            break;
965          if (((y-image->extract_info.y) >= 0) &&
966              ((y-image->extract_info.y) < (ssize_t) image->rows))
967            {
968              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
969                canvas_image->columns,1,exception);
970              q=GetAuthenticPixels(image,0,y-image->extract_info.y,
971                image->columns,1,exception);
972              if ((p == (const Quantum *) NULL) ||
973                  (q == (Quantum *) NULL))
974                break;
975              for (x=0; x < (ssize_t) image->columns; x++)
976              {
977                SetPixelBlack(image,GetPixelBlack(canvas_image,p),q);
978                p+=GetPixelChannels(canvas_image);
979                q+=GetPixelChannels(image);
980              }
981              if (SyncAuthenticPixels(image,exception) == MagickFalse)
982                break;
983           }
984          pixels=(const unsigned char *) ReadBlobStream(image,length,
985            GetQuantumPixels(quantum_info),&count);
986        }
987        if (image->previous == (Image *) NULL)
988          {
989            status=SetImageProgress(image,LoadImageTag,3,5);
990            if (status == MagickFalse)
991              break;
992          }
993        if (image->alpha_trait != UndefinedPixelTrait)
994          {
995            (void) CloseBlob(image);
996            AppendImageFormat("A",image->filename);
997            status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
998            if (status == MagickFalse)
999              {
1000                canvas_image=DestroyImageList(canvas_image);
1001                image=DestroyImageList(image);
1002                return((Image *) NULL);
1003              }
1004            length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum);
1005            for (i=0; i < (ssize_t) scene; i++)
1006              for (y=0; y < (ssize_t) image->extract_info.height; y++)
1007              {
1008                pixels=(const unsigned char *) ReadBlobStream(image,length,
1009                  GetQuantumPixels(quantum_info),&count);
1010                if (count != (ssize_t) length)
1011                  {
1012                    ThrowFileException(exception,CorruptImageError,
1013                      "UnexpectedEndOfFile",image->filename);
1014                    break;
1015                  }
1016              }
1017            pixels=(const unsigned char *) ReadBlobStream(image,length,
1018              GetQuantumPixels(quantum_info),
1019              &count);
1020            for (y=0; y < (ssize_t) image->extract_info.height; y++)
1021            {
1022              register const Quantum
1023                *magick_restrict p;
1024
1025              register Quantum
1026                *magick_restrict q;
1027
1028              register ssize_t
1029                x;
1030
1031              if (count != (ssize_t) length)
1032                {
1033                  ThrowFileException(exception,CorruptImageError,
1034                    "UnexpectedEndOfFile",image->filename);
1035                  break;
1036                }
1037              q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
1038                exception);
1039              if (q == (Quantum *) NULL)
1040                break;
1041              length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
1042                quantum_info,YellowQuantum,pixels,exception);
1043              if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
1044                break;
1045              if (((y-image->extract_info.y) >= 0) &&
1046                  ((y-image->extract_info.y) < (ssize_t) image->rows))
1047                {
1048                  p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
1049                    0,canvas_image->columns,1,exception);
1050                  q=GetAuthenticPixels(image,0,y-image->extract_info.y,
1051                    image->columns,1,exception);
1052                  if ((p == (const Quantum *) NULL) ||
1053                      (q == (Quantum *) NULL))
1054                    break;
1055                  for (x=0; x < (ssize_t) image->columns; x++)
1056                  {
1057                    SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
1058                    p+=GetPixelChannels(canvas_image);
1059                    q+=GetPixelChannels(image);
1060                  }
1061                  if (SyncAuthenticPixels(image,exception) == MagickFalse)
1062                    break;
1063               }
1064              pixels=(const unsigned char *) ReadBlobStream(image,length,
1065                GetQuantumPixels(quantum_info),&count);
1066            }
1067            if (image->previous == (Image *) NULL)
1068              {
1069                status=SetImageProgress(image,LoadImageTag,4,5);
1070                if (status == MagickFalse)
1071                  break;
1072              }
1073          }
1074        if (image->previous == (Image *) NULL)
1075          {
1076            status=SetImageProgress(image,LoadImageTag,5,5);
1077            if (status == MagickFalse)
1078              break;
1079          }
1080        break;
1081      }
1082    }
1083    SetQuantumImageType(image,quantum_type);
1084    /*
1085      Proceed to next image.
1086    */
1087    if (image_info->number_scenes != 0)
1088      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1089        break;
1090    if (count == (ssize_t) length)
1091      {
1092        /*
1093          Allocate next image structure.
1094        */
1095        AcquireNextImage(image_info,image,exception);
1096        if (GetNextImageInList(image) == (Image *) NULL)
1097          {
1098            image=DestroyImageList(image);
1099            return((Image *) NULL);
1100          }
1101        image=SyncNextImageInList(image);
1102        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1103          GetBlobSize(image));
1104        if (status == MagickFalse)
1105          break;
1106      }
1107    scene++;
1108  } while (count == (ssize_t) length);
1109  quantum_info=DestroyQuantumInfo(quantum_info);
1110  canvas_image=DestroyImage(canvas_image);
1111  (void) CloseBlob(image);
1112  return(GetFirstImageInList(image));
1113}
1114
1115/*
1116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117%                                                                             %
1118%                                                                             %
1119%                                                                             %
1120%   R e g i s t e r C M Y K I m a g e                                         %
1121%                                                                             %
1122%                                                                             %
1123%                                                                             %
1124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125%
1126%  RegisterCMYKImage() adds attributes for the CMYK image format to
1127%  the list of supported formats.  The attributes include the image format
1128%  tag, a method to read and/or write the format, whether the format
1129%  supports the saving of more than one frame to the same file or blob,
1130%  whether the format supports native in-memory I/O, and a brief
1131%  description of the format.
1132%
1133%  The format of the RegisterCMYKImage method is:
1134%
1135%      size_t RegisterCMYKImage(void)
1136%
1137*/
1138ModuleExport size_t RegisterCMYKImage(void)
1139{
1140  MagickInfo
1141    *entry;
1142
1143  entry=AcquireMagickInfo("CMYK","CMYK",
1144    "Raw cyan, magenta, yellow, and black samples");
1145  entry->decoder=(DecodeImageHandler *) ReadCMYKImage;
1146  entry->encoder=(EncodeImageHandler *) WriteCMYKImage;
1147  entry->flags|=CoderRawSupportFlag;
1148  entry->flags|=CoderEndianSupportFlag;
1149  (void) RegisterMagickInfo(entry);
1150  entry=AcquireMagickInfo("CMYK","CMYKA",
1151    "Raw cyan, magenta, yellow, black, and alpha samples");
1152  entry->decoder=(DecodeImageHandler *) ReadCMYKImage;
1153  entry->encoder=(EncodeImageHandler *) WriteCMYKImage;
1154  entry->flags|=CoderRawSupportFlag;
1155  entry->flags|=CoderEndianSupportFlag;
1156  (void) RegisterMagickInfo(entry);
1157  return(MagickImageCoderSignature);
1158}
1159
1160/*
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%                                                                             %
1163%                                                                             %
1164%                                                                             %
1165%   U n r e g i s t e r C M Y K I m a g e                                     %
1166%                                                                             %
1167%                                                                             %
1168%                                                                             %
1169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170%
1171%  UnregisterCMYKImage() removes format registrations made by the
1172%  CMYK module from the list of supported formats.
1173%
1174%  The format of the UnregisterCMYKImage method is:
1175%
1176%      UnregisterCMYKImage(void)
1177%
1178*/
1179ModuleExport void UnregisterCMYKImage(void)
1180{
1181  (void) UnregisterMagickInfo("CMYK");
1182  (void) UnregisterMagickInfo("CMYKA");
1183}
1184
1185/*
1186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187%                                                                             %
1188%                                                                             %
1189%                                                                             %
1190%   W r i t e C M Y K I m a g e                                               %
1191%                                                                             %
1192%                                                                             %
1193%                                                                             %
1194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195%
1196%  WriteCMYKImage() writes an image to a file in cyan, magenta, yellow, and
1197%  black,rasterfile format.
1198%
1199%  The format of the WriteCMYKImage method is:
1200%
1201%      MagickBooleanType WriteCMYKImage(const ImageInfo *image_info,
1202%        Image *image,ExceptionInfo *exception)
1203%
1204%  A description of each parameter follows.
1205%
1206%    o image_info: the image info.
1207%
1208%    o image:  The image.
1209%
1210%    o exception: return any errors or warnings in this structure.
1211%
1212*/
1213static MagickBooleanType WriteCMYKImage(const ImageInfo *image_info,
1214  Image *image,ExceptionInfo *exception)
1215{
1216  MagickBooleanType
1217    status;
1218
1219  MagickOffsetType
1220    scene;
1221
1222  QuantumInfo
1223    *quantum_info;
1224
1225  QuantumType
1226    quantum_type;
1227
1228  size_t
1229    length;
1230
1231  ssize_t
1232    count,
1233    y;
1234
1235  unsigned char
1236    *pixels;
1237
1238  /*
1239    Allocate memory for pixels.
1240  */
1241  assert(image_info != (const ImageInfo *) NULL);
1242  assert(image_info->signature == MagickCoreSignature);
1243  assert(image != (Image *) NULL);
1244  assert(image->signature == MagickCoreSignature);
1245  if (image->debug != MagickFalse)
1246    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1247  if (image_info->interlace != PartitionInterlace)
1248    {
1249      /*
1250        Open output image file.
1251      */
1252      status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1253      if (status == MagickFalse)
1254        return(status);
1255    }
1256  scene=0;
1257  do
1258  {
1259    /*
1260      Convert MIFF to CMYK raster pixels.
1261    */
1262    if (image->colorspace != CMYKColorspace)
1263      (void) TransformImageColorspace(image,CMYKColorspace,exception);
1264    quantum_type=CMYKQuantum;
1265    if (LocaleCompare(image_info->magick,"CMYKA") == 0)
1266      {
1267        quantum_type=CMYKAQuantum;
1268        if (image->alpha_trait == UndefinedPixelTrait)
1269          (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1270      }
1271    quantum_info=AcquireQuantumInfo(image_info,image);
1272    if (quantum_info == (QuantumInfo *) NULL)
1273      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1274    pixels=(unsigned char *) GetQuantumPixels(quantum_info);
1275    switch (image_info->interlace)
1276    {
1277      case NoInterlace:
1278      default:
1279      {
1280        /*
1281          No interlacing:  CMYKCMYKCMYKCMYKCMYKCMYK...
1282        */
1283        for (y=0; y < (ssize_t) image->rows; y++)
1284        {
1285          register const Quantum
1286            *magick_restrict p;
1287
1288          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1289          if (p == (const Quantum *) NULL)
1290            break;
1291          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1292            quantum_type,pixels,exception);
1293          count=WriteBlob(image,length,pixels);
1294          if (count != (ssize_t) length)
1295            break;
1296          if (image->previous == (Image *) NULL)
1297            {
1298              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1299                image->rows);
1300              if (status == MagickFalse)
1301                break;
1302            }
1303        }
1304        break;
1305      }
1306      case LineInterlace:
1307      {
1308        /*
1309          Line interlacing:  CCC...MMM...YYY...KKK...CCC...MMM...YYY...KKK...
1310        */
1311        for (y=0; y < (ssize_t) image->rows; y++)
1312        {
1313          register const Quantum
1314            *magick_restrict p;
1315
1316          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1317          if (p == (const Quantum *) NULL)
1318            break;
1319          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1320            CyanQuantum,pixels,exception);
1321          count=WriteBlob(image,length,pixels);
1322          if (count != (ssize_t) length)
1323            break;
1324          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1325            MagentaQuantum,pixels,exception);
1326          count=WriteBlob(image,length,pixels);
1327          if (count != (ssize_t) length)
1328            break;
1329          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1330            YellowQuantum,pixels,exception);
1331          count=WriteBlob(image,length,pixels);
1332          if (count != (ssize_t) length)
1333            break;
1334          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1335            BlackQuantum,pixels,exception);
1336          count=WriteBlob(image,length,pixels);
1337          if (count != (ssize_t) length)
1338            break;
1339          if (quantum_type == CMYKAQuantum)
1340            {
1341              length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1342                AlphaQuantum,pixels,exception);
1343              count=WriteBlob(image,length,pixels);
1344              if (count != (ssize_t) length)
1345                break;
1346            }
1347          if (image->previous == (Image *) NULL)
1348            {
1349              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1350                image->rows);
1351              if (status == MagickFalse)
1352                break;
1353            }
1354        }
1355        break;
1356      }
1357      case PlaneInterlace:
1358      {
1359        /*
1360          Plane interlacing:  CCCCCC...MMMMMM...YYYYYY...KKKKKK...
1361        */
1362        for (y=0; y < (ssize_t) image->rows; y++)
1363        {
1364          register const Quantum
1365            *magick_restrict p;
1366
1367          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1368          if (p == (const Quantum *) NULL)
1369            break;
1370          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1371            CyanQuantum,pixels,exception);
1372          count=WriteBlob(image,length,pixels);
1373          if (count != (ssize_t) length)
1374            break;
1375        }
1376        if (image->previous == (Image *) NULL)
1377          {
1378            status=SetImageProgress(image,SaveImageTag,1,6);
1379            if (status == MagickFalse)
1380              break;
1381          }
1382        for (y=0; y < (ssize_t) image->rows; y++)
1383        {
1384          register const Quantum
1385            *magick_restrict p;
1386
1387          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1388          if (p == (const Quantum *) NULL)
1389            break;
1390          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1391            MagentaQuantum,pixels,exception);
1392          count=WriteBlob(image,length,pixels);
1393          if (count != (ssize_t) length)
1394            break;
1395        }
1396        if (image->previous == (Image *) NULL)
1397          {
1398            status=SetImageProgress(image,SaveImageTag,2,6);
1399            if (status == MagickFalse)
1400              break;
1401          }
1402        for (y=0; y < (ssize_t) image->rows; y++)
1403        {
1404          register const Quantum
1405            *magick_restrict p;
1406
1407          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1408          if (p == (const Quantum *) NULL)
1409            break;
1410          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1411            YellowQuantum,pixels,exception);
1412          count=WriteBlob(image,length,pixels);
1413          if (count != (ssize_t) length)
1414            break;
1415        }
1416        if (image->previous == (Image *) NULL)
1417          {
1418            status=SetImageProgress(image,SaveImageTag,3,6);
1419            if (status == MagickFalse)
1420              break;
1421          }
1422        for (y=0; y < (ssize_t) image->rows; y++)
1423        {
1424          register const Quantum
1425            *magick_restrict p;
1426
1427          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1428          if (p == (const Quantum *) NULL)
1429            break;
1430          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1431            BlackQuantum,pixels,exception);
1432          count=WriteBlob(image,length,pixels);
1433          if (count != (ssize_t) length)
1434            break;
1435        }
1436        if (image->previous == (Image *) NULL)
1437          {
1438            status=SetImageProgress(image,SaveImageTag,4,6);
1439            if (status == MagickFalse)
1440              break;
1441          }
1442        if (quantum_type == CMYKAQuantum)
1443          {
1444            for (y=0; y < (ssize_t) image->rows; y++)
1445            {
1446              register const Quantum
1447                *magick_restrict p;
1448
1449              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1450              if (p == (const Quantum *) NULL)
1451                break;
1452              length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1453                AlphaQuantum,pixels,exception);
1454              count=WriteBlob(image,length,pixels);
1455              if (count != (ssize_t) length)
1456              break;
1457            }
1458            if (image->previous == (Image *) NULL)
1459              {
1460                status=SetImageProgress(image,SaveImageTag,5,6);
1461                if (status == MagickFalse)
1462                  break;
1463              }
1464          }
1465        if (image_info->interlace == PartitionInterlace)
1466          (void) CopyMagickString(image->filename,image_info->filename,
1467            MagickPathExtent);
1468        if (image->previous == (Image *) NULL)
1469          {
1470            status=SetImageProgress(image,SaveImageTag,6,6);
1471            if (status == MagickFalse)
1472              break;
1473          }
1474        break;
1475      }
1476      case PartitionInterlace:
1477      {
1478        /*
1479          Partition interlacing:  CCCCCC..., MMMMMM..., YYYYYY..., KKKKKK...
1480        */
1481        AppendImageFormat("C",image->filename);
1482        status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1483          AppendBinaryBlobMode,exception);
1484        if (status == MagickFalse)
1485          return(status);
1486        for (y=0; y < (ssize_t) image->rows; y++)
1487        {
1488          register const Quantum
1489            *magick_restrict p;
1490
1491          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1492          if (p == (const Quantum *) NULL)
1493            break;
1494          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1495            CyanQuantum,pixels,exception);
1496          count=WriteBlob(image,length,pixels);
1497          if (count != (ssize_t) length)
1498            break;
1499        }
1500        if (image->previous == (Image *) NULL)
1501          {
1502            status=SetImageProgress(image,SaveImageTag,1,6);
1503            if (status == MagickFalse)
1504              break;
1505          }
1506        (void) CloseBlob(image);
1507        AppendImageFormat("M",image->filename);
1508        status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1509          AppendBinaryBlobMode,exception);
1510        if (status == MagickFalse)
1511          return(status);
1512        for (y=0; y < (ssize_t) image->rows; y++)
1513        {
1514          register const Quantum
1515            *magick_restrict p;
1516
1517          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1518          if (p == (const Quantum *) NULL)
1519            break;
1520          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1521            MagentaQuantum,pixels,exception);
1522          count=WriteBlob(image,length,pixels);
1523          if (count != (ssize_t) length)
1524            break;
1525        }
1526        if (image->previous == (Image *) NULL)
1527          {
1528            status=SetImageProgress(image,SaveImageTag,2,6);
1529            if (status == MagickFalse)
1530              break;
1531          }
1532        (void) CloseBlob(image);
1533        AppendImageFormat("Y",image->filename);
1534        status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1535          AppendBinaryBlobMode,exception);
1536        if (status == MagickFalse)
1537          return(status);
1538        for (y=0; y < (ssize_t) image->rows; y++)
1539        {
1540          register const Quantum
1541            *magick_restrict p;
1542
1543          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1544          if (p == (const Quantum *) NULL)
1545            break;
1546          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1547            YellowQuantum,pixels,exception);
1548          count=WriteBlob(image,length,pixels);
1549          if (count != (ssize_t) length)
1550            break;
1551        }
1552        if (image->previous == (Image *) NULL)
1553          {
1554            status=SetImageProgress(image,SaveImageTag,3,6);
1555            if (status == MagickFalse)
1556              break;
1557          }
1558        (void) CloseBlob(image);
1559        AppendImageFormat("K",image->filename);
1560        status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1561          AppendBinaryBlobMode,exception);
1562        if (status == MagickFalse)
1563          return(status);
1564        for (y=0; y < (ssize_t) image->rows; y++)
1565        {
1566          register const Quantum
1567            *magick_restrict p;
1568
1569          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1570          if (p == (const Quantum *) NULL)
1571            break;
1572          length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1573            BlackQuantum,pixels,exception);
1574          count=WriteBlob(image,length,pixels);
1575          if (count != (ssize_t) length)
1576            break;
1577        }
1578        if (image->previous == (Image *) NULL)
1579          {
1580            status=SetImageProgress(image,SaveImageTag,4,6);
1581            if (status == MagickFalse)
1582              break;
1583          }
1584        if (quantum_type == CMYKAQuantum)
1585          {
1586            (void) CloseBlob(image);
1587            AppendImageFormat("A",image->filename);
1588            status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1589              AppendBinaryBlobMode,exception);
1590            if (status == MagickFalse)
1591              return(status);
1592            for (y=0; y < (ssize_t) image->rows; y++)
1593            {
1594              register const Quantum
1595                *magick_restrict p;
1596
1597              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1598              if (p == (const Quantum *) NULL)
1599                break;
1600              length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1601                AlphaQuantum,pixels,exception);
1602              count=WriteBlob(image,length,pixels);
1603              if (count != (ssize_t) length)
1604                break;
1605            }
1606            if (image->previous == (Image *) NULL)
1607              {
1608                status=SetImageProgress(image,SaveImageTag,5,6);
1609                if (status == MagickFalse)
1610                  break;
1611              }
1612          }
1613        (void) CloseBlob(image);
1614        (void) CopyMagickString(image->filename,image_info->filename,
1615          MagickPathExtent);
1616        if (image->previous == (Image *) NULL)
1617          {
1618            status=SetImageProgress(image,SaveImageTag,6,6);
1619            if (status == MagickFalse)
1620              break;
1621          }
1622        break;
1623      }
1624    }
1625    quantum_info=DestroyQuantumInfo(quantum_info);
1626    if (GetNextImageInList(image) == (Image *) NULL)
1627      break;
1628    image=SyncNextImageInList(image);
1629    status=SetImageProgress(image,SaveImagesTag,scene++,
1630      GetImageListLength(image));
1631    if (status == MagickFalse)
1632      break;
1633  } while (image_info->adjoin != MagickFalse);
1634  (void) CloseBlob(image);
1635  return(MagickTrue);
1636}
1637