]> granicus.if.org Git - imagemagick/blob - coders/ycbcr.c
(no commit message)
[imagemagick] / coders / ycbcr.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                     Y   Y   YYYC  BBBB    YYYC  RRRR                        %
7 %                      Y Y   C      B   B  C      R   R                       %
8 %                       Y    C      BBBB   C      RRRR                        %
9 %                       Y    C      B   B  C      R  R                        %
10 %                       Y     YYYC  BBBB    YYYC  R   R                       %
11 %                                                                             %
12 %                                                                             %
13 %                     Read/Write Raw YCbCr Image Format                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 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 \f
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/colorspace.h"
47 #include "MagickCore/constitute.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/magick.h"
54 #include "MagickCore/memory_.h"
55 #include "MagickCore/monitor.h"
56 #include "MagickCore/monitor-private.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/quantum-private.h"
59 #include "MagickCore/static.h"
60 #include "MagickCore/statistic.h"
61 #include "MagickCore/string_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/utility.h"
64 \f
65 /*
66   Forward declarations.
67 */
68 static MagickBooleanType
69   WriteYCBCRImage(const ImageInfo *,Image *,ExceptionInfo *);
70 \f
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 %                                                                             %
74 %                                                                             %
75 %                                                                             %
76 %   R e a d Y C b C r I m a g e                                               %
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 %  ReadYCBCRImage() reads an image of raw YCbCr or YCbCrA samples and returns
83 %  it. It allocates the memory necessary for the new Image structure and
84 %  returns a pointer to the new image.
85 %
86 %  The format of the ReadYCBCRImage method is:
87 %
88 %      Image *ReadYCBCRImage(const ImageInfo *image_info,
89 %        ExceptionInfo *exception)
90 %
91 %  A description of each parameter follows:
92 %
93 %    o image_info: the image info.
94 %
95 %    o exception: return any errors or warnings in this structure.
96 %
97 */
98 static Image *ReadYCBCRImage(const ImageInfo *image_info,
99   ExceptionInfo *exception)
100 {
101   Image
102     *canvas_image,
103     *image;
104
105   MagickBooleanType
106     status;
107
108   MagickOffsetType
109     scene;
110
111   QuantumInfo
112     *quantum_info;
113
114   QuantumType
115     quantum_type;
116
117   register const Quantum
118     *p;
119
120   register ssize_t
121     i,
122     x;
123
124   register Quantum
125     *q;
126
127   size_t
128     length;
129
130   ssize_t
131     count,
132     y;
133
134   unsigned char
135     *pixels;
136
137   /*
138     Open image file.
139   */
140   assert(image_info != (const ImageInfo *) NULL);
141   assert(image_info->signature == MagickSignature);
142   if (image_info->debug != MagickFalse)
143     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
144       image_info->filename);
145   assert(exception != (ExceptionInfo *) NULL);
146   assert(exception->signature == MagickSignature);
147   image=AcquireImage(image_info,exception);
148   if ((image->columns == 0) || (image->rows == 0))
149     ThrowReaderException(OptionError,"MustSpecifyImageSize");
150   SetImageColorspace(image,YCbCrColorspace,exception);
151   if (image_info->interlace != PartitionInterlace)
152     {
153       status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
154       if (status == MagickFalse)
155         {
156           image=DestroyImageList(image);
157           return((Image *) NULL);
158         }
159       if (DiscardBlobBytes(image,image->offset) == MagickFalse)
160         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
161           image->filename);
162     }
163   /*
164     Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]).
165   */
166   canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
167     exception);
168   (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
169     exception);
170   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
171   if (quantum_info == (QuantumInfo *) NULL)
172     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
173   pixels=GetQuantumPixels(quantum_info);
174   quantum_type=RGBQuantum;
175   if (LocaleCompare(image_info->magick,"YCbCrA") == 0)
176     {
177       quantum_type=RGBAQuantum;
178       image->matte=MagickTrue;
179     }
180   if (image_info->number_scenes != 0)
181     while (image->scene < image_info->scene)
182     {
183       /*
184         Skip to next image.
185       */
186       image->scene++;
187       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
188       for (y=0; y < (ssize_t) image->rows; y++)
189       {
190         count=ReadBlob(image,length,pixels);
191         if (count != (ssize_t) length)
192           break;
193       }
194     }
195   count=0;
196   length=0;
197   scene=0;
198   do
199   {
200     /*
201       Read pixels to virtual canvas image then push to image.
202     */
203     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
204       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
205         break;
206     SetImageColorspace(image,YCbCrColorspace,exception);
207     switch (image_info->interlace)
208     {
209       case NoInterlace:
210       default:
211       {
212         /*
213           No interlacing:  YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr...
214         */
215         if (scene == 0)
216           {
217             length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
218             count=ReadBlob(image,length,pixels);
219           }
220         for (y=0; y < (ssize_t) image->extract_info.height; y++)
221         {
222           if (count != (ssize_t) length)
223             {
224               ThrowFileException(exception,CorruptImageError,
225                 "UnexpectedEndOfFile",image->filename);
226               break;
227             }
228           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
229             exception);
230           if (q == (Quantum *) NULL)
231             break;
232           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
233             quantum_info,quantum_type,pixels,exception);
234           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
235             break;
236           if (((y-image->extract_info.y) >= 0) && 
237               ((y-image->extract_info.y) < (ssize_t) image->rows))
238             {
239               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
240                 canvas_image->columns,1,exception);
241               q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
242                 image->columns,1,exception);
243               if ((p == (const Quantum *) NULL) ||
244                   (q == (Quantum *) NULL))
245                 break;
246               for (x=0; x < (ssize_t) image->columns; x++)
247               {
248                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
249                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
250                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
251                 if (image->matte != MagickFalse)
252                   SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
253                 p+=GetPixelChannels(canvas_image);
254                 q+=GetPixelChannels(image);
255               }
256               if (SyncAuthenticPixels(image,exception) == MagickFalse)
257                 break;
258             }
259           if (image->previous == (Image *) NULL)
260             {
261               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
262                 image->rows);
263               if (status == MagickFalse)
264                 break;
265             }
266           count=ReadBlob(image,length,pixels);
267         }
268         break;
269       }
270       case LineInterlace:
271       {
272         static QuantumType
273           quantum_types[4] =
274           {
275             RedQuantum,
276             GreenQuantum,
277             BlueQuantum,
278             OpacityQuantum
279           };
280
281         /*
282           Line interlacing:  YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr...
283         */
284         if (scene == 0)
285           {
286             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
287             count=ReadBlob(image,length,pixels);
288           }
289         for (y=0; y < (ssize_t) image->extract_info.height; y++)
290         {
291           for (i=0; i < (image->matte != MagickFalse ? 4 : 3); i++)
292           {
293             if (count != (ssize_t) length)
294               {
295                 ThrowFileException(exception,CorruptImageError,
296                   "UnexpectedEndOfFile",image->filename);
297                 break;
298               }
299             quantum_type=quantum_types[i];
300             q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
301               exception);
302             if (q == (Quantum *) NULL)
303               break;
304             length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
305               quantum_info,quantum_type,pixels,exception);
306             if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
307               break;
308             if (((y-image->extract_info.y) >= 0) && 
309                 ((y-image->extract_info.y) < (ssize_t) image->rows))
310               {
311                 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
312                   0,canvas_image->columns,1,exception);
313                 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
314                   image->columns,1,exception);
315                 if ((p == (const Quantum *) NULL) ||
316                     (q == (Quantum *) NULL))
317                   break;
318                 for (x=0; x < (ssize_t) image->columns; x++)
319                 {
320                   switch (quantum_type)
321                   {
322                     case RedQuantum:
323                     {
324                       SetPixelRed(image,GetPixelRed(canvas_image,p),q);
325                       break;
326                     }
327                     case GreenQuantum:
328                     {
329                       SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
330                       break;
331                     }
332                     case BlueQuantum:
333                     {
334                       SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
335                       break;
336                     }
337                     case OpacityQuantum:
338                     {
339                       SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
340                       break;
341                     }
342                     default:
343                       break;
344                   }
345                   p+=GetPixelChannels(canvas_image);
346                   q+=GetPixelChannels(image);
347                 }
348                 if (SyncAuthenticPixels(image,exception) == MagickFalse)
349                   break;
350               }
351             count=ReadBlob(image,length,pixels);
352           }
353           if (image->previous == (Image *) NULL)
354             {
355               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
356                 image->rows);
357               if (status == MagickFalse)
358                 break;
359             }
360         }
361         break;
362       }
363       case PlaneInterlace:
364       {
365         /*
366           Plane interlacing:  YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr...
367         */
368         if (scene == 0)
369           {
370             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
371             count=ReadBlob(image,length,pixels);
372           }
373         for (y=0; y < (ssize_t) image->extract_info.height; y++)
374         {
375           if (count != (ssize_t) length)
376             {
377               ThrowFileException(exception,CorruptImageError,
378                 "UnexpectedEndOfFile",image->filename);
379               break;
380             }
381           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
382             exception);
383           if (q == (Quantum *) NULL)
384             break;
385           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
386             quantum_info,RedQuantum,pixels,exception);
387           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
388             break;
389           if (((y-image->extract_info.y) >= 0) && 
390               ((y-image->extract_info.y) < (ssize_t) image->rows))
391             {
392               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
393                 canvas_image->columns,1,exception);
394               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
395                 image->columns,1,exception);
396               if ((p == (const Quantum *) NULL) ||
397                   (q == (Quantum *) NULL))
398                 break;
399               for (x=0; x < (ssize_t) image->columns; x++)
400               {
401                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
402                 p+=GetPixelChannels(canvas_image);
403                 q+=GetPixelChannels(image);
404               }
405               if (SyncAuthenticPixels(image,exception) == MagickFalse)
406                 break;
407             }
408           count=ReadBlob(image,length,pixels);
409         }
410         if (image->previous == (Image *) NULL)
411           {
412             status=SetImageProgress(image,LoadImageTag,1,5);
413             if (status == MagickFalse)
414               break;
415           }
416         for (y=0; y < (ssize_t) image->extract_info.height; y++)
417         {
418           if (count != (ssize_t) length)
419             {
420               ThrowFileException(exception,CorruptImageError,
421                 "UnexpectedEndOfFile",image->filename);
422               break;
423             }
424           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
425             exception);
426           if (q == (Quantum *) NULL)
427             break;
428           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
429             quantum_info,GreenQuantum,pixels,exception);
430           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
431             break;
432           if (((y-image->extract_info.y) >= 0) && 
433               ((y-image->extract_info.y) < (ssize_t) image->rows))
434             {
435               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
436                 canvas_image->columns,1,exception);
437               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
438                 image->columns,1,exception);
439               if ((p == (const Quantum *) NULL) ||
440                   (q == (Quantum *) NULL))
441                 break;
442               for (x=0; x < (ssize_t) image->columns; x++)
443               {
444                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
445                 p+=GetPixelChannels(canvas_image);
446                 q+=GetPixelChannels(image);
447               }
448               if (SyncAuthenticPixels(image,exception) == MagickFalse)
449                 break;
450            }
451           count=ReadBlob(image,length,pixels);
452         }
453         if (image->previous == (Image *) NULL)
454           {
455             status=SetImageProgress(image,LoadImageTag,2,5);
456             if (status == MagickFalse)
457               break;
458           }
459         for (y=0; y < (ssize_t) image->extract_info.height; y++)
460         {
461           if (count != (ssize_t) length)
462             {
463               ThrowFileException(exception,CorruptImageError,
464                 "UnexpectedEndOfFile",image->filename);
465               break;
466             }
467           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
468             exception);
469           if (q == (Quantum *) NULL)
470             break;
471           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
472             quantum_info,BlueQuantum,pixels,exception);
473           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
474             break;
475           if (((y-image->extract_info.y) >= 0) && 
476               ((y-image->extract_info.y) < (ssize_t) image->rows))
477             {
478               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
479                 canvas_image->columns,1,exception);
480               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
481                 image->columns,1,exception);
482               if ((p == (const Quantum *) NULL) ||
483                   (q == (Quantum *) NULL))
484                 break;
485               for (x=0; x < (ssize_t) image->columns; x++)
486               {
487                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
488                 p+=GetPixelChannels(canvas_image);
489                 q+=GetPixelChannels(image);
490               }
491               if (SyncAuthenticPixels(image,exception) == MagickFalse)
492                 break;
493             }
494           count=ReadBlob(image,length,pixels);
495         }
496         if (image->previous == (Image *) NULL)
497           {
498             status=SetImageProgress(image,LoadImageTag,3,5);
499             if (status == MagickFalse)
500               break;
501           }
502         if (image->matte != MagickFalse)
503           {
504             for (y=0; y < (ssize_t) image->extract_info.height; y++)
505             {
506               if (count != (ssize_t) length)
507                 {
508                   ThrowFileException(exception,CorruptImageError,
509                     "UnexpectedEndOfFile",image->filename);
510                   break;
511                 }
512               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
513                 exception);
514               if (q == (Quantum *) NULL)
515                 break;
516               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
517                 quantum_info,AlphaQuantum,pixels,exception);
518               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
519                 break;
520               if (((y-image->extract_info.y) >= 0) && 
521                   ((y-image->extract_info.y) < (ssize_t) image->rows))
522                 {
523                   p=GetVirtualPixels(canvas_image,
524                     canvas_image->extract_info.x,0,canvas_image->columns,1,
525                     exception);
526                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
527                     image->columns,1,exception);
528                   if ((p == (const Quantum *) NULL) ||
529                       (q == (Quantum *) NULL))
530                     break;
531                   for (x=0; x < (ssize_t) image->columns; x++)
532                   {
533                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
534                     p+=GetPixelChannels(canvas_image);
535                     q+=GetPixelChannels(image);
536                   }
537                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
538                     break;
539                 }
540               count=ReadBlob(image,length,pixels);
541             }
542             if (image->previous == (Image *) NULL)
543               {
544                 status=SetImageProgress(image,LoadImageTag,4,5);
545                 if (status == MagickFalse)
546                   break;
547               }
548           }
549         if (image->previous == (Image *) NULL)
550           {
551             status=SetImageProgress(image,LoadImageTag,5,5);
552             if (status == MagickFalse)
553               break;
554           }
555         break;
556       }
557       case PartitionInterlace:
558       {
559         /*
560           Partition interlacing:  YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr...
561         */
562         AppendImageFormat("Y",image->filename);
563         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
564         if (status == MagickFalse)
565           {
566             canvas_image=DestroyImageList(canvas_image);
567             image=DestroyImageList(image);
568             return((Image *) NULL);
569           }
570         if (DiscardBlobBytes(image,image->offset) == MagickFalse)
571           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
572             image->filename);
573         length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
574         for (i=0; i < (ssize_t) scene; i++)
575           for (y=0; y < (ssize_t) image->extract_info.height; y++)
576             if (ReadBlob(image,length,pixels) != (ssize_t) length)
577               {
578                 ThrowFileException(exception,CorruptImageError,
579                   "UnexpectedEndOfFile",image->filename);
580                 break;
581               }
582         count=ReadBlob(image,length,pixels);
583         for (y=0; y < (ssize_t) image->extract_info.height; y++)
584         {
585           if (count != (ssize_t) length)
586             {
587               ThrowFileException(exception,CorruptImageError,
588                 "UnexpectedEndOfFile",image->filename);
589               break;
590             }
591           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
592             exception);
593           if (q == (Quantum *) NULL)
594             break;
595           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
596             quantum_info,RedQuantum,pixels,exception);
597           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
598             break;
599           if (((y-image->extract_info.y) >= 0) && 
600               ((y-image->extract_info.y) < (ssize_t) image->rows))
601             {
602               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
603                 canvas_image->columns,1,exception);
604               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
605                 image->columns,1,exception);
606               if ((p == (const Quantum *) NULL) ||
607                   (q == (Quantum *) NULL))
608                 break;
609               for (x=0; x < (ssize_t) image->columns; x++)
610               {
611                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
612                 p+=GetPixelChannels(canvas_image);
613                 q+=GetPixelChannels(image);
614               }
615               if (SyncAuthenticPixels(image,exception) == MagickFalse)
616                 break;
617             }
618           count=ReadBlob(image,length,pixels);
619         }
620         if (image->previous == (Image *) NULL)
621           {
622             status=SetImageProgress(image,LoadImageTag,1,5);
623             if (status == MagickFalse)
624               break;
625           }
626         (void) CloseBlob(image);
627         AppendImageFormat("Cb",image->filename);
628         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
629         if (status == MagickFalse)
630           {
631             canvas_image=DestroyImageList(canvas_image);
632             image=DestroyImageList(image);
633             return((Image *) NULL);
634           }
635         length=GetQuantumExtent(canvas_image,quantum_info,GreenQuantum);
636         for (i=0; i < (ssize_t) scene; i++)
637           for (y=0; y < (ssize_t) image->extract_info.height; y++)
638             if (ReadBlob(image,length,pixels) != (ssize_t) length)
639               {
640                 ThrowFileException(exception,CorruptImageError,
641                   "UnexpectedEndOfFile",image->filename);
642                 break;
643               }
644         count=ReadBlob(image,length,pixels);
645         for (y=0; y < (ssize_t) image->extract_info.height; y++)
646         {
647           if (count != (ssize_t) length)
648             {
649               ThrowFileException(exception,CorruptImageError,
650                 "UnexpectedEndOfFile",image->filename);
651               break;
652             }
653           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
654             exception);
655           if (q == (Quantum *) NULL)
656             break;
657           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
658             quantum_info,GreenQuantum,pixels,exception);
659           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
660             break;
661           if (((y-image->extract_info.y) >= 0) && 
662               ((y-image->extract_info.y) < (ssize_t) image->rows))
663             {
664               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
665                 canvas_image->columns,1,exception);
666               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
667                 image->columns,1,exception);
668               if ((p == (const Quantum *) NULL) ||
669                   (q == (Quantum *) NULL))
670                 break;
671               for (x=0; x < (ssize_t) image->columns; x++)
672               {
673                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
674                 p+=GetPixelChannels(canvas_image);
675                 q+=GetPixelChannels(image);
676               }
677               if (SyncAuthenticPixels(image,exception) == MagickFalse)
678                 break;
679            }
680           count=ReadBlob(image,length,pixels);
681         }
682         if (image->previous == (Image *) NULL)
683           {
684             status=SetImageProgress(image,LoadImageTag,2,5);
685             if (status == MagickFalse)
686               break;
687           }
688         (void) CloseBlob(image);
689         AppendImageFormat("Cr",image->filename);
690         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
691         if (status == MagickFalse)
692           {
693             canvas_image=DestroyImageList(canvas_image);
694             image=DestroyImageList(image);
695             return((Image *) NULL);
696           }
697         length=GetQuantumExtent(canvas_image,quantum_info,BlueQuantum);
698         for (i=0; i < (ssize_t) scene; i++)
699           for (y=0; y < (ssize_t) image->extract_info.height; y++)
700             if (ReadBlob(image,length,pixels) != (ssize_t) length)
701               {
702                 ThrowFileException(exception,CorruptImageError,
703                   "UnexpectedEndOfFile",image->filename);
704                 break;
705               }
706         count=ReadBlob(image,length,pixels);
707         for (y=0; y < (ssize_t) image->extract_info.height; y++)
708         {
709           if (count != (ssize_t) length)
710             {
711               ThrowFileException(exception,CorruptImageError,
712                 "UnexpectedEndOfFile",image->filename);
713               break;
714             }
715           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
716             exception);
717           if (q == (Quantum *) NULL)
718             break;
719           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
720             quantum_info,BlueQuantum,pixels,exception);
721           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
722             break;
723           if (((y-image->extract_info.y) >= 0) && 
724               ((y-image->extract_info.y) < (ssize_t) image->rows))
725             {
726               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
727                 canvas_image->columns,1,exception);
728               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
729                 image->columns,1,exception);
730               if ((p == (const Quantum *) NULL) ||
731                   (q == (Quantum *) NULL))
732                 break;
733               for (x=0; x < (ssize_t) image->columns; x++)
734               {
735                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
736                 p+=GetPixelChannels(canvas_image);
737                 q+=GetPixelChannels(image);
738               }
739               if (SyncAuthenticPixels(image,exception) == MagickFalse)
740                 break;
741            }
742           count=ReadBlob(image,length,pixels);
743         }
744         if (image->previous == (Image *) NULL)
745           {
746             status=SetImageProgress(image,LoadImageTag,3,5);
747             if (status == MagickFalse)
748               break;
749           }
750         if (image->matte != MagickFalse)
751           {
752             (void) CloseBlob(image);
753             AppendImageFormat("A",image->filename);
754             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
755             if (status == MagickFalse)
756               {
757                 canvas_image=DestroyImageList(canvas_image);
758                 image=DestroyImageList(image);
759                 return((Image *) NULL);
760               }
761             length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum);
762             for (i=0; i < (ssize_t) scene; i++)
763               for (y=0; y < (ssize_t) image->extract_info.height; y++)
764                 if (ReadBlob(image,length,pixels) != (ssize_t) length)
765                   {
766                     ThrowFileException(exception,CorruptImageError,
767                       "UnexpectedEndOfFile",image->filename);
768                     break;
769                   }
770             count=ReadBlob(image,length,pixels);
771             for (y=0; y < (ssize_t) image->extract_info.height; y++)
772             {
773               if (count != (ssize_t) length)
774                 {
775                   ThrowFileException(exception,CorruptImageError,
776                     "UnexpectedEndOfFile",image->filename);
777                   break;
778                 }
779               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
780                 exception);
781               if (q == (Quantum *) NULL)
782                 break;
783               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
784                 quantum_info,BlueQuantum,pixels,exception);
785               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
786                 break;
787               if (((y-image->extract_info.y) >= 0) && 
788                   ((y-image->extract_info.y) < (ssize_t) image->rows))
789                 {
790                   p=GetVirtualPixels(canvas_image,
791                     canvas_image->extract_info.x,0,canvas_image->columns,1,
792                     exception);
793                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
794                     image->columns,1,exception);
795                   if ((p == (const Quantum *) NULL) ||
796                       (q == (Quantum *) NULL))
797                     break;
798                   for (x=0; x < (ssize_t) image->columns; x++)
799                   {
800                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
801                     p+=GetPixelChannels(canvas_image);
802                     q+=GetPixelChannels(image);
803                   }
804                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
805                     break;
806                }
807               count=ReadBlob(image,length,pixels);
808             }
809             if (image->previous == (Image *) NULL)
810               {
811                 status=SetImageProgress(image,LoadImageTag,4,5);
812                 if (status == MagickFalse)
813                   break;
814               }
815           }
816         if (image->previous == (Image *) NULL)
817           {
818             status=SetImageProgress(image,LoadImageTag,5,5);
819             if (status == MagickFalse)
820               break;
821           }
822         break;
823       }
824     }
825     SetQuantumImageType(image,quantum_type);
826     /*
827       Proceed to next image.
828     */
829     if (image_info->number_scenes != 0)
830       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
831         break;
832     if (count == (ssize_t) length)
833       {
834         /*
835           Allocate next image structure.
836         */
837         AcquireNextImage(image_info,image,exception);
838         if (GetNextImageInList(image) == (Image *) NULL)
839           {
840             image=DestroyImageList(image);
841             return((Image *) NULL);
842           }
843         image=SyncNextImageInList(image);
844         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
845           GetBlobSize(image));
846         if (status == MagickFalse)
847           break;
848       }
849     scene++;
850   } while (count == (ssize_t) length);
851   quantum_info=DestroyQuantumInfo(quantum_info);
852   canvas_image=DestroyImage(canvas_image);
853   (void) CloseBlob(image);
854   return(GetFirstImageInList(image));
855 }
856 \f
857 /*
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 %   R e g i s t e r Y C b C r I m a g e                                       %
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 %
868 %  RegisterYCBCRImage() adds attributes for the YCbCr or YCbCrA image format to
869 %  the list of supported formats.  The attributes include the image format
870 %  tag, a method to read and/or write the format, whether the format
871 %  supports the saving of more than one frame to the same file or blob,
872 %  whether the format supports native in-memory I/O, and a brief
873 %  description of the format.
874 %
875 %  The format of the RegisterYCBCRImage method is:
876 %
877 %      size_t RegisterYCBCRImage(void)
878 %
879 */
880 ModuleExport size_t RegisterYCBCRImage(void)
881 {
882   MagickInfo
883     *entry;
884
885   entry=SetMagickInfo("YCbCr");
886   entry->decoder=(DecodeImageHandler *) ReadYCBCRImage;
887   entry->encoder=(EncodeImageHandler *) WriteYCBCRImage;
888   entry->raw=MagickTrue;
889   entry->endian_support=MagickTrue;
890   entry->description=ConstantString("Raw Y, Cb, and Cr samples");
891   entry->module=ConstantString("YCbCr");
892   (void) RegisterMagickInfo(entry);
893   entry=SetMagickInfo("YCbCrA");
894   entry->decoder=(DecodeImageHandler *) ReadYCBCRImage;
895   entry->encoder=(EncodeImageHandler *) WriteYCBCRImage;
896   entry->raw=MagickTrue;
897   entry->endian_support=MagickTrue;
898   entry->description=ConstantString("Raw Y, Cb, Cr, and alpha samples");
899   entry->module=ConstantString("YCbCr");
900   (void) RegisterMagickInfo(entry);
901   return(MagickImageCoderSignature);
902 }
903 \f
904 /*
905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906 %                                                                             %
907 %                                                                             %
908 %                                                                             %
909 %   U n r e g i s t e r Y C b C r I m a g e                                   %
910 %                                                                             %
911 %                                                                             %
912 %                                                                             %
913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 %
915 %  UnregisterYCBCRImage() removes format registrations made by the
916 %  YCbCr module from the list of supported formats.
917 %
918 %  The format of the UnregisterYCBCRImage method is:
919 %
920 %      UnregisterYCBCRImage(void)
921 %
922 */
923 ModuleExport void UnregisterYCBCRImage(void)
924 {
925   (void) UnregisterMagickInfo("YCbCr");
926   (void) UnregisterMagickInfo("YCbCrA");
927 }
928 \f
929 /*
930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 %                                                                             %
932 %                                                                             %
933 %                                                                             %
934 %   W r i t e Y C b C r I m a g e                                             %
935 %                                                                             %
936 %                                                                             %
937 %                                                                             %
938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 %
940 %  WriteYCBCRImage() writes an image to a file in the YCbCr or YCbCrA
941 %  rasterfile format.
942 %
943 %  The format of the WriteYCBCRImage method is:
944 %
945 %      MagickBooleanType WriteYCBCRImage(const ImageInfo *image_info,
946 %        Image *image,ExceptionInfo *exception)
947 %
948 %  A description of each parameter follows.
949 %
950 %    o image_info: the image info.
951 %
952 %    o image:  The image.
953 %
954 %    o exception: return any errors or warnings in this structure.
955 %
956 */
957 static MagickBooleanType WriteYCBCRImage(const ImageInfo *image_info,
958   Image *image,ExceptionInfo *exception)
959 {
960   MagickBooleanType
961     status;
962
963   MagickOffsetType
964     scene;
965
966   QuantumInfo
967     *quantum_info;
968
969   QuantumType
970     quantum_type;
971
972   register const Quantum
973     *p;
974
975   size_t
976     length;
977
978   ssize_t
979     count,
980     y;
981
982   unsigned char
983     *pixels;
984
985   /*
986     Allocate memory for pixels.
987   */
988   assert(image_info != (const ImageInfo *) NULL);
989   assert(image_info->signature == MagickSignature);
990   assert(image != (Image *) NULL);
991   assert(image->signature == MagickSignature);
992   if (image->debug != MagickFalse)
993     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
994   if (image_info->interlace != PartitionInterlace)
995     {
996       /*
997         Open output image file.
998       */
999       assert(exception != (ExceptionInfo *) NULL);
1000   assert(exception->signature == MagickSignature);
1001   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1002       if (status == MagickFalse)
1003         return(status);
1004     }
1005   quantum_type=RGBQuantum;
1006   if (LocaleCompare(image_info->magick,"YCbCrA") == 0)
1007     {
1008       quantum_type=RGBAQuantum;
1009       image->matte=MagickTrue;
1010     }
1011   scene=0;
1012   do
1013   {
1014     /*
1015       Convert MIFF to YCbCr raster pixels.
1016     */
1017     if (image->colorspace != YCbCrColorspace)
1018       (void) TransformImageColorspace(image,YCbCrColorspace,exception);
1019     if ((LocaleCompare(image_info->magick,"YCbCrA") == 0) &&
1020         (image->matte == MagickFalse))
1021       (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1022     quantum_info=AcquireQuantumInfo(image_info,image);
1023     if (quantum_info == (QuantumInfo *) NULL)
1024       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1025     pixels=GetQuantumPixels(quantum_info);
1026     switch (image_info->interlace)
1027     {
1028       case NoInterlace:
1029       default:
1030       {
1031         /*
1032           No interlacing:  YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr...
1033         */
1034         for (y=0; y < (ssize_t) image->rows; y++)
1035         {
1036           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1037           if (p == (const Quantum *) NULL)
1038             break;
1039           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1040             quantum_type,pixels,exception);
1041           count=WriteBlob(image,length,pixels);
1042           if (count != (ssize_t) length)
1043             break;
1044           if (image->previous == (Image *) NULL)
1045             {
1046               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1047                 image->rows);
1048               if (status == MagickFalse)
1049                 break;
1050             }
1051         }
1052         break;
1053       }
1054       case LineInterlace:
1055       {
1056         /*
1057           Line interlacing:  YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr...
1058         */
1059         for (y=0; y < (ssize_t) image->rows; y++)
1060         {
1061           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1062           if (p == (const Quantum *) NULL)
1063             break;
1064           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1065             RedQuantum,pixels,exception);
1066           count=WriteBlob(image,length,pixels);
1067           if (count != (ssize_t) length)
1068             break;
1069           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1070             GreenQuantum,pixels,exception);
1071           count=WriteBlob(image,length,pixels);
1072           if (count != (ssize_t) length)
1073             break;
1074           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1075             BlueQuantum,pixels,exception);
1076           count=WriteBlob(image,length,pixels);
1077           if (count != (ssize_t) length)
1078             break;
1079           if (quantum_type == RGBAQuantum)
1080             {
1081               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1082                 AlphaQuantum,pixels,exception);
1083               count=WriteBlob(image,length,pixels);
1084               if (count != (ssize_t) length)
1085                 break;
1086             }
1087           if (image->previous == (Image *) NULL)
1088             {
1089               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1090                 image->rows);
1091               if (status == MagickFalse)
1092                 break;
1093             }
1094         }
1095         break;
1096       }
1097       case PlaneInterlace:
1098       {
1099         /*
1100           Plane interlacing:  YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr...
1101         */
1102         for (y=0; y < (ssize_t) image->rows; y++)
1103         {
1104           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1105           if (p == (const Quantum *) NULL)
1106             break;
1107           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1108             RedQuantum,pixels,exception);
1109           count=WriteBlob(image,length,pixels);
1110           if (count != (ssize_t) length)
1111             break;
1112         }
1113         if (image->previous == (Image *) NULL)
1114           {
1115             status=SetImageProgress(image,SaveImageTag,1,5);
1116             if (status == MagickFalse)
1117               break;
1118           }
1119         for (y=0; y < (ssize_t) image->rows; y++)
1120         {
1121           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1122           if (p == (const Quantum *) NULL)
1123             break;
1124           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1125             GreenQuantum,pixels,exception);
1126           count=WriteBlob(image,length,pixels);
1127           if (count != (ssize_t) length)
1128             break;
1129         }
1130         if (image->previous == (Image *) NULL)
1131           {
1132             status=SetImageProgress(image,SaveImageTag,2,5);
1133             if (status == MagickFalse)
1134               break;
1135           }
1136         for (y=0; y < (ssize_t) image->rows; y++)
1137         {
1138           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1139           if (p == (const Quantum *) NULL)
1140             break;
1141           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1142             BlueQuantum,pixels,exception);
1143           count=WriteBlob(image,length,pixels);
1144           if (count != (ssize_t) length)
1145             break;
1146         }
1147         if (image->previous == (Image *) NULL)
1148           {
1149             status=SetImageProgress(image,SaveImageTag,3,5);
1150             if (status == MagickFalse)
1151               break;
1152           }
1153         if (quantum_type == RGBAQuantum)
1154           {
1155             for (y=0; y < (ssize_t) image->rows; y++)
1156             {
1157               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1158               if (p == (const Quantum *) NULL)
1159                 break;
1160               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1161                 AlphaQuantum,pixels,exception);
1162               count=WriteBlob(image,length,pixels);
1163               if (count != (ssize_t) length)
1164               break;
1165             }
1166           }
1167         if (image_info->interlace == PartitionInterlace)
1168           (void) CopyMagickString(image->filename,image_info->filename,
1169             MaxTextExtent);
1170         if (image->previous == (Image *) NULL)
1171           {
1172             status=SetImageProgress(image,SaveImageTag,5,5);
1173             if (status == MagickFalse)
1174               break;
1175           }
1176         break;
1177       }
1178       case PartitionInterlace:
1179       {
1180         /*
1181           Partition interlacing:  YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr...
1182         */
1183         AppendImageFormat("Y",image->filename);
1184         status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1185           AppendBinaryBlobMode,exception);
1186         if (status == MagickFalse)
1187           return(status);
1188         for (y=0; y < (ssize_t) image->rows; y++)
1189         {
1190           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1191           if (p == (const Quantum *) NULL)
1192             break;
1193           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1194             RedQuantum,pixels,exception);
1195           count=WriteBlob(image,length,pixels);
1196           if (count != (ssize_t) length)
1197             break;
1198         }
1199         if (image->previous == (Image *) NULL)
1200           {
1201             status=SetImageProgress(image,SaveImageTag,1,5);
1202             if (status == MagickFalse)
1203               break;
1204           }
1205         (void) CloseBlob(image);
1206         AppendImageFormat("Cb",image->filename);
1207         status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1208           AppendBinaryBlobMode,exception);
1209         if (status == MagickFalse)
1210           return(status);
1211         for (y=0; y < (ssize_t) image->rows; y++)
1212         {
1213           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1214           if (p == (const Quantum *) NULL)
1215             break;
1216           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1217             GreenQuantum,pixels,exception);
1218           count=WriteBlob(image,length,pixels);
1219           if (count != (ssize_t) length)
1220             break;
1221         }
1222         if (image->previous == (Image *) NULL)
1223           {
1224             status=SetImageProgress(image,SaveImageTag,2,5);
1225             if (status == MagickFalse)
1226               break;
1227           }
1228         (void) CloseBlob(image);
1229         AppendImageFormat("Cr",image->filename);
1230         status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1231           AppendBinaryBlobMode,exception);
1232         if (status == MagickFalse)
1233           return(status);
1234         for (y=0; y < (ssize_t) image->rows; y++)
1235         {
1236           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1237           if (p == (const Quantum *) NULL)
1238             break;
1239           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1240             BlueQuantum,pixels,exception);
1241           count=WriteBlob(image,length,pixels);
1242           if (count != (ssize_t) length)
1243             break;
1244         }
1245         if (image->previous == (Image *) NULL)
1246           {
1247             status=SetImageProgress(image,SaveImageTag,3,5);
1248             if (status == MagickFalse)
1249               break;
1250           }
1251         if (quantum_type == RGBAQuantum)
1252           {
1253             (void) CloseBlob(image);
1254             AppendImageFormat("A",image->filename);
1255             status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1256               AppendBinaryBlobMode,exception);
1257             if (status == MagickFalse)
1258               return(status);
1259             for (y=0; y < (ssize_t) image->rows; y++)
1260             {
1261               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1262               if (p == (const Quantum *) NULL)
1263                 break;
1264               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1265                 AlphaQuantum,pixels,exception);
1266               count=WriteBlob(image,length,pixels);
1267               if (count != (ssize_t) length)
1268                 break;
1269             }
1270             if (image->previous == (Image *) NULL)
1271               {
1272                 status=SetImageProgress(image,SaveImageTag,4,5);
1273                 if (status == MagickFalse)
1274                   break;
1275               }
1276           }
1277         (void) CloseBlob(image);
1278         (void) CopyMagickString(image->filename,image_info->filename,
1279           MaxTextExtent);
1280         if (image->previous == (Image *) NULL)
1281           {
1282             status=SetImageProgress(image,SaveImageTag,5,5);
1283             if (status == MagickFalse)
1284               break;
1285           }
1286         break;
1287       }
1288     }
1289     quantum_info=DestroyQuantumInfo(quantum_info);
1290     if (GetNextImageInList(image) == (Image *) NULL)
1291       break;
1292     image=SyncNextImageInList(image);
1293     status=SetImageProgress(image,SaveImagesTag,scene++,
1294       GetImageListLength(image));
1295     if (status == MagickFalse)
1296       break;
1297   } while (image_info->adjoin != MagickFalse);
1298   (void) CloseBlob(image);
1299   return(MagickTrue);
1300 }