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