2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21
% Read/Write Raw CCIR 601 4:1:1 or 4:2:2 Image Format. %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
#include "magick/studio.h"
39
#include "magick/blob.h"
40
#include "magick/cache.h"
41
#include "magick/magick.h"
42
#include "magick/monitor.h"
43
#include "magick/resize.h"
44
#include "magick/utility.h"
50
WriteYUVImage(const ImageInfo *,Image *);
53
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57
% R e a d Y U V I m a g e %
61
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63
% Method ReadYUVImage reads an image with digital YUV (CCIR 601 4:1:1, plane
64
% or partition interlaced, or 4:2:2 plane, partition interlaced or
65
% noninterlaced) bytes and returns it. It allocates the memory necessary
66
% for the new Image structure and returns a pointer to the new image.
68
% The format of the ReadYUVImage method is:
70
% Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception)
72
% A description of each parameter follows:
74
% o image: Method ReadYUVImage returns a pointer to the image after
75
% reading. A null image is returned if there is a memory shortage or
76
% if the image cannot be read.
78
% o image_info: Specifies a pointer to a ImageInfo structure.
80
% o exception: return any errors or warnings in this structure.
84
static Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception)
96
register const PixelPacket
109
register unsigned char
125
Allocate image structure.
127
assert(image_info != (const ImageInfo *) NULL);
128
assert(image_info->signature == MagickSignature);
129
assert(exception != (ExceptionInfo *) NULL);
130
assert(exception->signature == MagickSignature);
131
image=AllocateImage(image_info);
132
if ((image->columns == 0) || (image->rows == 0))
133
ThrowReaderException(OptionError,MustSpecifyImageSize,image);
135
interlace=image_info->interlace;
138
if (image_info->sampling_factor != (char *) NULL)
143
factors=sscanf(image_info->sampling_factor,"%ldx%ld",&horizontal_factor,
146
vertical_factor=horizontal_factor;
147
if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
148
(vertical_factor != 1) && (vertical_factor != 2))
149
ThrowReaderException(CorruptImageError,UnexpectedSamplingFactor,
152
if ((interlace == UndefinedInterlace) ||
153
((interlace == NoInterlace) && (vertical_factor == 2)))
155
interlace=NoInterlace; /* CCIR 4:2:2 */
156
if (vertical_factor == 2)
157
interlace=PlaneInterlace; /* CCIR 4:1:1 */
159
if (interlace != PartitionInterlace)
164
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
166
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
167
for (i=0; i < image->offset; i++)
168
(void) ReadBlobByte(image);
171
Allocate memory for a scanline.
173
if (interlace == NoInterlace)
174
scanline=MagickAllocateMemory(unsigned char *,2*image->columns+2);
176
scanline=MagickAllocateMemory(unsigned char *,image->columns);
177
if (scanline == (unsigned char *) NULL)
178
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
181
chroma_image=CloneImage(image,image->columns/horizontal_factor,
182
image->rows/vertical_factor,True,exception);
183
if (chroma_image == (Image *) NULL)
184
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
186
Convert raster image to pixel packets.
188
if (image_info->ping && (image_info->subrange != 0))
189
if (image->scene >= (image_info->subimage+image_info->subrange-1))
191
if (interlace == PartitionInterlace)
193
AppendImageFormat("Y",image->filename);
194
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
196
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
198
for (y=0; y < (long) image->rows; y++)
200
if (interlace == NoInterlace)
202
if ((y > 0) || (image->previous == (Image *) NULL))
203
(void) ReadBlob(image,2*image->columns,scanline);
205
q=SetImagePixels(image,0,y,image->columns,1);
206
if (q == (PixelPacket *) NULL)
208
s=SetImagePixels(chroma_image,0,y,chroma_image->columns,1);
209
if (s == (PixelPacket *) NULL)
211
for (x=0; x < (long) image->columns; x+=2)
214
s->green=ScaleCharToQuantum(*p++);
215
q->red=ScaleCharToQuantum(*p++);
221
s->blue=ScaleCharToQuantum(*p++);
222
q->red=ScaleCharToQuantum(*p++);
229
if ((y > 0) || (image->previous == (Image *) NULL))
230
(void) ReadBlob(image,image->columns,scanline);
232
q=SetImagePixels(image,0,y,image->columns,1);
233
if (q == (PixelPacket *) NULL)
235
for (x=0; x < (long) image->columns; x++)
237
q->red=ScaleCharToQuantum(*p++);
243
if (!SyncImagePixels(image))
245
if (interlace == NoInterlace)
246
if (!SyncImagePixels(chroma_image))
248
if (image->previous == (Image *) NULL)
249
if (!MagickMonitor(LoadImageText,y,image->rows,exception))
252
if (interlace == PartitionInterlace)
255
AppendImageFormat("U",image->filename);
256
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
258
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
260
if (interlace != NoInterlace)
262
for (y=0; y < (long) chroma_image->rows; y++)
264
(void) ReadBlob(image,chroma_image->columns,scanline);
266
q=SetImagePixels(chroma_image,0,y,chroma_image->columns,1);
267
if (q == (PixelPacket *) NULL)
269
for (x=0; x < (long) chroma_image->columns; x++)
272
q->green=ScaleCharToQuantum(*p++);
276
if (!SyncImagePixels(chroma_image))
279
if (interlace == PartitionInterlace)
282
AppendImageFormat("V",image->filename);
283
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
285
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
287
for (y=0; y < (long) chroma_image->rows; y++)
289
(void) ReadBlob(image,chroma_image->columns,scanline);
291
q=GetImagePixels(chroma_image,0,y,chroma_image->columns,1);
292
if (q == (PixelPacket *) NULL)
294
for (x=0; x < (long) chroma_image->columns; x++)
296
q->blue=ScaleCharToQuantum(*p++);
299
if (!SyncImagePixels(chroma_image))
306
resize_image=ResizeImage(chroma_image,image->columns,image->rows,
307
TriangleFilter,1.0,exception);
308
DestroyImage(chroma_image);
309
if (resize_image == (Image *) NULL)
310
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
311
for (y=0; y < (long) image->rows; y++)
313
q=GetImagePixels(image,0,y,image->columns,1);
314
r=AcquireImagePixels(resize_image,0,y,resize_image->columns,1,
315
&resize_image->exception);
316
if ((q == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
318
for (x=0; x < (long) image->columns; x++)
325
if (!SyncImagePixels(image))
328
DestroyImage(resize_image);
329
image->colorspace=YCbCrColorspace;
330
TransformColorspace(image,RGBColorspace);
331
if (interlace == PartitionInterlace)
332
(void) strncpy(image->filename,image_info->filename,MaxTextExtent-1);
335
ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
340
Proceed to next image.
342
if (image_info->subrange != 0)
343
if (image->scene >= (image_info->subimage+image_info->subrange-1))
345
if (interlace == NoInterlace)
346
count=ReadBlob(image,2*image->columns,(char *) scanline);
348
count=ReadBlob(image,image->columns,(char *) scanline);
352
Allocate next image structure.
354
AllocateNextImage(image_info,image);
355
if (image->next == (Image *) NULL)
357
DestroyImageList(image);
358
return((Image *) NULL);
360
image=SyncNextImageInList(image);
361
if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
364
} while (count != 0);
365
MagickFreeMemory(scanline);
366
while (image->previous != (Image *) NULL)
367
image=image->previous;
373
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377
% R e g i s t e r Y U V I m a g e %
381
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383
% Method RegisterYUVImage adds attributes for the YUV image format to
384
% the list of supported formats. The attributes include the image format
385
% tag, a method to read and/or write the format, whether the format
386
% supports the saving of more than one frame to the same file or blob,
387
% whether the format supports native in-memory I/O, and a brief
388
% description of the format.
390
% The format of the RegisterYUVImage method is:
392
% RegisterYUVImage(void)
395
ModuleExport void RegisterYUVImage(void)
400
entry=SetMagickInfo("YUV");
401
entry->decoder=(DecoderHandler) ReadYUVImage;
402
entry->encoder=(EncoderHandler) WriteYUVImage;
405
entry->description=AcquireString("CCIR 601 4:1:1 or 4:2:2");
406
entry->module=AcquireString("YUV");
407
(void) RegisterMagickInfo(entry);
411
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415
% U n r e g i s t e r Y U V I m a g e %
419
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421
% Method UnregisterYUVImage removes format registrations made by the
422
% YUV module from the list of supported formats.
424
% The format of the UnregisterYUVImage method is:
426
% UnregisterYUVImage(void)
429
ModuleExport void UnregisterYUVImage(void)
431
(void) UnregisterMagickInfo("YUV");
435
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439
% W r i t e Y U V I m a g e %
443
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445
% Method WriteYUVImage writes an image to a file in the digital YUV
446
% (CCIR 601 4:1:1, plane or partition interlaced, or 4:2:2 plane, partition
447
% interlaced or noninterlaced) bytes and returns it.
449
% The format of the WriteYUVImage method is:
451
% unsigned int WriteYUVImage(const ImageInfo *image_info,Image *image)
453
% A description of each parameter follows.
455
% o status: Method WriteYUVImage return True if the image is written.
456
% False is returned is there is a memory shortage or if the image file
459
% o image_info: Specifies a pointer to a ImageInfo structure.
461
% o image: A pointer to an Image structure.
465
static unsigned int WriteYUVImage(const ImageInfo *image_info,Image *image)
479
register const PixelPacket
494
assert(image_info != (const ImageInfo *) NULL);
495
assert(image_info->signature == MagickSignature);
496
assert(image != (Image *) NULL);
497
assert(image->signature == MagickSignature);
498
interlace=image_info->interlace;
501
if (image_info->sampling_factor != (char *) NULL)
506
factors=sscanf(image_info->sampling_factor,"%ldx%ld",&horizontal_factor,
509
vertical_factor=horizontal_factor;
510
if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
511
(vertical_factor != 1) && (vertical_factor != 2))
512
ThrowWriterException(CorruptImageError,UnexpectedSamplingFactor,
515
if ((interlace == UndefinedInterlace) ||
516
((interlace == NoInterlace) && (vertical_factor == 2)))
518
interlace=NoInterlace; /* CCIR 4:2:2 */
519
if (vertical_factor == 2)
520
interlace=PlaneInterlace; /* CCIR 4:1:1 */
522
if (interlace != PartitionInterlace)
525
Open output image file.
527
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
529
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
533
AppendImageFormat("Y",image->filename);
534
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
536
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
542
Sample image to an even width and height, if necessary.
545
TransformColorspace(image,RGBColorspace);
546
width=image->columns+(image->columns & (horizontal_factor-1));
547
height=image->rows+(image->rows & (vertical_factor-1));
548
yuv_image=ResizeImage(image,width,height,TriangleFilter,1.0,
550
if (yuv_image == (Image *) NULL)
551
ThrowWriterException2(ResourceLimitError,image->exception.reason,image);
552
TransformColorspace(yuv_image,YCbCrColorspace);
556
chroma_image=ResizeImage(image,width/horizontal_factor,
557
height/vertical_factor,TriangleFilter,1.0,&image->exception);
558
if (chroma_image == (Image *) NULL)
559
ThrowWriterException2(ResourceLimitError,image->exception.reason,image);
560
TransformColorspace(chroma_image,YCbCrColorspace);
561
if (interlace == NoInterlace)
564
Write noninterlaced YUV.
566
for (y=0; y < (long) yuv_image->rows; y++)
568
p=AcquireImagePixels(yuv_image,0,y,yuv_image->columns,1,
569
&yuv_image->exception);
570
if (p == (const PixelPacket *) NULL)
572
s=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
573
&chroma_image->exception);
574
if (s == (const PixelPacket *) NULL)
576
for (x=0; x < (long) yuv_image->columns; x++)
578
(void) WriteBlobByte(image,ScaleQuantumToChar(s->green));
579
(void) WriteBlobByte(image,ScaleQuantumToChar(p->red));
581
(void) WriteBlobByte(image,ScaleQuantumToChar(s->blue));
582
(void) WriteBlobByte(image,ScaleQuantumToChar(p->red));
587
if (image->previous == (Image *) NULL)
588
if (QuantumTick(y,image->rows))
589
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
592
DestroyImage(yuv_image);
597
Initialize Y channel.
599
for (y=0; y < (long) yuv_image->rows; y++)
601
p=AcquireImagePixels(yuv_image,0,y,yuv_image->columns,1,
602
&yuv_image->exception);
603
if (p == (const PixelPacket *) NULL)
605
for (x=0; x < (long) yuv_image->columns; x++)
607
(void) WriteBlobByte(image,ScaleQuantumToChar(p->red));
610
if (image->previous == (Image *) NULL)
611
if (QuantumTick(y,image->rows))
612
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
615
DestroyImage(yuv_image);
617
Initialize U channel.
619
if (interlace == PartitionInterlace)
622
AppendImageFormat("U",image->filename);
623
status=OpenBlob(image_info,image,WriteBinaryBlobMode,
626
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
628
for (y=0; y < (long) chroma_image->rows; y++)
630
p=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
631
&chroma_image->exception);
632
if (p == (const PixelPacket *) NULL)
634
for (x=0; x < (long) chroma_image->columns; x++)
636
(void) WriteBlobByte(image,ScaleQuantumToChar(p->green));
641
Initialize V channel.
643
if (interlace == PartitionInterlace)
646
AppendImageFormat("V",image->filename);
647
status=OpenBlob(image_info,image,WriteBinaryBlobMode,
650
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
652
for (y=0; y < (long) chroma_image->rows; y++)
654
p=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
655
&chroma_image->exception);
656
if (p == (const PixelPacket *) NULL)
658
for (x=0; x < (long) chroma_image->columns; x++)
660
(void) WriteBlobByte(image,ScaleQuantumToChar(p->blue));
665
DestroyImage(chroma_image);
666
if (interlace == PartitionInterlace)
667
(void) strncpy(image->filename,image_info->filename,MaxTextExtent-1);
668
if (image->next == (Image *) NULL)
670
image=SyncNextImageInList(image);
671
status=MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),
675
} while (image_info->adjoin);
676
if (image_info->adjoin)
677
while (image->previous != (Image *) NULL)
678
image=image->previous;