1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% U U Y Y V V Y Y % 7% U U Y Y V V Y Y % 8% U U Y V V Y % 9% U U Y V V Y % 10% UUU Y V Y % 11% % 12% % 13% Read/Write 16bit/pixel Interleaved YUV Image Format % 14% % 15% Software Design % 16% Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2016 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 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/blob.h" 44#include "MagickCore/blob-private.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/color.h" 47#include "MagickCore/colorspace.h" 48#include "MagickCore/exception.h" 49#include "MagickCore/exception-private.h" 50#include "MagickCore/image.h" 51#include "MagickCore/image-private.h" 52#include "MagickCore/list.h" 53#include "MagickCore/magick.h" 54#include "MagickCore/memory_.h" 55#include "MagickCore/monitor.h" 56#include "MagickCore/monitor-private.h" 57#include "MagickCore/pixel-accessor.h" 58#include "MagickCore/quantum-private.h" 59#include "MagickCore/static.h" 60#include "MagickCore/string_.h" 61#include "MagickCore/module.h" 62 63/* 64 Forward declarations. 65*/ 66static MagickBooleanType 67 WriteUYVYImage(const ImageInfo *,Image *,ExceptionInfo *); 68 69/* 70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 71% % 72% % 73% % 74% R e a d U Y V Y I m a g e % 75% % 76% % 77% % 78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 79% 80% ReadUYVYImage() reads an image in the UYVY format and returns it. It 81% allocates the memory necessary for the new Image structure and returns a 82% pointer to the new image. 83% 84% The format of the ReadUYVYImage method is: 85% 86% Image *ReadUYVYImage(const ImageInfo *image_info, 87% ExceptionInfo *exception) 88% 89% A description of each parameter follows: 90% 91% o image_info: the image info. 92% 93% o exception: return any errors or warnings in this structure. 94% 95*/ 96static Image *ReadUYVYImage(const ImageInfo *image_info, 97 ExceptionInfo *exception) 98{ 99 Image 100 *image; 101 102 MagickBooleanType 103 status; 104 105 register ssize_t 106 x; 107 108 register Quantum 109 *q; 110 111 ssize_t 112 y; 113 114 unsigned char 115 u, 116 v, 117 y1, 118 y2; 119 120 /* 121 Open image file. 122 */ 123 assert(image_info != (const ImageInfo *) NULL); 124 assert(image_info->signature == MagickCoreSignature); 125 if (image_info->debug != MagickFalse) 126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 127 image_info->filename); 128 assert(exception != (ExceptionInfo *) NULL); 129 assert(exception->signature == MagickCoreSignature); 130 image=AcquireImage(image_info,exception); 131 if ((image->columns == 0) || (image->rows == 0)) 132 ThrowReaderException(OptionError,"MustSpecifyImageSize"); 133 if ((image->columns % 2) != 0) 134 image->columns++; 135 (void) CopyMagickString(image->filename,image_info->filename,MagickPathExtent); 136 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 137 if (status == MagickFalse) 138 return((Image *) NULL); 139 if (DiscardBlobBytes(image,image->offset) == MagickFalse) 140 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 141 image->filename); 142 image->depth=8; 143 if (image_info->ping != MagickFalse) 144 { 145 (void) CloseBlob(image); 146 return(GetFirstImageInList(image)); 147 } 148 status=SetImageExtent(image,image->columns,image->rows,exception); 149 if (status == MagickFalse) 150 return(DestroyImageList(image)); 151 /* 152 Accumulate UYVY, then unpack into two pixels. 153 */ 154 for (y=0; y < (ssize_t) image->rows; y++) 155 { 156 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 157 if (q == (Quantum *) NULL) 158 break; 159 for (x=0; x < (ssize_t) (image->columns >> 1); x++) 160 { 161 u=(unsigned char) ReadBlobByte(image); 162 y1=(unsigned char) ReadBlobByte(image); 163 v=(unsigned char) ReadBlobByte(image); 164 y2=(unsigned char) ReadBlobByte(image); 165 SetPixelRed(image,ScaleCharToQuantum(y1),q); 166 SetPixelGreen(image,ScaleCharToQuantum(u),q); 167 SetPixelBlue(image,ScaleCharToQuantum(v),q); 168 q+=GetPixelChannels(image); 169 SetPixelRed(image,ScaleCharToQuantum(y2),q); 170 SetPixelGreen(image,ScaleCharToQuantum(u),q); 171 SetPixelBlue(image,ScaleCharToQuantum(v),q); 172 q+=GetPixelChannels(image); 173 } 174 if (SyncAuthenticPixels(image,exception) == MagickFalse) 175 break; 176 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 177 image->rows); 178 if (status == MagickFalse) 179 break; 180 } 181 SetImageColorspace(image,YCbCrColorspace,exception); 182 if (EOFBlob(image) != MagickFalse) 183 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 184 image->filename); 185 (void) CloseBlob(image); 186 return(GetFirstImageInList(image)); 187} 188 189/* 190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 191% % 192% % 193% % 194% R e g i s t e r U Y V Y I m a g e % 195% % 196% % 197% % 198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 199% 200% RegisterUYVYImage() adds attributes for the UYVY image format to 201% the list of supported formats. The attributes include the image format 202% tag, a method to read and/or write the format, whether the format 203% supports the saving of more than one frame to the same file or blob, 204% whether the format supports native in-memory I/O, and a brief 205% description of the format. 206% 207% The format of the RegisterUYVYImage method is: 208% 209% size_t RegisterUYVYImage(void) 210% 211*/ 212ModuleExport size_t RegisterUYVYImage(void) 213{ 214 MagickInfo 215 *entry; 216 217 entry=AcquireMagickInfo("UYVY","PAL","16bit/pixel interleaved YUV"); 218 entry->decoder=(DecodeImageHandler *) ReadUYVYImage; 219 entry->encoder=(EncodeImageHandler *) WriteUYVYImage; 220 entry->flags^=CoderAdjoinFlag; 221 entry->flags|=CoderRawSupportFlag; 222 entry->flags|=CoderEndianSupportFlag; 223 (void) RegisterMagickInfo(entry); 224 entry=AcquireMagickInfo("UYVY","UYVY","16bit/pixel interleaved YUV"); 225 entry->decoder=(DecodeImageHandler *) ReadUYVYImage; 226 entry->encoder=(EncodeImageHandler *) WriteUYVYImage; 227 entry->flags^=CoderAdjoinFlag; 228 entry->flags|=CoderRawSupportFlag; 229 entry->flags|=CoderEndianSupportFlag; 230 (void) RegisterMagickInfo(entry); 231 return(MagickImageCoderSignature); 232} 233 234/* 235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 236% % 237% % 238% % 239% U n r e g i s t e r U Y V Y I m a g e % 240% % 241% % 242% % 243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 244% 245% UnregisterUYVYImage() removes format registrations made by the 246% UYVY module from the list of supported formats. 247% 248% The format of the UnregisterUYVYImage method is: 249% 250% UnregisterUYVYImage(void) 251% 252*/ 253ModuleExport void UnregisterUYVYImage(void) 254{ 255 (void) UnregisterMagickInfo("PAL"); 256 (void) UnregisterMagickInfo("UYVY"); 257} 258 259/* 260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 261% % 262% % 263% % 264% W r i t e U Y V Y I m a g e % 265% % 266% % 267% % 268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 269% 270% WriteUYVYImage() writes an image to a file in the digital UYVY 271% format. This format, used by AccomWSD, is not dramatically higher quality 272% than the 12bit/pixel YUV format, but has better locality. 273% 274% The format of the WriteUYVYImage method is: 275% 276% MagickBooleanType WriteUYVYImage(const ImageInfo *image_info, 277% Image *image,ExceptionInfo *exception) 278% 279% A description of each parameter follows. 280% 281% o image_info: the image info. 282% 283% o image: The image. Implicit assumption: number of columns is even. 284% 285% o exception: return any errors or warnings in this structure. 286% 287*/ 288static MagickBooleanType WriteUYVYImage(const ImageInfo *image_info, 289 Image *image,ExceptionInfo *exception) 290{ 291 PixelInfo 292 pixel; 293 294 Image 295 *uyvy_image; 296 297 MagickBooleanType 298 full, 299 status; 300 301 register const Quantum 302 *p; 303 304 register ssize_t 305 x; 306 307 ssize_t 308 y; 309 310 /* 311 Open output image file. 312 */ 313 assert(image_info != (const ImageInfo *) NULL); 314 assert(image_info->signature == MagickCoreSignature); 315 assert(image != (Image *) NULL); 316 assert(image->signature == MagickCoreSignature); 317 if (image->debug != MagickFalse) 318 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 319 if ((image->columns % 2) != 0) 320 image->columns++; 321 assert(exception != (ExceptionInfo *) NULL); 322 assert(exception->signature == MagickCoreSignature); 323 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 324 if (status == MagickFalse) 325 return(status); 326 /* 327 Accumulate two pixels, then output. 328 */ 329 uyvy_image=CloneImage(image,0,0,MagickTrue,exception); 330 if (uyvy_image == (Image *) NULL) 331 return(MagickFalse); 332 (void) TransformImageColorspace(uyvy_image,YCbCrColorspace,exception); 333 full=MagickFalse; 334 (void) ResetMagickMemory(&pixel,0,sizeof(PixelInfo)); 335 for (y=0; y < (ssize_t) image->rows; y++) 336 { 337 p=GetVirtualPixels(uyvy_image,0,y,image->columns,1,exception); 338 if (p == (const Quantum *) NULL) 339 break; 340 for (x=0; x < (ssize_t) image->columns; x++) 341 { 342 if (full != MagickFalse) 343 { 344 pixel.green=(pixel.green+GetPixelGreen(uyvy_image,p))/2; 345 pixel.blue=(pixel.blue+GetPixelBlue(uyvy_image,p))/2; 346 (void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.green)); 347 (void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.red)); 348 (void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.blue)); 349 (void) WriteBlobByte(image,ScaleQuantumToChar( 350 GetPixelRed(uyvy_image,p))); 351 } 352 pixel.red=(double) GetPixelRed(uyvy_image,p); 353 pixel.green=(double) GetPixelGreen(uyvy_image,p); 354 pixel.blue=(double) GetPixelBlue(uyvy_image,p); 355 full=full == MagickFalse ? MagickTrue : MagickFalse; 356 p+=GetPixelChannels(uyvy_image); 357 } 358 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 359 image->rows); 360 if (status == MagickFalse) 361 break; 362 } 363 uyvy_image=DestroyImage(uyvy_image); 364 (void) CloseBlob(image); 365 return(MagickTrue); 366} 367