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