]> granicus.if.org Git - imagemagick/blobdiff - coders/webp.c
(no commit message)
[imagemagick] / coders / webp.c
index 2ad9c6a4853440415a8b1191f395be13ba509ac4..a56317e112f6c90e0b43bf514fc68ef8a1bc8ca5 100644 (file)
@@ -76,6 +76,40 @@ static MagickBooleanType
   WriteWEBPImage(const ImageInfo *,Image *,ExceptionInfo *);
 #endif
 \f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s W E B P                                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsWEBP() returns MagickTrue if the image format type, identified by the
+%  magick string, is WebP.
+%
+%  The format of the IsWEBP method is:
+%
+%      MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o magick: compare image format pattern against these bytes.
+%
+%    o length: Specifies the length of the magick string.
+%
+*/
+static MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length)
+{
+  if (length < 12)
+    return(MagickFalse);
+  if (LocaleNCompare((const char *) magick+8,"WEBP",4) == 0)
+    return(MagickTrue);
+  return(MagickFalse);
+}
+\f
 #if defined(MAGICKCORE_WEBP_DELEGATE)
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -102,6 +136,68 @@ static MagickBooleanType
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
+static inline uint32_t ReadWebPLSBWord(const unsigned char *restrict data)
+{
+  register const unsigned char
+    *p;
+
+  register uint32_t
+    value;
+
+  p=data;
+  value=(uint32_t) (*p++);
+  value|=((uint32_t) (*p++)) << 8;
+  value|=((uint32_t) (*p++)) << 16;
+  value|=((uint32_t) (*p++)) << 24;
+  return(value);
+}
+
+static MagickBooleanType IsWEBPImageLossless(const unsigned char *stream,
+  const size_t length)
+{
+#define VP8_CHUNK_INDEX  15
+#define LOSSLESS_FLAG  'L'
+#define EXTENDED_HEADER  'X'
+#define VP8_CHUNK_HEADER  "VP8"
+#define VP8_CHUNK_HEADER_SIZE  3
+#define RIFF_HEADER_SIZE  12
+#define VP8X_CHUNK_SIZE  10
+#define TAG_SIZE  4
+#define CHUNK_SIZE_BYTES  4
+#define CHUNK_HEADER_SIZE  8
+#define MAX_CHUNK_PAYLOAD  (~0U-CHUNK_HEADER_SIZE-1)
+
+  ssize_t
+    offset;
+
+  /*
+    Read simple header.
+  */
+  if (stream[VP8_CHUNK_INDEX] != EXTENDED_HEADER)
+   return(stream[VP8_CHUNK_INDEX] == LOSSLESS_FLAG ? MagickTrue : MagickFalse);
+  /*
+    Read extended header.
+  */
+  offset=RIFF_HEADER_SIZE+TAG_SIZE+CHUNK_SIZE_BYTES+VP8X_CHUNK_SIZE;
+  while (offset <= length)
+  {
+    uint32_t
+      chunk_size,
+      chunk_size_pad;
+
+    chunk_size=ReadWebPLSBWord(stream+pos+TAG_SIZE);
+    if (chunk_size > MAX_CHUNK_PAYLOAD)
+      break;
+    chunk_size_pad=(CHUNK_HEADER_SIZE+chunk_size+1) & ~1;
+    if (memcmp( stream+offset,VP8_CHUNK_HEADER,VP8_CHUNK_HEADER_SIZE) == 0)
+      return*(stream+offset+VP8_CHUNK_HEADER_SIZE) == LOSSLESS_FLAG ?
+        MagickTrue : MagickFalse);
+    offset+=chunk_size_pad;
+  }
+  return(MagickFalse);
+}
+
 static Image *ReadWEBPImage(const ImageInfo *image_info,
   ExceptionInfo *exception)
 {
@@ -128,10 +224,10 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
     configure;
 
   WebPDecBuffer
-    *const webp_image = &configure.output;
+    *restrict webp_image = &configure.output;
 
   WebPBitstreamFeatures
-    *const features = &configure.input;
+    *restrict features = &configure.input;
 
   /*
     Open image file.
@@ -174,7 +270,7 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
   image->rows=(size_t) webp_image->height;
   image->alpha_trait=features->has_alpha != 0 ? BlendPixelTrait :
     UndefinedPixelTrait;
-  if ((stream[15] == 'L') || (stream[15] == ' '))
+  if (IsWEBPImageLossless(stream,length) != MagickFalse)
     image->quality=100;
   p=webp_image->u.RGBA.rgba;
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -253,6 +349,7 @@ ModuleExport size_t RegisterWEBPImage(void)
   entry->description=ConstantString("WebP Image Format");
   entry->adjoin=MagickFalse;
   entry->module=ConstantString("WEBP");
+  entry->magick=(IsImageFormatHandler *) IsWEBP;
   if (*version != '\0')
     entry->version=ConstantString(version);
   (void) RegisterMagickInfo(entry);
@@ -356,7 +453,7 @@ static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if ((image->columns > 16383) || (image->rows > 16383))
+  if ((image->columns > 16383UL) || (image->rows > 16383UL))
     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
@@ -377,13 +474,21 @@ static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
       configure.lossless=1;
   value=GetImageOption(image_info,"webp:lossless");
   if (value != (char *) NULL)
-   configure.lossless=StringToInteger(value);
+    configure.lossless=ParseCommandOption(MagickBooleanOptions,MagickFalse,
+      value);
   value=GetImageOption(image_info,"webp:method");
   if (value != (char *) NULL)
     configure.method=StringToInteger(value);
   value=GetImageOption(image_info,"webp:image-hint");
   if (value != (char *) NULL)
-    configure.image_hint=(WebPImageHint) StringToInteger(value);
+    {
+      if (LocaleCompare(value,"graph") == 0)
+        configure.image_hint=WEBP_HINT_GRAPH;
+      if (LocaleCompare(value,"photo") == 0)
+        configure.image_hint=WEBP_HINT_PHOTO;
+      if (LocaleCompare(value,"picture") == 0)
+        configure.image_hint=WEBP_HINT_PICTURE;
+    }
   value=GetImageOption(image_info,"webp:target-size");
   if (value != (char *) NULL)
     configure.target_size=StringToInteger(value);
@@ -405,9 +510,10 @@ static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
   value=GetImageOption(image_info,"webp:filter-type");
   if (value != (char *) NULL)
     configure.filter_type=StringToInteger(value);
-  value=GetImageOption(image_info,"webp:autofilter");
+  value=GetImageOption(image_info,"webp:auto-filter");
   if (value != (char *) NULL)
-    configure.autofilter=StringToInteger(value);
+    configure.autofilter=ParseCommandOption(MagickBooleanOptions,MagickFalse,
+      value);
   value=GetImageOption(image_info,"webp:alpha-compression");
   if (value != (char *) NULL)
     configure.alpha_compression=StringToInteger(value);