396 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			396 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                         W   W  EEEEE  BBBB   PPPP                           %
 | ||
| %                         W   W  E      B   B  P   P                          %
 | ||
| %                         W W W  EEE    BBBB   PPPP                           %
 | ||
| %                         WW WW  E      B   B  P                              %
 | ||
| %                         W   W  EEEEE  BBBB   P                              %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                         Read/Write WebP Image Format                        %
 | ||
| %                                                                             %
 | ||
| %                              Software Design                                %
 | ||
| %                                John Cristy                                  %
 | ||
| %                                 March 2011                                  %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %  Copyright 1999-2013 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                                            %
 | ||
| %                                                                             %
 | ||
| %    http://www.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 "magick/studio.h"
 | ||
| #include "magick/blob.h"
 | ||
| #include "magick/blob-private.h"
 | ||
| #include "magick/client.h"
 | ||
| #include "magick/display.h"
 | ||
| #include "magick/exception.h"
 | ||
| #include "magick/exception-private.h"
 | ||
| #include "magick/image.h"
 | ||
| #include "magick/image-private.h"
 | ||
| #include "magick/list.h"
 | ||
| #include "magick/magick.h"
 | ||
| #include "magick/monitor.h"
 | ||
| #include "magick/monitor-private.h"
 | ||
| #include "magick/memory_.h"
 | ||
| #include "magick/option.h"
 | ||
| #include "magick/pixel-accessor.h"
 | ||
| #include "magick/quantum-private.h"
 | ||
| #include "magick/static.h"
 | ||
| #include "magick/string_.h"
 | ||
| #include "magick/module.h"
 | ||
| #include "magick/utility.h"
 | ||
| #include "magick/xwindow.h"
 | ||
| #include "magick/xwindow-private.h"
 | ||
| #if defined(MAGICKCORE_WEBP_DELEGATE)
 | ||
| #include <webp/decode.h>
 | ||
| #include <webp/encode.h>
 | ||
| #endif
 | ||
| 
 | ||
| /*
 | ||
|   Forward declarations.
 | ||
| */
 | ||
| #if defined(MAGICKCORE_WEBP_DELEGATE)
 | ||
| static MagickBooleanType
 | ||
|   WriteWEBPImage(const ImageInfo *,Image *);
 | ||
| #endif
 | ||
| 
 | ||
| #if defined(MAGICKCORE_WEBP_DELEGATE)
 | ||
| /*
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %   R e a d W E B P I m a g e                                                 %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %
 | ||
| %  ReadWEBPImage() reads an image in the WebP image format.
 | ||
| %
 | ||
| %  The format of the ReadWEBPImage method is:
 | ||
| %
 | ||
| %      Image *ReadWEBPImage(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 *ReadWEBPImage(const ImageInfo *image_info,
 | ||
|   ExceptionInfo *exception)
 | ||
| {
 | ||
|   int
 | ||
|     height,
 | ||
|     width;
 | ||
| 
 | ||
|   Image
 | ||
|     *image;
 | ||
| 
 | ||
|   MagickBooleanType
 | ||
|     status;
 | ||
| 
 | ||
|   register PixelPacket
 | ||
|     *q;
 | ||
| 
 | ||
|   register ssize_t
 | ||
|     x;
 | ||
| 
 | ||
|   register unsigned char
 | ||
|     *p;
 | ||
| 
 | ||
|   size_t
 | ||
|     length;
 | ||
| 
 | ||
|   ssize_t
 | ||
|     count,
 | ||
|     y;
 | ||
| 
 | ||
|   unsigned char
 | ||
|     *stream,
 | ||
|     *pixels;
 | ||
| 
 | ||
|   /*
 | ||
|     Open image file.
 | ||
|   */
 | ||
|   assert(image_info != (const ImageInfo *) NULL);
 | ||
|   assert(image_info->signature == MagickSignature);
 | ||
|   if (image_info->debug != MagickFalse)
 | ||
|     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
 | ||
|       image_info->filename);
 | ||
|   assert(exception != (ExceptionInfo *) NULL);
 | ||
|   assert(exception->signature == MagickSignature);
 | ||
|   image=AcquireImage(image_info);
 | ||
|   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
 | ||
|   if (status == MagickFalse)
 | ||
|     {
 | ||
|       image=DestroyImageList(image);
 | ||
|       return((Image *) NULL);
 | ||
|     }
 | ||
|   length=(size_t) GetBlobSize(image);
 | ||
|   stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
 | ||
|   if (stream == (unsigned char *) NULL)
 | ||
|     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
 | ||
|   count=ReadBlob(image,length,stream);
 | ||
|   if (count != (ssize_t) length)
 | ||
|     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
 | ||
|   pixels=(unsigned char *) WebPDecodeRGBA(stream,length,&width,&height);
 | ||
|   if (pixels == (unsigned char *) NULL)
 | ||
|     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
 | ||
|   image->columns=(size_t) width;
 | ||
|   image->rows=(size_t) height;
 | ||
|   p=pixels;
 | ||
|   for (y=0; y < (ssize_t) image->rows; y++)
 | ||
|   {
 | ||
|     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
 | ||
|     if (q == (PixelPacket *) NULL)
 | ||
|       break;
 | ||
|     for (x=0; x < (ssize_t) image->columns; x++)
 | ||
|     {
 | ||
|       SetPixelRed(q,ScaleCharToQuantum(*p++));
 | ||
|       SetPixelGreen(q,ScaleCharToQuantum(*p++));
 | ||
|       SetPixelBlue(q,ScaleCharToQuantum(*p++));
 | ||
|       SetPixelAlpha(q,ScaleCharToQuantum(*p++));
 | ||
|       if (q->opacity != OpaqueOpacity)
 | ||
|         image->matte=MagickTrue;
 | ||
|       q++;
 | ||
|     }
 | ||
|     if (SyncAuthenticPixels(image,exception) == MagickFalse)
 | ||
|       break;
 | ||
|     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
 | ||
|       image->rows);
 | ||
|     if (status == MagickFalse)
 | ||
|       break;
 | ||
|   }
 | ||
|   free(pixels);
 | ||
|   pixels=(unsigned char *) NULL;
 | ||
|   return(image);
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| /*
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %   R e g i s t e r W E B P I m a g e                                         %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %
 | ||
| %  RegisterWEBPImage() adds attributes for the WebP 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 RegisterWEBPImage method is:
 | ||
| %
 | ||
| %      size_t RegisterWEBPImage(void)
 | ||
| %
 | ||
| */
 | ||
| ModuleExport size_t RegisterWEBPImage(void)
 | ||
| {
 | ||
|   MagickInfo
 | ||
|     *entry;
 | ||
| 
 | ||
|   entry=SetMagickInfo("WEBP");
 | ||
| #if defined(MAGICKCORE_WEBP_DELEGATE)
 | ||
|   entry->decoder=(DecodeImageHandler *) ReadWEBPImage;
 | ||
|   entry->encoder=(EncodeImageHandler *) WriteWEBPImage;
 | ||
| #endif
 | ||
|   entry->description=ConstantString("WebP Image Format");
 | ||
|   entry->adjoin=MagickFalse;
 | ||
|   entry->module=ConstantString("WEBP");
 | ||
|   (void) RegisterMagickInfo(entry);
 | ||
|   return(MagickImageCoderSignature);
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %   U n r e g i s t e r W E B P I m a g e                                     %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %
 | ||
| %  UnregisterWEBPImage() removes format registrations made by the WebP module
 | ||
| %  from the list of supported formats.
 | ||
| %
 | ||
| %  The format of the UnregisterWEBPImage method is:
 | ||
| %
 | ||
| %      UnregisterWEBPImage(void)
 | ||
| %
 | ||
| */
 | ||
| ModuleExport void UnregisterWEBPImage(void)
 | ||
| {
 | ||
|   (void) UnregisterMagickInfo("WEBP");
 | ||
| }
 | ||
| #if defined(MAGICKCORE_WEBP_DELEGATE)
 | ||
| 
 | ||
| /*
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %   W r i t e W E B P I m a g e                                               %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %                                                                             %
 | ||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | ||
| %
 | ||
| %  WriteWEBPImage() writes an image in the WebP image format.
 | ||
| %
 | ||
| %  The format of the WriteWEBPImage method is:
 | ||
| %
 | ||
| %      MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
 | ||
| %        Image *image)
 | ||
| %
 | ||
| %  A description of each parameter follows.
 | ||
| %
 | ||
| %    o image_info: the image info.
 | ||
| %
 | ||
| %    o image:  The image.
 | ||
| %
 | ||
| */
 | ||
| 
 | ||
| static int WebPWriter(const unsigned char *stream,size_t length,
 | ||
|   const WebPPicture *const picture)
 | ||
| {
 | ||
|   Image
 | ||
|     *image;
 | ||
| 
 | ||
|   image=(Image *) picture->custom_ptr;
 | ||
|   return(length != 0 ? (int) WriteBlob(image,length,stream) : 1);
 | ||
| }
 | ||
| 
 | ||
| static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
 | ||
|   Image *image)
 | ||
| {
 | ||
|   int
 | ||
|     webp_status;
 | ||
| 
 | ||
|   MagickBooleanType
 | ||
|     status;
 | ||
| 
 | ||
|   register const PixelPacket
 | ||
|     *restrict p;
 | ||
| 
 | ||
|   register ssize_t
 | ||
|     x;
 | ||
| 
 | ||
|   register unsigned char
 | ||
|     *restrict q;
 | ||
| 
 | ||
|   ssize_t
 | ||
|     y;
 | ||
| 
 | ||
|   unsigned char
 | ||
|     *pixels;
 | ||
| 
 | ||
|   WebPConfig
 | ||
|     configure;
 | ||
| 
 | ||
|   WebPPicture
 | ||
|     picture;
 | ||
| 
 | ||
|   WebPAuxStats
 | ||
|     statistics;
 | ||
| 
 | ||
|   /*
 | ||
|     Open output image file.
 | ||
|   */
 | ||
|   assert(image_info != (const ImageInfo *) NULL);
 | ||
|   assert(image_info->signature == MagickSignature);
 | ||
|   assert(image != (Image *) NULL);
 | ||
|   assert(image->signature == MagickSignature);
 | ||
|   if (image->debug != MagickFalse)
 | ||
|     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
 | ||
|   if ((image->columns > 16383) || (image->rows > 16383))
 | ||
|     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
 | ||
|   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
 | ||
|   if (status == MagickFalse)
 | ||
|     return(status);
 | ||
|   if (WebPPictureInit(&picture) == 0)
 | ||
|     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
 | ||
|   picture.writer=WebPWriter;
 | ||
|   picture.custom_ptr=(void *) image;
 | ||
|   picture.stats=(&statistics);
 | ||
|   picture.width=(int) image->columns;
 | ||
|   picture.height=(int) image->rows;
 | ||
|   if (WebPConfigInit(&configure) == 0)
 | ||
|     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
 | ||
|   if (image->quality != UndefinedCompressionQuality)
 | ||
|     configure.quality=(float) image->quality;
 | ||
|   if (WebPValidateConfig(&configure) == 0)
 | ||
|     ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile");
 | ||
|   /*
 | ||
|     Allocate memory for pixels.
 | ||
|   */
 | ||
|   pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
 | ||
|     (image->matte != MagickFalse ? 4 : 3)*image->rows*sizeof(*pixels));
 | ||
|   if (pixels == (unsigned char *) NULL)
 | ||
|     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
 | ||
|   /*
 | ||
|     Convert image to WebP raster pixels.
 | ||
|   */
 | ||
|   q=pixels;
 | ||
|   for (y=0; y < (ssize_t) image->rows; y++)
 | ||
|   {
 | ||
|     p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
 | ||
|     if (p == (PixelPacket *) NULL)
 | ||
|       break;
 | ||
|     for (x=0; x < (ssize_t) image->columns; x++)
 | ||
|     {
 | ||
|       *q++=ScaleQuantumToChar(GetPixelRed(p));
 | ||
|       *q++=ScaleQuantumToChar(GetPixelGreen(p));
 | ||
|       *q++=ScaleQuantumToChar(GetPixelBlue(p));
 | ||
|       if (image->matte != MagickFalse)
 | ||
|         *q++=ScaleQuantumToChar(GetPixelAlpha(p));
 | ||
|       p++;
 | ||
|     }
 | ||
|     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
 | ||
|       image->rows);
 | ||
|     if (status == MagickFalse)
 | ||
|       break;
 | ||
|   }
 | ||
|   if (image->matte == MagickFalse)
 | ||
|     webp_status=WebPPictureImportRGB(&picture,pixels,3*picture.width);
 | ||
|   else
 | ||
|     webp_status=WebPPictureImportRGBA(&picture,pixels,4*picture.width);
 | ||
|   pixels=(unsigned char *) RelinquishMagickMemory(pixels);
 | ||
|   webp_status=WebPEncode(&configure,&picture);
 | ||
|   WebPPictureFree(&picture);
 | ||
|   (void) CloseBlob(image);
 | ||
|   return(webp_status == 0 ? MagickFalse : MagickTrue);
 | ||
| }
 | ||
| #endif
 |