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