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