You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
14 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U U Y Y V V Y Y %
% U U Y Y V V Y Y %
% U U Y V V Y %
% U U Y V V Y %
% UUU Y V Y %
% %
% %
% Read/Write 16bit/pixel Interleaved YUV Image Format %
% %
% Software Design %
% Cristy %
% July 1992 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/cache.h"
#include "MagickCore/color.h"
#include "MagickCore/colorspace.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/module.h"
/*
Forward declarations.
*/
static MagickBooleanType
WriteUYVYImage(const ImageInfo *,Image *,ExceptionInfo *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e a d U Y V Y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ReadUYVYImage() reads an image in the UYVY format and returns it. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ReadUYVYImage method is:
%
% Image *ReadUYVYImage(const ImageInfo *image_info,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o exception: return any errors or warnings in this structure.
%
*/
static Image *ReadUYVYImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
Image
*image;
MagickBooleanType
status;
ssize_t
x;
Quantum
*q;
ssize_t
y;
unsigned char
u,
v,
y1,
y2;
/*
Open image file.
*/
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
image=AcquireImage(image_info,exception);
if ((image->columns == 0) || (image->rows == 0))
ThrowReaderException(OptionError,"MustSpecifyImageSize");
if ((image->columns % 2) != 0)
image->columns++;
(void) CopyMagickString(image->filename,image_info->filename,
MagickPathExtent);
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == MagickFalse)
return(DestroyImage(image));
if (DiscardBlobBytes(image,image->offset) == MagickFalse)
ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
image->filename);
image->depth=8;
if (image_info->ping != MagickFalse)
{
(void) CloseBlob(image);
return(GetFirstImageInList(image));
}
status=SetImageExtent(image,image->columns,image->rows,exception);
if (status == MagickFalse)
return(DestroyImageList(image));
/*
Accumulate UYVY, then unpack into two pixels.
*/
for (y=0; y < (ssize_t) image->rows; y++)
{
q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
if (q == (Quantum *) NULL)
break;
for (x=0; x < (ssize_t) (image->columns >> 1); x++)
{
u=(unsigned char) ReadBlobByte(image);
y1=(unsigned char) ReadBlobByte(image);
v=(unsigned char) ReadBlobByte(image);
y2=(unsigned char) ReadBlobByte(image);
SetPixelRed(image,ScaleCharToQuantum(y1),q);
SetPixelGreen(image,ScaleCharToQuantum(u),q);
SetPixelBlue(image,ScaleCharToQuantum(v),q);
q+=GetPixelChannels(image);
SetPixelRed(image,ScaleCharToQuantum(y2),q);
SetPixelGreen(image,ScaleCharToQuantum(u),q);
SetPixelBlue(image,ScaleCharToQuantum(v),q);
q+=GetPixelChannels(image);
}
if (SyncAuthenticPixels(image,exception) == MagickFalse)
break;
status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
image->rows);
if (status == MagickFalse)
break;
}
SetImageColorspace(image,YCbCrColorspace,exception);
if (EOFBlob(image) != MagickFalse)
ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
image->filename);
(void) CloseBlob(image);
return(GetFirstImageInList(image));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e g i s t e r U Y V Y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RegisterUYVYImage() adds attributes for the UYVY image format to
% the list of supported formats. The attributes include the image format
% tag, a method to read and/or write the format, whether the format
% supports the saving of more than one frame to the same file or blob,
% whether the format supports native in-memory I/O, and a brief
% description of the format.
%
% The format of the RegisterUYVYImage method is:
%
% size_t RegisterUYVYImage(void)
%
*/
ModuleExport size_t RegisterUYVYImage(void)
{
MagickInfo
*entry;
entry=AcquireMagickInfo("UYVY","PAL","16bit/pixel interleaved YUV");
entry->decoder=(DecodeImageHandler *) ReadUYVYImage;
entry->encoder=(EncodeImageHandler *) WriteUYVYImage;
entry->flags^=CoderAdjoinFlag;
entry->flags|=CoderRawSupportFlag;
entry->flags|=CoderEndianSupportFlag;
(void) RegisterMagickInfo(entry);
entry=AcquireMagickInfo("UYVY","UYVY","16bit/pixel interleaved YUV");
entry->decoder=(DecodeImageHandler *) ReadUYVYImage;
entry->encoder=(EncodeImageHandler *) WriteUYVYImage;
entry->flags^=CoderAdjoinFlag;
entry->flags|=CoderRawSupportFlag;
entry->flags|=CoderEndianSupportFlag;
(void) RegisterMagickInfo(entry);
return(MagickImageCoderSignature);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U n r e g i s t e r U Y V Y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% UnregisterUYVYImage() removes format registrations made by the
% UYVY module from the list of supported formats.
%
% The format of the UnregisterUYVYImage method is:
%
% UnregisterUYVYImage(void)
%
*/
ModuleExport void UnregisterUYVYImage(void)
{
(void) UnregisterMagickInfo("PAL");
(void) UnregisterMagickInfo("UYVY");
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e U Y V Y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% WriteUYVYImage() writes an image to a file in the digital UYVY
% format. This format, used by AccomWSD, is not dramatically higher quality
% than the 12bit/pixel YUV format, but has better locality.
%
% The format of the WriteUYVYImage method is:
%
% MagickBooleanType WriteUYVYImage(const ImageInfo *image_info,
% Image *image,ExceptionInfo *exception)
%
% A description of each parameter follows.
%
% o image_info: the image info.
%
% o image: The image. Implicit assumption: number of columns is even.
%
% o exception: return any errors or warnings in this structure.
%
*/
static MagickBooleanType WriteUYVYImage(const ImageInfo *image_info,
Image *image,ExceptionInfo *exception)
{
PixelInfo
pixel;
Image
*uyvy_image;
MagickBooleanType
full,
status;
const Quantum
*p;
ssize_t
x;
ssize_t
y;
/*
Open output image file.
*/
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
if ((image->columns % 2) != 0)
image->columns++;
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
if (status == MagickFalse)
return(status);
/*
Accumulate two pixels, then output.
*/
uyvy_image=CloneImage(image,0,0,MagickTrue,exception);
if (uyvy_image == (Image *) NULL)
return(MagickFalse);
(void) TransformImageColorspace(uyvy_image,YCbCrColorspace,exception);
full=MagickFalse;
(void) memset(&pixel,0,sizeof(PixelInfo));
for (y=0; y < (ssize_t) image->rows; y++)
{
p=GetVirtualPixels(uyvy_image,0,y,image->columns,1,exception);
if (p == (const Quantum *) NULL)
break;
for (x=0; x < (ssize_t) image->columns; x++)
{
if (full != MagickFalse)
{
pixel.green=(pixel.green+GetPixelGreen(uyvy_image,p))/2;
pixel.blue=(pixel.blue+GetPixelBlue(uyvy_image,p))/2;
(void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.green));
(void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.red));
(void) WriteBlobByte(image,ScaleQuantumToChar((Quantum) pixel.blue));
(void) WriteBlobByte(image,ScaleQuantumToChar(
GetPixelRed(uyvy_image,p)));
}
pixel.red=(double) GetPixelRed(uyvy_image,p);
pixel.green=(double) GetPixelGreen(uyvy_image,p);
pixel.blue=(double) GetPixelBlue(uyvy_image,p);
full=full == MagickFalse ? MagickTrue : MagickFalse;
p+=GetPixelChannels(uyvy_image);
}
status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
image->rows);
if (status == MagickFalse)
break;
}
uyvy_image=DestroyImage(uyvy_image);
(void) CloseBlob(image);
return(MagickTrue);
}