]> granicus.if.org Git - imagemagick/blob - coders/ycbcr.c
b0fa64f37d887619c5ce3996fab26bb4f652a14a
[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-2011 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);
148   if ((image->columns == 0) || (image->rows == 0))
149     ThrowReaderException(OptionError,"MustSpecifyImageSize");
150   image->colorspace=YCbCrColorspace;
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   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
170   if (quantum_info == (QuantumInfo *) NULL)
171     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
172   pixels=GetQuantumPixels(quantum_info);
173   quantum_type=RGBQuantum;
174   if (LocaleCompare(image_info->magick,"YCbCrA") == 0)
175     {
176       quantum_type=RGBAQuantum;
177       image->matte=MagickTrue;
178     }
179   if (image_info->number_scenes != 0)
180     while (image->scene < image_info->scene)
181     {
182       /*
183         Skip to next image.
184       */
185       image->scene++;
186       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
187       for (y=0; y < (ssize_t) image->rows; y++)
188       {
189         count=ReadBlob(image,length,pixels);
190         if (count != (ssize_t) length)
191           break;
192       }
193     }
194   count=0;
195   length=0;
196   scene=0;
197   do
198   {
199     /*
200       Read pixels to virtual canvas image then push to image.
201     */
202     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
203       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
204         break;
205     image->colorspace=YCbCrColorspace;
206     switch (image_info->interlace)
207     {
208       case NoInterlace:
209       default:
210       {
211         /*
212           No interlacing:  YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr...
213         */
214         if (scene == 0)
215           {
216             length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
217             count=ReadBlob(image,length,pixels);
218           }
219         for (y=0; y < (ssize_t) image->extract_info.height; y++)
220         {
221           if (count != (ssize_t) length)
222             {
223               ThrowFileException(exception,CorruptImageError,
224                 "UnexpectedEndOfFile",image->filename);
225               break;
226             }
227           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
228             exception);
229           if (q == (Quantum *) NULL)
230             break;
231           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
232             quantum_info,quantum_type,pixels,exception);
233           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
234             break;
235           if (((y-image->extract_info.y) >= 0) && 
236               ((y-image->extract_info.y) < (ssize_t) image->rows))
237             {
238               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
239                 canvas_image->columns,1,exception);
240               q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
241                 image->columns,1,exception);
242               if ((p == (const Quantum *) NULL) ||
243                   (q == (Quantum *) NULL))
244                 break;
245               for (x=0; x < (ssize_t) image->columns; x++)
246               {
247                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
248                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
249                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
250                 if (image->matte != MagickFalse)
251                   SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
252                 p+=GetPixelChannels(canvas_image);
253                 q+=GetPixelChannels(image);
254               }
255               if (SyncAuthenticPixels(image,exception) == MagickFalse)
256                 break;
257             }
258           if (image->previous == (Image *) NULL)
259             {
260               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
261                 image->rows);
262               if (status == MagickFalse)
263                 break;
264             }
265           count=ReadBlob(image,length,pixels);
266         }
267         break;
268       }
269       case LineInterlace:
270       {
271         static QuantumType
272           quantum_types[4] =
273           {
274             RedQuantum,
275             GreenQuantum,
276             BlueQuantum,
277             OpacityQuantum
278           };
279
280         /*
281           Line interlacing:  YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr...
282         */
283         if (scene == 0)
284           {
285             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
286             count=ReadBlob(image,length,pixels);
287           }
288         for (y=0; y < (ssize_t) image->extract_info.height; y++)
289         {
290           for (i=0; i < (image->matte != MagickFalse ? 4 : 3); i++)
291           {
292             if (count != (ssize_t) length)
293               {
294                 ThrowFileException(exception,CorruptImageError,
295                   "UnexpectedEndOfFile",image->filename);
296                 break;
297               }
298             quantum_type=quantum_types[i];
299             q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
300               exception);
301             if (q == (Quantum *) NULL)
302               break;
303             length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
304               quantum_info,quantum_type,pixels,exception);
305             if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
306               break;
307             if (((y-image->extract_info.y) >= 0) && 
308                 ((y-image->extract_info.y) < (ssize_t) image->rows))
309               {
310                 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
311                   0,canvas_image->columns,1,exception);
312                 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
313                   image->columns,1,exception);
314                 if ((p == (const Quantum *) NULL) ||
315                     (q == (Quantum *) NULL))
316                   break;
317                 for (x=0; x < (ssize_t) image->columns; x++)
318                 {
319                   switch (quantum_type)
320                   {
321                     case RedQuantum:
322                     {
323                       SetPixelRed(image,GetPixelRed(canvas_image,p),q);
324                       break;
325                     }
326                     case GreenQuantum:
327                     {
328                       SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
329                       break;
330                     }
331                     case BlueQuantum:
332                     {
333                       SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
334                       break;
335                     }
336                     case OpacityQuantum:
337                     {
338                       SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
339                       break;
340                     }
341                     default:
342                       break;
343                   }
344                   p+=GetPixelChannels(canvas_image);
345                   q+=GetPixelChannels(image);
346                 }
347                 if (SyncAuthenticPixels(image,exception) == MagickFalse)
348                   break;
349               }
350             count=ReadBlob(image,length,pixels);
351           }
352           if (image->previous == (Image *) NULL)
353             {
354               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
355                 image->rows);
356               if (status == MagickFalse)
357                 break;
358             }
359         }
360         break;
361       }
362       case PlaneInterlace:
363       {
364         /*
365           Plane interlacing:  YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr...
366         */
367         if (scene == 0)
368           {
369             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
370             count=ReadBlob(image,length,pixels);
371           }
372         for (y=0; y < (ssize_t) image->extract_info.height; y++)
373         {
374           if (count != (ssize_t) length)
375             {
376               ThrowFileException(exception,CorruptImageError,
377                 "UnexpectedEndOfFile",image->filename);
378               break;
379             }
380           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
381             exception);
382           if (q == (Quantum *) NULL)
383             break;
384           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
385             quantum_info,RedQuantum,pixels,exception);
386           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
387             break;
388           if (((y-image->extract_info.y) >= 0) && 
389               ((y-image->extract_info.y) < (ssize_t) image->rows))
390             {
391               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
392                 canvas_image->columns,1,exception);
393               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
394                 image->columns,1,exception);
395               if ((p == (const Quantum *) NULL) ||
396                   (q == (Quantum *) NULL))
397                 break;
398               for (x=0; x < (ssize_t) image->columns; x++)
399               {
400                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
401                 p+=GetPixelChannels(canvas_image);
402                 q+=GetPixelChannels(image);
403               }
404               if (SyncAuthenticPixels(image,exception) == MagickFalse)
405                 break;
406             }
407           count=ReadBlob(image,length,pixels);
408         }
409         if (image->previous == (Image *) NULL)
410           {
411             status=SetImageProgress(image,LoadImageTag,1,5);
412             if (status == MagickFalse)
413               break;
414           }
415         for (y=0; y < (ssize_t) image->extract_info.height; y++)
416         {
417           if (count != (ssize_t) length)
418             {
419               ThrowFileException(exception,CorruptImageError,
420                 "UnexpectedEndOfFile",image->filename);
421               break;
422             }
423           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
424             exception);
425           if (q == (Quantum *) NULL)
426             break;
427           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
428             quantum_info,GreenQuantum,pixels,exception);
429           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
430             break;
431           if (((y-image->extract_info.y) >= 0) && 
432               ((y-image->extract_info.y) < (ssize_t) image->rows))
433             {
434               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
435                 canvas_image->columns,1,exception);
436               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
437                 image->columns,1,exception);
438               if ((p == (const Quantum *) NULL) ||
439                   (q == (Quantum *) NULL))
440                 break;
441               for (x=0; x < (ssize_t) image->columns; x++)
442               {
443                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
444                 p+=GetPixelChannels(canvas_image);
445                 q+=GetPixelChannels(image);
446               }
447               if (SyncAuthenticPixels(image,exception) == MagickFalse)
448                 break;
449            }
450           count=ReadBlob(image,length,pixels);
451         }
452         if (image->previous == (Image *) NULL)
453           {
454             status=SetImageProgress(image,LoadImageTag,2,5);
455             if (status == MagickFalse)
456               break;
457           }
458         for (y=0; y < (ssize_t) image->extract_info.height; y++)
459         {
460           if (count != (ssize_t) length)
461             {
462               ThrowFileException(exception,CorruptImageError,
463                 "UnexpectedEndOfFile",image->filename);
464               break;
465             }
466           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
467             exception);
468           if (q == (Quantum *) NULL)
469             break;
470           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
471             quantum_info,BlueQuantum,pixels,exception);
472           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
473             break;
474           if (((y-image->extract_info.y) >= 0) && 
475               ((y-image->extract_info.y) < (ssize_t) image->rows))
476             {
477               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
478                 canvas_image->columns,1,exception);
479               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
480                 image->columns,1,exception);
481               if ((p == (const Quantum *) NULL) ||
482                   (q == (Quantum *) NULL))
483                 break;
484               for (x=0; x < (ssize_t) image->columns; x++)
485               {
486                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
487                 p+=GetPixelChannels(canvas_image);
488                 q+=GetPixelChannels(image);
489               }
490               if (SyncAuthenticPixels(image,exception) == MagickFalse)
491                 break;
492             }
493           count=ReadBlob(image,length,pixels);
494         }
495         if (image->previous == (Image *) NULL)
496           {
497             status=SetImageProgress(image,LoadImageTag,3,5);
498             if (status == MagickFalse)
499               break;
500           }
501         if (image->matte != MagickFalse)
502           {
503             for (y=0; y < (ssize_t) image->extract_info.height; y++)
504             {
505               if (count != (ssize_t) length)
506                 {
507                   ThrowFileException(exception,CorruptImageError,
508                     "UnexpectedEndOfFile",image->filename);
509                   break;
510                 }
511               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
512                 exception);
513               if (q == (Quantum *) NULL)
514                 break;
515               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
516                 quantum_info,AlphaQuantum,pixels,exception);
517               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
518                 break;
519               if (((y-image->extract_info.y) >= 0) && 
520                   ((y-image->extract_info.y) < (ssize_t) image->rows))
521                 {
522                   p=GetVirtualPixels(canvas_image,
523                     canvas_image->extract_info.x,0,canvas_image->columns,1,
524                     exception);
525                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
526                     image->columns,1,exception);
527                   if ((p == (const Quantum *) NULL) ||
528                       (q == (Quantum *) NULL))
529                     break;
530                   for (x=0; x < (ssize_t) image->columns; x++)
531                   {
532                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
533                     p+=GetPixelChannels(canvas_image);
534                     q+=GetPixelChannels(image);
535                   }
536                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
537                     break;
538                 }
539               count=ReadBlob(image,length,pixels);
540             }
541             if (image->previous == (Image *) NULL)
542               {
543                 status=SetImageProgress(image,LoadImageTag,4,5);
544                 if (status == MagickFalse)
545                   break;
546               }
547           }
548         if (image->previous == (Image *) NULL)
549           {
550             status=SetImageProgress(image,LoadImageTag,5,5);
551             if (status == MagickFalse)
552               break;
553           }
554         break;
555       }
556       case PartitionInterlace:
557       {
558         /*
559           Partition interlacing:  YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr...
560         */
561         AppendImageFormat("Y",image->filename);
562         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
563         if (status == MagickFalse)
564           {
565             canvas_image=DestroyImageList(canvas_image);
566             image=DestroyImageList(image);
567             return((Image *) NULL);
568           }
569         if (DiscardBlobBytes(image,image->offset) == MagickFalse)
570           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
571             image->filename);
572         length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
573         for (i=0; i < (ssize_t) scene; i++)
574           for (y=0; y < (ssize_t) image->extract_info.height; y++)
575             if (ReadBlob(image,length,pixels) != (ssize_t) length)
576               {
577                 ThrowFileException(exception,CorruptImageError,
578                   "UnexpectedEndOfFile",image->filename);
579                 break;
580               }
581         count=ReadBlob(image,length,pixels);
582         for (y=0; y < (ssize_t) image->extract_info.height; y++)
583         {
584           if (count != (ssize_t) length)
585             {
586               ThrowFileException(exception,CorruptImageError,
587                 "UnexpectedEndOfFile",image->filename);
588               break;
589             }
590           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
591             exception);
592           if (q == (Quantum *) NULL)
593             break;
594           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
595             quantum_info,RedQuantum,pixels,exception);
596           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
597             break;
598           if (((y-image->extract_info.y) >= 0) && 
599               ((y-image->extract_info.y) < (ssize_t) image->rows))
600             {
601               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
602                 canvas_image->columns,1,exception);
603               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
604                 image->columns,1,exception);
605               if ((p == (const Quantum *) NULL) ||
606                   (q == (Quantum *) NULL))
607                 break;
608               for (x=0; x < (ssize_t) image->columns; x++)
609               {
610                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
611                 p+=GetPixelChannels(canvas_image);
612                 q+=GetPixelChannels(image);
613               }
614               if (SyncAuthenticPixels(image,exception) == MagickFalse)
615                 break;
616             }
617           count=ReadBlob(image,length,pixels);
618         }
619         if (image->previous == (Image *) NULL)
620           {
621             status=SetImageProgress(image,LoadImageTag,1,5);
622             if (status == MagickFalse)
623               break;
624           }
625         (void) CloseBlob(image);
626         AppendImageFormat("Cb",image->filename);
627         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
628         if (status == MagickFalse)
629           {
630             canvas_image=DestroyImageList(canvas_image);
631             image=DestroyImageList(image);
632             return((Image *) NULL);
633           }
634         length=GetQuantumExtent(canvas_image,quantum_info,GreenQuantum);
635         for (i=0; i < (ssize_t) scene; i++)
636           for (y=0; y < (ssize_t) image->extract_info.height; y++)
637             if (ReadBlob(image,length,pixels) != (ssize_t) length)
638               {
639                 ThrowFileException(exception,CorruptImageError,
640                   "UnexpectedEndOfFile",image->filename);
641                 break;
642               }
643         count=ReadBlob(image,length,pixels);
644         for (y=0; y < (ssize_t) image->extract_info.height; y++)
645         {
646           if (count != (ssize_t) length)
647             {
648               ThrowFileException(exception,CorruptImageError,
649                 "UnexpectedEndOfFile",image->filename);
650               break;
651             }
652           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
653             exception);
654           if (q == (Quantum *) NULL)
655             break;
656           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
657             quantum_info,GreenQuantum,pixels,exception);
658           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
659             break;
660           if (((y-image->extract_info.y) >= 0) && 
661               ((y-image->extract_info.y) < (ssize_t) image->rows))
662             {
663               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
664                 canvas_image->columns,1,exception);
665               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
666                 image->columns,1,exception);
667               if ((p == (const Quantum *) NULL) ||
668                   (q == (Quantum *) NULL))
669                 break;
670               for (x=0; x < (ssize_t) image->columns; x++)
671               {
672                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
673                 p+=GetPixelChannels(canvas_image);
674                 q+=GetPixelChannels(image);
675               }
676               if (SyncAuthenticPixels(image,exception) == MagickFalse)
677                 break;
678            }
679           count=ReadBlob(image,length,pixels);
680         }
681         if (image->previous == (Image *) NULL)
682           {
683             status=SetImageProgress(image,LoadImageTag,2,5);
684             if (status == MagickFalse)
685               break;
686           }
687         (void) CloseBlob(image);
688         AppendImageFormat("Cr",image->filename);
689         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
690         if (status == MagickFalse)
691           {
692             canvas_image=DestroyImageList(canvas_image);
693             image=DestroyImageList(image);
694             return((Image *) NULL);
695           }
696         length=GetQuantumExtent(canvas_image,quantum_info,BlueQuantum);
697         for (i=0; i < (ssize_t) scene; i++)
698           for (y=0; y < (ssize_t) image->extract_info.height; y++)
699             if (ReadBlob(image,length,pixels) != (ssize_t) length)
700               {
701                 ThrowFileException(exception,CorruptImageError,
702                   "UnexpectedEndOfFile",image->filename);
703                 break;
704               }
705         count=ReadBlob(image,length,pixels);
706         for (y=0; y < (ssize_t) image->extract_info.height; y++)
707         {
708           if (count != (ssize_t) length)
709             {
710               ThrowFileException(exception,CorruptImageError,
711                 "UnexpectedEndOfFile",image->filename);
712               break;
713             }
714           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
715             exception);
716           if (q == (Quantum *) NULL)
717             break;
718           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
719             quantum_info,BlueQuantum,pixels,exception);
720           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
721             break;
722           if (((y-image->extract_info.y) >= 0) && 
723               ((y-image->extract_info.y) < (ssize_t) image->rows))
724             {
725               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
726                 canvas_image->columns,1,exception);
727               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
728                 image->columns,1,exception);
729               if ((p == (const Quantum *) NULL) ||
730                   (q == (Quantum *) NULL))
731                 break;
732               for (x=0; x < (ssize_t) image->columns; x++)
733               {
734                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
735                 p+=GetPixelChannels(canvas_image);
736                 q+=GetPixelChannels(image);
737               }
738               if (SyncAuthenticPixels(image,exception) == MagickFalse)
739                 break;
740            }
741           count=ReadBlob(image,length,pixels);
742         }
743         if (image->previous == (Image *) NULL)
744           {
745             status=SetImageProgress(image,LoadImageTag,3,5);
746             if (status == MagickFalse)
747               break;
748           }
749         if (image->matte != MagickFalse)
750           {
751             (void) CloseBlob(image);
752             AppendImageFormat("A",image->filename);
753             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
754             if (status == MagickFalse)
755               {
756                 canvas_image=DestroyImageList(canvas_image);
757                 image=DestroyImageList(image);
758                 return((Image *) NULL);
759               }
760             length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum);
761             for (i=0; i < (ssize_t) scene; i++)
762               for (y=0; y < (ssize_t) image->extract_info.height; y++)
763                 if (ReadBlob(image,length,pixels) != (ssize_t) length)
764                   {
765                     ThrowFileException(exception,CorruptImageError,
766                       "UnexpectedEndOfFile",image->filename);
767                     break;
768                   }
769             count=ReadBlob(image,length,pixels);
770             for (y=0; y < (ssize_t) image->extract_info.height; y++)
771             {
772               if (count != (ssize_t) length)
773                 {
774                   ThrowFileException(exception,CorruptImageError,
775                     "UnexpectedEndOfFile",image->filename);
776                   break;
777                 }
778               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
779                 exception);
780               if (q == (Quantum *) NULL)
781                 break;
782               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
783                 quantum_info,BlueQuantum,pixels,exception);
784               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
785                 break;
786               if (((y-image->extract_info.y) >= 0) && 
787                   ((y-image->extract_info.y) < (ssize_t) image->rows))
788                 {
789                   p=GetVirtualPixels(canvas_image,
790                     canvas_image->extract_info.x,0,canvas_image->columns,1,
791                     exception);
792                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
793                     image->columns,1,exception);
794                   if ((p == (const Quantum *) NULL) ||
795                       (q == (Quantum *) NULL))
796                     break;
797                   for (x=0; x < (ssize_t) image->columns; x++)
798                   {
799                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
800                     p+=GetPixelChannels(canvas_image);
801                     q+=GetPixelChannels(image);
802                   }
803                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
804                     break;
805                }
806               count=ReadBlob(image,length,pixels);
807             }
808             if (image->previous == (Image *) NULL)
809               {
810                 status=SetImageProgress(image,LoadImageTag,4,5);
811                 if (status == MagickFalse)
812                   break;
813               }
814           }
815         if (image->previous == (Image *) NULL)
816           {
817             status=SetImageProgress(image,LoadImageTag,5,5);
818             if (status == MagickFalse)
819               break;
820           }
821         break;
822       }
823     }
824     SetQuantumImageType(image,quantum_type);
825     /*
826       Proceed to next image.
827     */
828     if (image_info->number_scenes != 0)
829       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
830         break;
831     if (count == (ssize_t) length)
832       {
833         /*
834           Allocate next image structure.
835         */
836         AcquireNextImage(image_info,image);
837         if (GetNextImageInList(image) == (Image *) NULL)
838           {
839             image=DestroyImageList(image);
840             return((Image *) NULL);
841           }
842         image=SyncNextImageInList(image);
843         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
844           GetBlobSize(image));
845         if (status == MagickFalse)
846           break;
847       }
848     scene++;
849   } while (count == (ssize_t) length);
850   quantum_info=DestroyQuantumInfo(quantum_info);
851   InheritException(&image->exception,&canvas_image->exception);
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);
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 }