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