blob: 7751534afcf9acfa841aa0b695903cb4539b4bb1 [file] [log] [blame]
cristyb1860752011-03-14 00:27:46 +00001/*
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-2011 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
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/client.h"
46#include "magick/display.h"
47#include "magick/exception.h"
48#include "magick/exception-private.h"
49#include "magick/image.h"
50#include "magick/image-private.h"
51#include "magick/list.h"
52#include "magick/magick.h"
cristy644040e2011-03-14 17:31:59 +000053#include "magick/monitor.h"
54#include "magick/monitor-private.h"
cristyb1860752011-03-14 00:27:46 +000055#include "magick/memory_.h"
56#include "magick/option.h"
57#include "magick/quantum-private.h"
58#include "magick/static.h"
59#include "magick/string_.h"
60#include "magick/module.h"
61#include "magick/utility.h"
62#include "magick/xwindow.h"
63#include "magick/xwindow-private.h"
cristy644040e2011-03-14 17:31:59 +000064#if defined(MAGICKCORE_WEBP_DELEGATE)
65#include <webp/decode.h>
66#include <webp/encode.h>
67#endif
cristyb1860752011-03-14 00:27:46 +000068
69/*
70 Forward declarations.
71*/
72#if defined(MAGICKCORE_WEBP_DELEGATE)
73static MagickBooleanType
74 WriteWEBPImage(const ImageInfo *,Image *);
75#endif
76
77#if defined(MAGICKCORE_WEBP_DELEGATE)
78/*
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80% %
81% %
82% %
83% R e a d W E B P I m a g e %
84% %
85% %
86% %
87%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88%
89% ReadWEBPImage() reads an image in the WebP image format.
90%
91% The format of the ReadWEBPImage method is:
92%
93% Image *ReadWEBPImage(const ImageInfo *image_info,
94% ExceptionInfo *exception)
95%
96% A description of each parameter follows:
97%
98% o image_info: the image info.
99%
100% o exception: return any errors or warnings in this structure.
101%
102*/
103static Image *ReadWEBPImage(const ImageInfo *image_info,
104 ExceptionInfo *exception)
105{
cristy644040e2011-03-14 17:31:59 +0000106 int
107 height,
108 width;
109
cristyffa663d2011-03-14 00:58:51 +0000110 Image
111 *image;
112
113 MagickBooleanType
114 status;
115
cristy644040e2011-03-14 17:31:59 +0000116 register PixelPacket
117 *q;
118
119 register ssize_t
120 x;
121
122 register unsigned char
123 *p;
124
125 size_t
126 length;
127
128 ssize_t
129 count,
130 y;
131
132 unsigned char
133 *stream,
134 *pixels;
135
cristyffa663d2011-03-14 00:58:51 +0000136 /*
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);
147 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
148 if (status == MagickFalse)
149 {
150 image=DestroyImageList(image);
151 return((Image *) NULL);
152 }
cristy644040e2011-03-14 17:31:59 +0000153 length=(size_t) GetBlobSize(image);
154 stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
155 if (stream == (unsigned char *) NULL)
156 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
157 count=ReadBlob(image,length,stream);
158 if (count != (ssize_t) length)
159 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
160 pixels=(unsigned char *) WebPDecodeRGBA(stream,length,&width,&height);
161 if (pixels == (unsigned char *) NULL)
162 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
163 image->columns=(size_t) width;
164 image->rows=(size_t) height;
165 p=pixels;
166 for (y=0; y < (ssize_t) image->rows; y++)
167 {
168 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
169 if (q == (PixelPacket *) NULL)
170 break;
171 for (x=0; x < (ssize_t) image->columns; x++)
172 {
173 q->red=ScaleCharToQuantum(*p++);
174 q->green=ScaleCharToQuantum(*p++);
175 q->blue=ScaleCharToQuantum(*p++);
176 q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(*p++));
177 if (q->opacity != OpaqueOpacity)
178 image->matte=MagickTrue;
179 q++;
180 }
181 if (SyncAuthenticPixels(image,exception) == MagickFalse)
182 break;
183 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
184 image->rows);
185 if (status == MagickFalse)
186 break;
187 }
188 free(pixels);
189 pixels=(unsigned char *) NULL;
cristyffa663d2011-03-14 00:58:51 +0000190 return(image);
cristyb1860752011-03-14 00:27:46 +0000191}
192#endif
193
194/*
195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196% %
197% %
198% %
199% R e g i s t e r W E B P I m a g e %
200% %
201% %
202% %
203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204%
205% RegisterWEBPImage() adds attributes for the WebP image format to
206% the list of supported formats. The attributes include the image format
207% tag, a method to read and/or write the format, whether the format
208% supports the saving of more than one frame to the same file or blob,
209% whether the format supports native in-memory I/O, and a brief
210% description of the format.
211%
212% The format of the RegisterWEBPImage method is:
213%
214% size_t RegisterWEBPImage(void)
215%
216*/
217ModuleExport size_t RegisterWEBPImage(void)
218{
219 MagickInfo
220 *entry;
221
cristy25ba0c02011-03-14 00:54:32 +0000222 entry=SetMagickInfo("WEBP");
cristyb1860752011-03-14 00:27:46 +0000223#if defined(MAGICKCORE_WEBP_DELEGATE)
224 entry->decoder=(DecodeImageHandler *) ReadWEBPImage;
225 entry->encoder=(EncodeImageHandler *) WriteWEBPImage;
226#endif
cristyb1860752011-03-14 00:27:46 +0000227 entry->description=ConstantString("WebP Image Format");
cristy644040e2011-03-14 17:31:59 +0000228 entry->adjoin=MagickFalse;
cristyb1860752011-03-14 00:27:46 +0000229 entry->module=ConstantString("WEBP");
230 (void) RegisterMagickInfo(entry);
231 return(MagickImageCoderSignature);
232}
233
234/*
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236% %
237% %
238% %
239% U n r e g i s t e r W E B P I m a g e %
240% %
241% %
242% %
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244%
245% UnregisterWEBPImage() removes format registrations made by the WebP module
246% from the list of supported formats.
247%
248% The format of the UnregisterWEBPImage method is:
249%
250% UnregisterWEBPImage(void)
251%
252*/
253ModuleExport void UnregisterWEBPImage(void)
254{
255 (void) UnregisterMagickInfo("WEBP");
256}
257#if defined(MAGICKCORE_WEBP_DELEGATE)
258
259/*
260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261% %
262% %
263% %
264% W r i t e W E B P I m a g e %
265% %
266% %
267% %
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269%
270% WriteWEBPImage() writes an image in the WebP image format.
271%
272% The format of the WriteWEBPImage method is:
273%
274% MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
275% Image *image)
276%
277% A description of each parameter follows.
278%
279% o image_info: the image info.
280%
281% o image: The image.
282%
283*/
cristy644040e2011-03-14 17:31:59 +0000284
285static int WebPWriter(const unsigned char *stream,size_t length,
286 const WebPPicture *const picture)
287{
288 Image
289 *image;
290
291 image=(Image *) picture->custom_ptr;
292 return(length != 0 ? (int) WriteBlob(image,length,stream) : 1);
293}
294
cristyb1860752011-03-14 00:27:46 +0000295static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info,
296 Image *image)
297{
cristy644040e2011-03-14 17:31:59 +0000298 int
299 webp_status;
300
cristyffa663d2011-03-14 00:58:51 +0000301 MagickBooleanType
302 status;
303
cristy644040e2011-03-14 17:31:59 +0000304 register const PixelPacket
305 *restrict p;
306
307 register ssize_t
308 x;
309
310 register unsigned char
311 *restrict q;
312
313 ssize_t
314 y;
315
316 unsigned char
317 *pixels;
318
319 WebPConfig
320 configure;
321
322 WebPPicture
323 picture;
324
325 WebPAuxStats
326 statistics;
327
cristyffa663d2011-03-14 00:58:51 +0000328 /*
329 Open output image file.
330 */
331 assert(image_info != (const ImageInfo *) NULL);
332 assert(image_info->signature == MagickSignature);
333 assert(image != (Image *) NULL);
334 assert(image->signature == MagickSignature);
335 if (image->debug != MagickFalse)
336 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
337 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
338 if (status == MagickFalse)
339 return(status);
cristy644040e2011-03-14 17:31:59 +0000340 if (WebPPictureInit(&picture) == 0)
341 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
342 picture.writer=WebPWriter;
343 picture.custom_ptr=(void *) image;
344 picture.stats=(&statistics);
345 picture.width=(int) image->columns;
346 picture.height=(int) image->rows;
347 if (image->quality != UndefinedCompressionQuality)
348 configure.quality=(float) image->quality;
349 if (WebPConfigInit(&configure) == 0)
350 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
351 /*
352 Future: set custom configuration parameters here.
353 */
354 if (WebPValidateConfig(&configure) == 0)
355 ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile");
356 /*
357 Allocate memory for pixels.
358 */
359 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
360 (image->matte != MagickFalse ? 4 : 3)*image->rows*sizeof(*pixels));
361 if (pixels == (unsigned char *) NULL)
362 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
363 /*
364 Convert image to WebP raster pixels.
365 */
366 q=pixels;
367 for (y=0; y < (ssize_t) image->rows; y++)
368 {
369 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
370 if (p == (PixelPacket *) NULL)
371 break;
372 for (x=0; x < (ssize_t) image->columns; x++)
373 {
374 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
375 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
376 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
377 if (image->matte != MagickFalse)
378 *q++=ScaleQuantumToChar((Quantum) (QuantumRange-
cristyd05ecd12011-04-22 20:44:42 +0000379 (image->matte != MagickFalse ? GetOpacityPixelComponent(p) : OpaqueOpacity)));
cristy644040e2011-03-14 17:31:59 +0000380 p++;
381 }
382 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
383 image->rows);
384 if (status == MagickFalse)
385 break;
386 }
387 if (image->matte == MagickFalse)
388 webp_status=WebPPictureImportRGB(&picture,pixels,3*picture.width);
389 else
390 webp_status=WebPPictureImportRGBA(&picture,pixels,4*picture.width);
391 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
392 webp_status=WebPEncode(&configure,&picture);
393 (void) CloseBlob(image);
394 return(webp_status == 0 ? MagickFalse : MagickTrue);
cristyb1860752011-03-14 00:27:46 +0000395}
396#endif