]> granicus.if.org Git - imagemagick/blob - coders/webp.c
(no commit message)
[imagemagick] / coders / webp.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         W   W  EEEEE  BBBB   PPPP                           %
7 %                         W   W  E      B   B  P   P                          %
8 %                         W W W  EEE    BBBB   PPPP                           %
9 %                         WW WW  E      B   B  P                              %
10 %                         W   W  EEEEE  BBBB   P                              %
11 %                                                                             %
12 %                                                                             %
13 %                         Read/Write WebP Image Format                        %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 March 2011                                  %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 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 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/client.h"
46 #include "MagickCore/display.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/image-private.h"
51 #include "MagickCore/list.h"
52 #include "MagickCore/magick.h"
53 #include "MagickCore/monitor.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/memory_.h"
56 #include "MagickCore/option.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/string-private.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/utility.h"
64 #include "MagickCore/xwindow.h"
65 #include "MagickCore/xwindow-private.h"
66 #if defined(MAGICKCORE_WEBP_DELEGATE)
67 #include <webp/decode.h>
68 #include <webp/encode.h>
69 #endif
70 \f
71 /*
72   Forward declarations.
73 */
74 #if defined(MAGICKCORE_WEBP_DELEGATE)
75 static MagickBooleanType
76   WriteWEBPImage(const ImageInfo *,Image *,ExceptionInfo *);
77 #endif
78 \f
79 /*
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %                                                                             %
82 %                                                                             %
83 %                                                                             %
84 %   I s W E B P                                                               %
85 %                                                                             %
86 %                                                                             %
87 %                                                                             %
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 %
90 %  IsWEBP() returns MagickTrue if the image format type, identified by the
91 %  magick string, is WebP.
92 %
93 %  The format of the IsWEBP method is:
94 %
95 %      MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length)
96 %
97 %  A description of each parameter follows:
98 %
99 %    o magick: compare image format pattern against these bytes.
100 %
101 %    o length: Specifies the length of the magick string.
102 %
103 */
104 static MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length)
105 {
106   if (length < 12)
107     return(MagickFalse);
108   if (LocaleNCompare((const char *) magick+8,"WEBP",4) == 0)
109     return(MagickTrue);
110   return(MagickFalse);
111 }
112 \f
113 #if defined(MAGICKCORE_WEBP_DELEGATE)
114 /*
115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 %                                                                             %
117 %                                                                             %
118 %                                                                             %
119 %   R e a d W E B P I m a g e                                                 %
120 %                                                                             %
121 %                                                                             %
122 %                                                                             %
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 %
125 %  ReadWEBPImage() reads an image in the WebP image format.
126 %
127 %  The format of the ReadWEBPImage method is:
128 %
129 %      Image *ReadWEBPImage(const ImageInfo *image_info,
130 %        ExceptionInfo *exception)
131 %
132 %  A description of each parameter follows:
133 %
134 %    o image_info: the image info.
135 %
136 %    o exception: return any errors or warnings in this structure.
137 %
138 */
139 static Image *ReadWEBPImage(const ImageInfo *image_info,
140   ExceptionInfo *exception)
141 {
142   Image
143     *image;
144
145   MagickBooleanType
146     status;
147
148   register unsigned char
149     *p;
150
151   size_t
152     length;
153
154   ssize_t
155     count,
156     y;
157
158   unsigned char
159     *stream;
160
161   WebPDecoderConfig
162     configure;
163
164   WebPDecBuffer
165     *const webp_image = &configure.output;
166
167   WebPBitstreamFeatures
168     *const features = &configure.input;
169
170   /*
171     Open image file.
172   */
173   assert(image_info != (const ImageInfo *) NULL);
174   assert(image_info->signature == MagickSignature);
175   if (image_info->debug != MagickFalse)
176     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
177       image_info->filename);
178   assert(exception != (ExceptionInfo *) NULL);
179   assert(exception->signature == MagickSignature);
180   image=AcquireImage(image_info,exception);
181   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
182   if (status == MagickFalse)
183     {
184       image=DestroyImageList(image);
185       return((Image *) NULL);
186     }
187   if (WebPInitDecoderConfig(&configure) == 0)
188     ThrowReaderException(ResourceLimitError,"UnableToDecodeImageFile");
189   length=(size_t) GetBlobSize(image);
190   stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
191   if (stream == (unsigned char *) NULL)
192     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
193   count=ReadBlob(image,length,stream);
194   if (count != (ssize_t) length)
195     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
196   if (WebPGetFeatures(stream,length,features) != 0)
197     {
198       stream=(unsigned char*) RelinquishMagickMemory(stream);
199       ThrowReaderException(ResourceLimitError,"UnableToDecodeImageFile");
200     }
201   webp_image->colorspace=MODE_RGBA;
202   if (WebPDecode(stream,length,&configure) != 0)
203     {
204       stream=(unsigned char*) RelinquishMagickMemory(stream);
205       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
206     }
207   image->columns=(size_t) webp_image->width;
208   image->rows=(size_t) webp_image->height;
209   image->alpha_trait=features->has_alpha != 0 ? BlendPixelTrait :
210     UndefinedPixelTrait;
211   if (stream[15] == 'L')
212     image->quality=100;
213   p=webp_image->u.RGBA.rgba;
214   for (y=0; y < (ssize_t) image->rows; y++)
215   {
216     register Quantum
217       *q;
218
219     register ssize_t
220       x;
221
222     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
223     if (q == (Quantum *) NULL)
224       break;
225     for (x=0; x < (ssize_t) image->columns; x++)
226     {
227       SetPixelRed(image,ScaleCharToQuantum(*p++),q);
228       SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
229       SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
230       SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
231       q+=GetPixelChannels(image);
232     }
233     if (SyncAuthenticPixels(image,exception) == MagickFalse)
234       break;
235     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
236       image->rows);
237     if (status == MagickFalse)
238       break;
239   }
240   WebPFreeDecBuffer(webp_image);
241   stream=(unsigned char*) RelinquishMagickMemory(stream);
242   return(image);
243 }
244 #endif
245 \f
246 /*
247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 %                                                                             %
249 %                                                                             %
250 %                                                                             %
251 %   R e g i s t e r W E B P I m a g e                                         %
252 %                                                                             %
253 %                                                                             %
254 %                                                                             %
255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256 %
257 %  RegisterWEBPImage() adds attributes for the WebP image format to
258 %  the list of supported formats.  The attributes include the image format
259 %  tag, a method to read and/or write the format, whether the format
260 %  supports the saving of more than one frame to the same file or blob,
261 %  whether the format supports native in-memory I/O, and a brief
262 %  description of the format.
263 %
264 %  The format of the RegisterWEBPImage method is:
265 %
266 %      size_t RegisterWEBPImage(void)
267 %
268 */
269 ModuleExport size_t RegisterWEBPImage(void)
270 {
271   char
272     version[MaxTextExtent];
273
274   MagickInfo
275     *entry;
276
277   *version='\0';
278   entry=SetMagickInfo("WEBP");
279 #if defined(MAGICKCORE_WEBP_DELEGATE)
280   entry->decoder=(DecodeImageHandler *) ReadWEBPImage;
281   entry->encoder=(EncodeImageHandler *) WriteWEBPImage;
282   (void) FormatLocaleString(version,MaxTextExtent,"libwebp %d.%d.%d",
283     (WebPGetDecoderVersion() >> 16) & 0xff,
284     (WebPGetDecoderVersion() >> 8) & 0xff,
285     (WebPGetDecoderVersion() >> 0) & 0xff);
286 #endif
287   entry->description=ConstantString("WebP Image Format");
288   entry->adjoin=MagickFalse;
289   entry->module=ConstantString("WEBP");
290   entry->magick=(IsImageFormatHandler *) IsWEBP;
291   if (*version != '\0')
292     entry->version=ConstantString(version);
293   (void) RegisterMagickInfo(entry);
294   return(MagickImageCoderSignature);
295 }
296 \f
297 /*
298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299 %                                                                             %
300 %                                                                             %
301 %                                                                             %
302 %   U n r e g i s t e r W E B P I m a g e                                     %
303 %                                                                             %
304 %                                                                             %
305 %                                                                             %
306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307 %
308 %  UnregisterWEBPImage() removes format registrations made by the WebP module
309 %  from the list of supported formats.
310 %
311 %  The format of the UnregisterWEBPImage method is:
312 %
313 %      UnregisterWEBPImage(void)
314 %
315 */
316 ModuleExport void UnregisterWEBPImage(void)
317 {
318   (void) UnregisterMagickInfo("WEBP");
319 }
320 #if defined(MAGICKCORE_WEBP_DELEGATE)
321 \f
322 /*
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324 %                                                                             %
325 %                                                                             %
326 %                                                                             %
327 %   W r i t e W E B P I m a g e                                               %
328 %                                                                             %
329 %                                                                             %
330 %                                                                             %
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 %
333 %  WriteWEBPImage() writes an image in the WebP image format.
334 %
335 %  The format of the WriteWEBPImage method is:
336 %
337 %      MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
338 %        Image *image)
339 %
340 %  A description of each parameter follows.
341 %
342 %    o image_info: the image info.
343 %
344 %    o image:  The image.
345 %
346 */
347
348 static int WebPWriter(const unsigned char *stream,size_t length,
349   const WebPPicture *const picture)
350 {
351   Image
352     *image;
353
354   image=(Image *) picture->custom_ptr;
355   return(length != 0 ? (int) WriteBlob(image,length,stream) : 1);
356 }
357
358 static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
359   Image *image,ExceptionInfo *exception)
360 {
361   const char
362     *value;
363
364   int
365     webp_status;
366
367   MagickBooleanType
368     status;
369
370   register uint32_t
371     *restrict q;
372
373   ssize_t
374     y;
375
376   WebPConfig
377     configure;
378
379   WebPPicture
380     picture;
381
382   WebPAuxStats
383     statistics;
384
385   /*
386     Open output image file.
387   */
388   assert(image_info != (const ImageInfo *) NULL);
389   assert(image_info->signature == MagickSignature);
390   assert(image != (Image *) NULL);
391   assert(image->signature == MagickSignature);
392   if (image->debug != MagickFalse)
393     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
394   if ((image->columns > 16383UL) || (image->rows > 16383UL))
395     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
396   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
397   if (status == MagickFalse)
398     return(status);
399   if ((WebPPictureInit(&picture) == 0) || (WebPConfigInit(&configure) == 0))
400     ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile");
401   picture.writer=WebPWriter;
402   picture.custom_ptr=(void *) image;
403   picture.stats=(&statistics);
404   picture.width=(int) image->columns;
405   picture.height=(int) image->rows;
406   picture.argb_stride=(int) image->columns;
407   picture.use_argb=1;
408   if (image->quality != UndefinedCompressionQuality)
409     configure.quality=(float) image->quality;
410   else
411     if (image->quality >= 100)
412       configure.lossless=1;
413   value=GetImageOption(image_info,"webp:lossless");
414   if (value != (char *) NULL)
415     configure.lossless=ParseCommandOption(MagickBooleanOptions,MagickFalse,
416       value);
417   value=GetImageOption(image_info,"webp:method");
418   if (value != (char *) NULL)
419     configure.method=StringToInteger(value);
420   value=GetImageOption(image_info,"webp:image-hint");
421   if (value != (char *) NULL)
422     {
423       if (LocaleCompare(value,"graph") == 0)
424         configure.image_hint=WEBP_HINT_GRAPH;
425       if (LocaleCompare(value,"photo") == 0)
426         configure.image_hint=WEBP_HINT_PHOTO;
427       if (LocaleCompare(value,"picture") == 0)
428         configure.image_hint=WEBP_HINT_PICTURE;
429     }
430   value=GetImageOption(image_info,"webp:target-size");
431   if (value != (char *) NULL)
432     configure.target_size=StringToInteger(value);
433   value=GetImageOption(image_info,"webp:target-psnr");
434   if (value != (char *) NULL)
435     configure.target_PSNR=(float) StringToDouble(value,(char **) NULL);
436   value=GetImageOption(image_info,"webp:segments");
437   if (value != (char *) NULL)
438     configure.segments=StringToInteger(value);
439   value=GetImageOption(image_info,"webp:sns-strength");
440   if (value != (char *) NULL)
441     configure.sns_strength=StringToInteger(value);
442   value=GetImageOption(image_info,"webp:filter-strength");
443   if (value != (char *) NULL)
444     configure.filter_strength=StringToInteger(value);
445   value=GetImageOption(image_info,"webp:filter-sharpness");
446   if (value != (char *) NULL)
447     configure.filter_sharpness=StringToInteger(value);
448   value=GetImageOption(image_info,"webp:filter-type");
449   if (value != (char *) NULL)
450     configure.filter_type=StringToInteger(value);
451   value=GetImageOption(image_info,"webp:auto-filter");
452   if (value != (char *) NULL)
453     configure.autofilter=ParseCommandOption(MagickBooleanOptions,MagickFalse,
454       value);
455   value=GetImageOption(image_info,"webp:alpha-compression");
456   if (value != (char *) NULL)
457     configure.alpha_compression=StringToInteger(value);
458   value=GetImageOption(image_info,"webp:alpha-filtering");
459   if (value != (char *) NULL)
460     configure.alpha_filtering=StringToInteger(value);
461   value=GetImageOption(image_info,"webp:alpha-quality");
462   if (value != (char *) NULL)
463     configure.alpha_quality=StringToInteger(value);
464   value=GetImageOption(image_info,"webp:pass");
465   if (value != (char *) NULL)
466     configure.pass=StringToInteger(value);
467   value=GetImageOption(image_info,"webp:show-compressed");
468   if (value != (char *) NULL)
469     configure.show_compressed=StringToInteger(value);
470   value=GetImageOption(image_info,"webp:preprocessing");
471   if (value != (char *) NULL)
472     configure.preprocessing=StringToInteger(value);
473   value=GetImageOption(image_info,"webp:partitions");
474   if (value != (char *) NULL)
475     configure.partitions=StringToInteger(value);
476   value=GetImageOption(image_info,"webp:partition-limit");
477   if (value != (char *) NULL)
478     configure.partition_limit=StringToInteger(value);
479   if (WebPValidateConfig(&configure) == 0)
480     ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile");
481   /*
482     Allocate memory for pixels.
483   */
484   picture.argb=(uint32_t *) AcquireQuantumMemory(image->columns,image->rows*
485     sizeof(*picture.argb));
486   if (picture.argb == (uint32_t *) NULL)
487     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
488   /*
489     Convert image to WebP raster pixels.
490   */
491   q=picture.argb;
492   for (y=0; y < (ssize_t) image->rows; y++)
493   {
494     register const Quantum
495       *restrict p;
496
497     register ssize_t
498       x;
499
500     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
501     if (p == (const Quantum *) NULL)
502       break;
503     for (x=0; x < (ssize_t) image->columns; x++)
504     {
505       *q++=(uint32_t) (image->alpha_trait == BlendPixelTrait ?
506         ScaleQuantumToChar(GetPixelAlpha(image,p)) << 24 : 0xff000000u) |
507         (ScaleQuantumToChar(GetPixelRed(image,p)) << 16) |
508         (ScaleQuantumToChar(GetPixelGreen(image,p)) << 8) |
509         (ScaleQuantumToChar(GetPixelBlue(image,p)));
510       p+=GetPixelChannels(image);
511     }
512     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
513       image->rows);
514     if (status == MagickFalse)
515       break;
516   }
517   webp_status=WebPEncode(&configure,&picture);
518   WebPPictureFree(&picture);
519   picture.argb=(uint32_t *) RelinquishMagickMemory(picture.argb);
520   (void) CloseBlob(image);
521   return(webp_status == 0 ? MagickFalse : MagickTrue);
522 }
523 #endif