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