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 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/blob-private.h" 46#include "MagickCore/client.h" 47#include "MagickCore/colorspace-private.h" 48#include "MagickCore/display.h" 49#include "MagickCore/exception.h" 50#include "MagickCore/exception-private.h" 51#include "MagickCore/image.h" 52#include "MagickCore/image-private.h" 53#include "MagickCore/list.h" 54#include "MagickCore/magick.h" 55#include "MagickCore/monitor.h" 56#include "MagickCore/monitor-private.h" 57#include "MagickCore/memory_.h" 58#include "MagickCore/option.h" 59#include "MagickCore/pixel-accessor.h" 60#include "MagickCore/quantum-private.h" 61#include "MagickCore/static.h" 62#include "MagickCore/string_.h" 63#include "MagickCore/string-private.h" 64#include "MagickCore/module.h" 65#include "MagickCore/utility.h" 66#include "MagickCore/xwindow.h" 67#include "MagickCore/xwindow-private.h" 68#if defined(MAGICKCORE_WEBP_DELEGATE) 69#include <webp/decode.h> 70#include <webp/encode.h> 71#endif 72 73/* 74 Forward declarations. 75*/ 76#if defined(MAGICKCORE_WEBP_DELEGATE) 77static MagickBooleanType 78 WriteWEBPImage(const ImageInfo *,Image *,ExceptionInfo *); 79#endif 80 81/* 82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83% % 84% % 85% % 86% I s W E B P % 87% % 88% % 89% % 90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91% 92% IsWEBP() returns MagickTrue if the image format type, identified by the 93% magick string, is WebP. 94% 95% The format of the IsWEBP method is: 96% 97% MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length) 98% 99% A description of each parameter follows: 100% 101% o magick: compare image format pattern against these bytes. 102% 103% o length: Specifies the length of the magick string. 104% 105*/ 106static MagickBooleanType IsWEBP(const unsigned char *magick,const size_t length) 107{ 108 if (length < 12) 109 return(MagickFalse); 110 if (LocaleNCompare((const char *) magick+8,"WEBP",4) == 0) 111 return(MagickTrue); 112 return(MagickFalse); 113} 114 115#if defined(MAGICKCORE_WEBP_DELEGATE) 116/* 117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118% % 119% % 120% % 121% R e a d W E B P I m a g e % 122% % 123% % 124% % 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126% 127% ReadWEBPImage() reads an image in the WebP image format. 128% 129% The format of the ReadWEBPImage method is: 130% 131% Image *ReadWEBPImage(const ImageInfo *image_info, 132% ExceptionInfo *exception) 133% 134% A description of each parameter follows: 135% 136% o image_info: the image info. 137% 138% o exception: return any errors or warnings in this structure. 139% 140*/ 141 142static inline uint32_t ReadWebPLSBWord( 143 const unsigned char *magick_restrict data) 144{ 145 register const unsigned char 146 *p; 147 148 register uint32_t 149 value; 150 151 p=data; 152 value=(uint32_t) (*p++); 153 value|=((uint32_t) (*p++)) << 8; 154 value|=((uint32_t) (*p++)) << 16; 155 value|=((uint32_t) (*p++)) << 24; 156 return(value); 157} 158 159static MagickBooleanType IsWEBPImageLossless(const unsigned char *stream, 160 const size_t length) 161{ 162#define VP8_CHUNK_INDEX 15 163#define LOSSLESS_FLAG 'L' 164#define EXTENDED_HEADER 'X' 165#define VP8_CHUNK_HEADER "VP8" 166#define VP8_CHUNK_HEADER_SIZE 3 167#define RIFF_HEADER_SIZE 12 168#define VP8X_CHUNK_SIZE 10 169#define TAG_SIZE 4 170#define CHUNK_SIZE_BYTES 4 171#define CHUNK_HEADER_SIZE 8 172#define MAX_CHUNK_PAYLOAD (~0U-CHUNK_HEADER_SIZE-1) 173 174 ssize_t 175 offset; 176 177 /* 178 Read simple header. 179 */ 180 if (stream[VP8_CHUNK_INDEX] != EXTENDED_HEADER) 181 return(stream[VP8_CHUNK_INDEX] == LOSSLESS_FLAG ? MagickTrue : MagickFalse); 182 /* 183 Read extended header. 184 */ 185 offset=RIFF_HEADER_SIZE+TAG_SIZE+CHUNK_SIZE_BYTES+VP8X_CHUNK_SIZE; 186 while (offset <= (ssize_t) length) 187 { 188 uint32_t 189 chunk_size, 190 chunk_size_pad; 191 192 chunk_size=ReadWebPLSBWord(stream+offset+TAG_SIZE); 193 if (chunk_size > MAX_CHUNK_PAYLOAD) 194 break; 195 chunk_size_pad=(CHUNK_HEADER_SIZE+chunk_size+1) & ~1; 196 if (memcmp(stream+offset,VP8_CHUNK_HEADER,VP8_CHUNK_HEADER_SIZE) == 0) 197 return(*(stream+offset+VP8_CHUNK_HEADER_SIZE) == LOSSLESS_FLAG ? 198 MagickTrue : MagickFalse); 199 offset+=chunk_size_pad; 200 } 201 return(MagickFalse); 202} 203 204static Image *ReadWEBPImage(const ImageInfo *image_info, 205 ExceptionInfo *exception) 206{ 207 Image 208 *image; 209 210 int 211 webp_status; 212 213 MagickBooleanType 214 status; 215 216 register unsigned char 217 *p; 218 219 size_t 220 length; 221 222 ssize_t 223 count, 224 y; 225 226 unsigned char 227 header[12], 228 *stream; 229 230 WebPDecoderConfig 231 configure; 232 233 WebPDecBuffer 234 *magick_restrict webp_image = &configure.output; 235 236 WebPBitstreamFeatures 237 *magick_restrict features = &configure.input; 238 239 /* 240 Open image file. 241 */ 242 assert(image_info != (const ImageInfo *) NULL); 243 assert(image_info->signature == MagickCoreSignature); 244 if (image_info->debug != MagickFalse) 245 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 246 image_info->filename); 247 assert(exception != (ExceptionInfo *) NULL); 248 assert(exception->signature == MagickCoreSignature); 249 image=AcquireImage(image_info,exception); 250 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 251 if (status == MagickFalse) 252 { 253 image=DestroyImageList(image); 254 return((Image *) NULL); 255 } 256 if (WebPInitDecoderConfig(&configure) == 0) 257 ThrowReaderException(ResourceLimitError,"UnableToDecodeImageFile"); 258 webp_image->colorspace=MODE_RGBA; 259 count=ReadBlob(image,12,header); 260 if (count != 12) 261 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 262 status=IsWEBP(header,count); 263 if (status == MagickFalse) 264 ThrowReaderException(CorruptImageError,"CorruptImage"); 265 length=(size_t) (ReadWebPLSBWord(header+4)+8); 266 if (length < 12) 267 ThrowReaderException(CorruptImageError,"CorruptImage"); 268 stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream)); 269 if (stream == (unsigned char *) NULL) 270 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 271 memcpy(stream,header,12); 272 count=ReadBlob(image,length-12,stream+12); 273 if (count != (ssize_t) (length-12)) 274 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 275 webp_status=WebPGetFeatures(stream,length,features); 276 if (webp_status == VP8_STATUS_OK) 277 { 278 image->columns=(size_t) features->width; 279 image->rows=(size_t) features->height; 280 image->depth=8; 281 image->alpha_trait=features->has_alpha != 0 ? BlendPixelTrait : 282 UndefinedPixelTrait; 283 if (image_info->ping != MagickFalse) 284 { 285 stream=(unsigned char*) RelinquishMagickMemory(stream); 286 (void) CloseBlob(image); 287 return(GetFirstImageInList(image)); 288 } 289 status=SetImageExtent(image,image->columns,image->rows,exception); 290 if (status == MagickFalse) 291 return(DestroyImageList(image)); 292 webp_status=WebPDecode(stream,length,&configure); 293 } 294 if (webp_status != VP8_STATUS_OK) 295 { 296 stream=(unsigned char*) RelinquishMagickMemory(stream); 297 switch (webp_status) 298 { 299 case VP8_STATUS_OUT_OF_MEMORY: 300 { 301 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 302 break; 303 } 304 case VP8_STATUS_INVALID_PARAM: 305 { 306 ThrowReaderException(CorruptImageError,"invalid parameter"); 307 break; 308 } 309 case VP8_STATUS_BITSTREAM_ERROR: 310 { 311 ThrowReaderException(CorruptImageError,"CorruptImage"); 312 break; 313 } 314 case VP8_STATUS_UNSUPPORTED_FEATURE: 315 { 316 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported"); 317 break; 318 } 319 case VP8_STATUS_SUSPENDED: 320 { 321 ThrowReaderException(CorruptImageError,"decoder suspended"); 322 break; 323 } 324 case VP8_STATUS_USER_ABORT: 325 { 326 ThrowReaderException(CorruptImageError,"user abort"); 327 break; 328 } 329 case VP8_STATUS_NOT_ENOUGH_DATA: 330 { 331 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 332 break; 333 } 334 default: 335 ThrowReaderException(CorruptImageError,"CorruptImage"); 336 } 337 } 338 if (IsWEBPImageLossless(stream,length) != MagickFalse) 339 image->quality=100; 340 p=(unsigned char *) webp_image->u.RGBA.rgba; 341 for (y=0; y < (ssize_t) image->rows; y++) 342 { 343 register Quantum 344 *q; 345 346 register ssize_t 347 x; 348 349 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 350 if (q == (Quantum *) NULL) 351 break; 352 for (x=0; x < (ssize_t) image->columns; x++) 353 { 354 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 355 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 356 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 357 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q); 358 q+=GetPixelChannels(image); 359 } 360 if (SyncAuthenticPixels(image,exception) == MagickFalse) 361 break; 362 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 363 image->rows); 364 if (status == MagickFalse) 365 break; 366 } 367 WebPFreeDecBuffer(webp_image); 368 stream=(unsigned char*) RelinquishMagickMemory(stream); 369 return(image); 370} 371#endif 372 373/* 374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 375% % 376% % 377% % 378% R e g i s t e r W E B P I m a g e % 379% % 380% % 381% % 382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 383% 384% RegisterWEBPImage() adds attributes for the WebP image format to 385% the list of supported formats. The attributes include the image format 386% tag, a method to read and/or write the format, whether the format 387% supports the saving of more than one frame to the same file or blob, 388% whether the format supports native in-memory I/O, and a brief 389% description of the format. 390% 391% The format of the RegisterWEBPImage method is: 392% 393% size_t RegisterWEBPImage(void) 394% 395*/ 396ModuleExport size_t RegisterWEBPImage(void) 397{ 398 char 399 version[MagickPathExtent]; 400 401 MagickInfo 402 *entry; 403 404 *version='\0'; 405 entry=AcquireMagickInfo("WEBP","WEBP","WebP Image Format"); 406#if defined(MAGICKCORE_WEBP_DELEGATE) 407 entry->decoder=(DecodeImageHandler *) ReadWEBPImage; 408 entry->encoder=(EncodeImageHandler *) WriteWEBPImage; 409 (void) FormatLocaleString(version,MagickPathExtent,"libwebp %d.%d.%d [%04X]", 410 (WebPGetDecoderVersion() >> 16) & 0xff, 411 (WebPGetDecoderVersion() >> 8) & 0xff, 412 (WebPGetDecoderVersion() >> 0) & 0xff,WEBP_DECODER_ABI_VERSION); 413#endif 414 entry->mime_type=ConstantString("image/webp"); 415 entry->flags^=CoderAdjoinFlag; 416 entry->magick=(IsImageFormatHandler *) IsWEBP; 417 if (*version != '\0') 418 entry->version=ConstantString(version); 419 (void) RegisterMagickInfo(entry); 420 return(MagickImageCoderSignature); 421} 422 423/* 424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 425% % 426% % 427% % 428% U n r e g i s t e r W E B P I m a g e % 429% % 430% % 431% % 432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 433% 434% UnregisterWEBPImage() removes format registrations made by the WebP module 435% from the list of supported formats. 436% 437% The format of the UnregisterWEBPImage method is: 438% 439% UnregisterWEBPImage(void) 440% 441*/ 442ModuleExport void UnregisterWEBPImage(void) 443{ 444 (void) UnregisterMagickInfo("WEBP"); 445} 446#if defined(MAGICKCORE_WEBP_DELEGATE) 447 448/* 449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 450% % 451% % 452% % 453% W r i t e W E B P I m a g e % 454% % 455% % 456% % 457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 458% 459% WriteWEBPImage() writes an image in the WebP image format. 460% 461% The format of the WriteWEBPImage method is: 462% 463% MagickBooleanType WriteWEBPImage(const ImageInfo *image_info, 464% Image *image) 465% 466% A description of each parameter follows. 467% 468% o image_info: the image info. 469% 470% o image: The image. 471% 472*/ 473 474#if WEBP_DECODER_ABI_VERSION >= 0x0100 475static int WebPEncodeProgress(int percent,const WebPPicture* picture) 476{ 477#define EncodeImageTag "Encode/Image" 478 479 Image 480 *image; 481 482 MagickBooleanType 483 status; 484 485 image=(Image *) picture->custom_ptr; 486 status=SetImageProgress(image,EncodeImageTag,percent-1,100); 487 return(status == MagickFalse ? 0 : 1); 488} 489#endif 490 491static int WebPEncodeWriter(const unsigned char *stream,size_t length, 492 const WebPPicture *const picture) 493{ 494 Image 495 *image; 496 497 image=(Image *) picture->custom_ptr; 498 return(length != 0 ? (int) WriteBlob(image,length,stream) : 1); 499} 500 501static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info, 502 Image *image,ExceptionInfo *exception) 503{ 504 const char 505 *value; 506 507 int 508 webp_status; 509 510 MagickBooleanType 511 status; 512 513 MemoryInfo 514 *pixel_info; 515 516 register uint32_t 517 *magick_restrict q; 518 519 ssize_t 520 y; 521 522 WebPConfig 523 configure; 524 525 WebPPicture 526 picture; 527 528 WebPAuxStats 529 statistics; 530 531 /* 532 Open output image file. 533 */ 534 assert(image_info != (const ImageInfo *) NULL); 535 assert(image_info->signature == MagickCoreSignature); 536 assert(image != (Image *) NULL); 537 assert(image->signature == MagickCoreSignature); 538 if (image->debug != MagickFalse) 539 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 540 if ((image->columns > 16383UL) || (image->rows > 16383UL)) 541 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 542 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 543 if (status == MagickFalse) 544 return(status); 545 if ((WebPPictureInit(&picture) == 0) || (WebPConfigInit(&configure) == 0)) 546 ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile"); 547 picture.writer=WebPEncodeWriter; 548 picture.custom_ptr=(void *) image; 549#if WEBP_DECODER_ABI_VERSION >= 0x0100 550 picture.progress_hook=WebPEncodeProgress; 551#endif 552 picture.stats=(&statistics); 553 picture.width=(int) image->columns; 554 picture.height=(int) image->rows; 555 picture.argb_stride=(int) image->columns; 556 picture.use_argb=1; 557 if (image->quality != UndefinedCompressionQuality) 558 configure.quality=(float) image->quality; 559 if (image->quality >= 100) 560 configure.lossless=1; 561 value=GetImageOption(image_info,"webp:lossless"); 562 if (value != (char *) NULL) 563 configure.lossless=(int) ParseCommandOption(MagickBooleanOptions, 564 MagickFalse,value); 565 value=GetImageOption(image_info,"webp:method"); 566 if (value != (char *) NULL) 567 configure.method=StringToInteger(value); 568 value=GetImageOption(image_info,"webp:image-hint"); 569 if (value != (char *) NULL) 570 { 571 if (LocaleCompare(value,"default") == 0) 572 configure.image_hint=WEBP_HINT_DEFAULT; 573 if (LocaleCompare(value,"photo") == 0) 574 configure.image_hint=WEBP_HINT_PHOTO; 575 if (LocaleCompare(value,"picture") == 0) 576 configure.image_hint=WEBP_HINT_PICTURE; 577#if WEBP_DECODER_ABI_VERSION >= 0x0200 578 if (LocaleCompare(value,"graph") == 0) 579 configure.image_hint=WEBP_HINT_GRAPH; 580#endif 581 } 582 value=GetImageOption(image_info,"webp:target-size"); 583 if (value != (char *) NULL) 584 configure.target_size=StringToInteger(value); 585 value=GetImageOption(image_info,"webp:target-psnr"); 586 if (value != (char *) NULL) 587 configure.target_PSNR=(float) StringToDouble(value,(char **) NULL); 588 value=GetImageOption(image_info,"webp:segments"); 589 if (value != (char *) NULL) 590 configure.segments=StringToInteger(value); 591 value=GetImageOption(image_info,"webp:sns-strength"); 592 if (value != (char *) NULL) 593 configure.sns_strength=StringToInteger(value); 594 value=GetImageOption(image_info,"webp:filter-strength"); 595 if (value != (char *) NULL) 596 configure.filter_strength=StringToInteger(value); 597 value=GetImageOption(image_info,"webp:filter-sharpness"); 598 if (value != (char *) NULL) 599 configure.filter_sharpness=StringToInteger(value); 600 value=GetImageOption(image_info,"webp:filter-type"); 601 if (value != (char *) NULL) 602 configure.filter_type=StringToInteger(value); 603 value=GetImageOption(image_info,"webp:auto-filter"); 604 if (value != (char *) NULL) 605 configure.autofilter=(int) ParseCommandOption(MagickBooleanOptions, 606 MagickFalse,value); 607 value=GetImageOption(image_info,"webp:alpha-compression"); 608 if (value != (char *) NULL) 609 configure.alpha_compression=StringToInteger(value); 610 value=GetImageOption(image_info,"webp:alpha-filtering"); 611 if (value != (char *) NULL) 612 configure.alpha_filtering=StringToInteger(value); 613 value=GetImageOption(image_info,"webp:alpha-quality"); 614 if (value != (char *) NULL) 615 configure.alpha_quality=StringToInteger(value); 616 value=GetImageOption(image_info,"webp:pass"); 617 if (value != (char *) NULL) 618 configure.pass=StringToInteger(value); 619 value=GetImageOption(image_info,"webp:show-compressed"); 620 if (value != (char *) NULL) 621 configure.show_compressed=StringToInteger(value); 622 value=GetImageOption(image_info,"webp:preprocessing"); 623 if (value != (char *) NULL) 624 configure.preprocessing=StringToInteger(value); 625 value=GetImageOption(image_info,"webp:partitions"); 626 if (value != (char *) NULL) 627 configure.partitions=StringToInteger(value); 628 value=GetImageOption(image_info,"webp:partition-limit"); 629 if (value != (char *) NULL) 630 configure.partition_limit=StringToInteger(value); 631#if WEBP_DECODER_ABI_VERSION >= 0x0201 632 value=GetImageOption(image_info,"webp:emulate-jpeg-size"); 633 if (value != (char *) NULL) 634 configure.emulate_jpeg_size=(int) ParseCommandOption(MagickBooleanOptions, 635 MagickFalse,value); 636 value=GetImageOption(image_info,"webp:low-memory"); 637 if (value != (char *) NULL) 638 configure.low_memory=(int) ParseCommandOption(MagickBooleanOptions, 639 MagickFalse,value); 640 value=GetImageOption(image_info,"webp:thread-level"); 641 if (value != (char *) NULL) 642 configure.thread_level=StringToInteger(value); 643#endif 644 if (WebPValidateConfig(&configure) == 0) 645 ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile"); 646 /* 647 Allocate memory for pixels. 648 */ 649 (void) TransformImageColorspace(image,sRGBColorspace,exception); 650 pixel_info=AcquireVirtualMemory(image->columns,image->rows* 651 sizeof(*picture.argb)); 652 if (pixel_info == (MemoryInfo *) NULL) 653 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 654 picture.argb=(uint32_t *) GetVirtualMemoryBlob(pixel_info); 655 /* 656 Convert image to WebP raster pixels. 657 */ 658 q=picture.argb; 659 for (y=0; y < (ssize_t) image->rows; y++) 660 { 661 register const Quantum 662 *magick_restrict p; 663 664 register ssize_t 665 x; 666 667 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 668 if (p == (const Quantum *) NULL) 669 break; 670 for (x=0; x < (ssize_t) image->columns; x++) 671 { 672 *q++=(uint32_t) (image->alpha_trait != UndefinedPixelTrait ? 673 ScaleQuantumToChar(GetPixelAlpha(image,p)) << 24 : 0xff000000) | 674 (ScaleQuantumToChar(GetPixelRed(image,p)) << 16) | 675 (ScaleQuantumToChar(GetPixelGreen(image,p)) << 8) | 676 (ScaleQuantumToChar(GetPixelBlue(image,p))); 677 p+=GetPixelChannels(image); 678 } 679 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 680 image->rows); 681 if (status == MagickFalse) 682 break; 683 } 684 webp_status=WebPEncode(&configure,&picture); 685 if (webp_status == 0) 686 { 687 const char 688 *message; 689 690 switch (picture.error_code) 691 { 692 case VP8_ENC_ERROR_OUT_OF_MEMORY: 693 { 694 message="out of memory"; 695 break; 696 } 697 case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: 698 { 699 message="bitstream out of memory"; 700 break; 701 } 702 case VP8_ENC_ERROR_NULL_PARAMETER: 703 { 704 message="NULL parameter"; 705 break; 706 } 707 case VP8_ENC_ERROR_INVALID_CONFIGURATION: 708 { 709 message="invalid configuration"; 710 break; 711 } 712 case VP8_ENC_ERROR_BAD_DIMENSION: 713 { 714 message="bad dimension"; 715 break; 716 } 717 case VP8_ENC_ERROR_PARTITION0_OVERFLOW: 718 { 719 message="partition 0 overflow (> 512K)"; 720 break; 721 } 722 case VP8_ENC_ERROR_PARTITION_OVERFLOW: 723 { 724 message="partition overflow (> 16M)"; 725 break; 726 } 727 case VP8_ENC_ERROR_BAD_WRITE: 728 { 729 message="bad write"; 730 break; 731 } 732 case VP8_ENC_ERROR_FILE_TOO_BIG: 733 { 734 message="file too big (> 4GB)"; 735 break; 736 } 737#if WEBP_DECODER_ABI_VERSION >= 0x0100 738 case VP8_ENC_ERROR_USER_ABORT: 739 { 740 message="user abort"; 741 break; 742 } 743#endif 744 default: 745 { 746 message="unknown exception"; 747 break; 748 } 749 } 750 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, 751 (char *) message,"`%s'",image->filename); 752 } 753 picture.argb=(uint32_t *) NULL; 754 WebPPictureFree(&picture); 755 pixel_info=RelinquishVirtualMemory(pixel_info); 756 (void) CloseBlob(image); 757 return(webp_status == 0 ? MagickFalse : MagickTrue); 758} 759#endif 760