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