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