summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjiyong.min <jiyong.min@samsung.com>2020-07-10 13:31:36 +0900
committerjiyong.min <jiyong.min@samsung.com>2020-07-21 12:59:10 +0900
commit5850e806768449cffd5d9bb84d7c2c3e71846ec6 (patch)
treed264d17b97a922e38780743069fbb7d4ad5c1a7f
parentc3b553d0fe0bafce7f4405867d947a13be2fecd2 (diff)
downloadGraphicsMagick-tizen_6.0.tar.gz
GraphicsMagick-tizen_6.0.tar.bz2
GraphicsMagick-tizen_6.0.zip
- WebP is based on RIFF container and it provides additional container for animation. If a WebP image contains animation container, image data is included in the animation container. But GraphicsMagick does not support animation container. For the reason, GraphicsMagick return invalid image for animated WebP. (The mandatory image data is not found) So we add to parse animation container and decode 1 frame. - Tizen platform supports 1 frame for animated image format. Change-Id: I1894517769d1b097f7103fe55a525211e7519589
-rw-r--r--coders/webp.c385
-rwxr-xr-xconfigure6
-rwxr-xr-xconfigure.ac1
-rwxr-xr-xpackaging/GraphicsMagick.spec1
4 files changed, 333 insertions, 60 deletions
diff --git a/coders/webp.c b/coders/webp.c
index 04016e7..711fcf5 100644
--- a/coders/webp.c
+++ b/coders/webp.c
@@ -61,6 +61,7 @@ static unsigned int WriteWEBPImage(const ImageInfo *,Image *);
#if defined(HasWEBP)
#include <webp/decode.h>
#include <webp/encode.h>
+#include <webp/demux.h>
/*
Release versions vs ABI versions (found in src/webp/encode.h)
@@ -138,6 +139,252 @@ static MagickTsdKey_t tsd_key = (MagickTsdKey_t) 0;
% o exception: return any errors or warnings in this structure.
%
*/
+
+/*
+ Apply ImageMagick patch for animated WebP.
+ Decoding only the first frame of the animation image is supported.
+*/
+#ifndef __TIZEN__
+#define __TIZEN__
+#endif
+
+#if defined(__TIZEN__)
+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 int FillBasicWEBPInfo(Image *image,const uint8_t *stream,size_t length,
+ WebPDecoderConfig *configure)
+{
+ WebPBitstreamFeatures
+ *restrict features = &configure->input;
+
+ int
+ webp_status;
+
+ webp_status=WebPGetFeatures(stream,length,features);
+
+ if (webp_status != VP8_STATUS_OK)
+ return(webp_status);
+
+ image->columns=(size_t) features->width;
+ image->rows=(size_t) features->height;
+ image->depth=8;
+ image->matte=(features->has_alpha ? MagickTrue : MagickFalse);
+
+ return(webp_status);
+}
+
+static int ReadSingleWEBPImage(Image *image,const uint8_t *stream,
+ size_t length,WebPDecoderConfig *configure,ExceptionInfo *exception,
+ MagickBool is_first)
+{
+ int
+ webp_status;
+
+ register unsigned char
+ *p;
+
+ register PixelPacket
+ *q;
+
+ register size_t
+ x;
+
+ size_t
+ canvas_width,
+ canvas_height,
+ image_width,
+ image_height;
+
+ ssize_t
+ x_offset,
+ y_offset,
+ y;
+
+ WebPDecBuffer
+ *restrict webp_image = &configure->output;
+
+ if (is_first)
+ {
+ canvas_width=image->columns;
+ canvas_height=image->rows;
+ x_offset=image->page.x;
+ y_offset=image->page.y;
+ image->page.x=0;
+ image->page.y=0;
+ }
+ else
+ {
+ x_offset=0;
+ y_offset=0;
+ }
+ webp_status=FillBasicWEBPInfo(image,stream,length,configure);
+ image_width=image->columns;
+ image_height=image->rows;
+ if (is_first)
+ {
+ image->columns=canvas_width;
+ image->rows=canvas_height;
+ }
+
+ if (webp_status != VP8_STATUS_OK)
+ return(webp_status);
+
+ webp_status=WebPDecode(stream,length,configure);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),"WebPDecode webp_status=%d",webp_status);
+ if (webp_status != VP8_STATUS_OK)
+ return(webp_status);
+
+ p=(unsigned char *) webp_image->u.RGBA.rgba;
+
+ for (y=0; y < (size_t) image->rows; y++)
+ {
+ q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
+ if (q == (PixelPacket *) NULL)
+ break;
+
+ for (x=0; x < (size_t) image->columns; x++)
+ {
+ SetRedSample(q,ScaleCharToQuantum(*p++));
+ SetGreenSample(q,ScaleCharToQuantum(*p++));
+ SetBlueSample(q,ScaleCharToQuantum(*p++));
+ if (image->matte)
+ SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p++));
+ else
+ SetOpacitySample(q,OpaqueOpacity);
+ q++;
+ }
+
+ if (!SyncImagePixels(image))
+ break;
+ }
+
+ WebPFreeDecBuffer(webp_image);
+#if defined(MAGICKCORE_WEBPMUX_DELEGATE)
+ {
+ uint32_t
+ webp_flags = 0;
+
+ WebPData
+ chunk,
+ content;
+
+ WebPMux
+ *mux;
+
+ /*
+ Extract any profiles.
+ */
+ content.bytes=stream;
+ content.size=length;
+ mux=WebPMuxCreate(&content,0);
+ (void) memset(&chunk,0,sizeof(chunk));
+ WebPMuxGetFeatures(mux,&webp_flags);
+ if (webp_flags & ICCP_FLAG)
+ {
+ WebPMuxGetChunk(mux,"ICCP",&chunk);
+ AppendImageProfile(image,"ICC",chunk.bytes,chunk.size);
+ }
+ if (webp_flags & EXIF_FLAG)
+ {
+ WebPMuxGetChunk(mux,"EXIF",&chunk);
+ AppendImageProfile(image,"EXIF",chunk.bytes,chunk.size);
+ }
+ if (webp_flags & XMP_FLAG)
+ {
+ WebPMuxGetChunk(mux,"XMP",&chunk);
+ AppendImageProfile(image,"XMP",chunk.bytes,chunk.size);
+ }
+ WebPMuxDelete(mux);
+ }
+#endif
+ return(webp_status);
+}
+
+static int ReadAnimatedWEBPImage(const ImageInfo *image_info,Image *image,
+ uint8_t *stream,size_t length,WebPDecoderConfig *configure,
+ ExceptionInfo *exception)
+{
+ Image
+ *original_image;
+
+ int
+ image_count,
+ webp_status;
+
+ size_t
+ canvas_width,
+ canvas_height;
+
+ WebPData
+ data;
+
+ WebPDemuxer
+ *demux;
+
+ WebPIterator
+ iter;
+
+ image_count=0;
+ webp_status=0;
+ original_image=image;
+ webp_status=FillBasicWEBPInfo(image,stream,length,configure);
+ canvas_width=image->columns;
+ canvas_height=image->rows;
+ data.bytes=stream;
+ data.size=length;
+ demux=WebPDemux(&data);
+ if (WebPDemuxGetFrame(demux,1,&iter)) {
+ do {
+ if (image_count != 0)
+ {
+ if (GetNextImageInList(image) == (Image *) NULL)
+ break;
+ image=SyncNextImageInList(image);
+ CloneImageAttributes(image,original_image);
+ image->page.x=iter.x_offset;
+ image->page.y=iter.y_offset;
+ webp_status=ReadSingleWEBPImage(image,iter.fragment.bytes,
+ iter.fragment.size,configure,exception,MagickFalse);
+ }
+ else
+ {
+ image->page.x=iter.x_offset;
+ image->page.y=iter.y_offset;
+ webp_status=ReadSingleWEBPImage(image,iter.fragment.bytes,
+ iter.fragment.size,configure,exception,MagickTrue);
+ }
+ if (webp_status != VP8_STATUS_OK)
+ break;
+
+ image->page.width=canvas_width;
+ image->page.height=canvas_height;
+ image->delay=iter.duration/10;
+ if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND)
+ image->dispose=BackgroundDispose;
+ image_count++;
+ } while (WebPDemuxNextFrame(&iter));
+ WebPDemuxReleaseIterator(&iter);
+ }
+ WebPDemuxDelete(demux);
+ return(webp_status);
+}
+#endif /* defined(__TIZEN__) */
+
static Image *ReadWEBPImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
@@ -164,6 +411,11 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
*stream,
*pixels;
+#if defined(__TIZEN__)
+ WebPDecoderConfig
+ configure;
+#endif /* defined(__TIZEN__) */
+
WebPBitstreamFeatures
stream_features;
@@ -195,7 +447,15 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
MagickFreeMemory(stream);
ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
}
- if ((webp_status=WebPGetFeatures(stream,length,&stream_features)) != VP8_STATUS_OK)
+
+#if defined(__TIZEN__)
+ memset(&configure, 0x00, sizeof(WebPDecoderConfig));
+ webp_status=FillBasicWEBPInfo(image,stream,length,&configure);
+ memcpy(&stream_features,&configure.input,sizeof(WebPBitstreamFeatures));
+#else
+ webp_status=WebPGetFeatures(stream,length,&stream_features);
+#endif /* defined(__TIZEN__) */
+ if (webp_status != VP8_STATUS_OK)
{
MagickFreeMemory(stream);
@@ -244,6 +504,7 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
*/
ThrowReaderException(CorruptImageError,CorruptImage,image);
}
+
image->depth=8;
image->columns=(size_t) stream_features.width;
image->rows=(size_t) stream_features.height;
@@ -259,79 +520,91 @@ static Image *ReadWEBPImage(const ImageInfo *image_info,
MagickFreeMemory(stream);
ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
}
- if (image->matte)
- pixels=(unsigned char *) WebPDecodeRGBA(stream,length,
+
+#if defined(__TIZEN__)
+ if (configure.input.has_animation) {
+ webp_status=ReadAnimatedWEBPImage(image_info,image,stream,length,
+ &configure,exception);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "ReadAnimatedWEBPImage return %d",webp_status);
+ } else
+#endif /* defined(__TIZEN__) */
+ {
+ if (image->matte)
+ pixels=(unsigned char *) WebPDecodeRGBA(stream,length,
&stream_features.width,
&stream_features.height);
- else
- pixels=(unsigned char *) WebPDecodeRGB(stream,length,
+ else
+ pixels=(unsigned char *) WebPDecodeRGB(stream,length,
&stream_features.width,
&stream_features.height);
- if (pixels == (unsigned char *) NULL)
- {
- MagickFreeMemory(stream);
- ThrowReaderException(CoderError,NoDataReturned,image);
- }
+ if (pixels == (unsigned char *) NULL)
+ {
+ MagickFreeMemory(stream);
+ ThrowReaderException(CoderError,NoDataReturned,image);
+ }
- p=pixels;
+ p=pixels;
- for (y=0; y < (size_t) image->rows; y++)
- {
- q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
- if (q == (PixelPacket *) NULL)
- break;
+ for (y=0; y < (size_t) image->rows; y++)
+ {
+ q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
+ if (q == (PixelPacket *) NULL)
+ break;
- for (x=0; x < (size_t) image->columns; x++)
- {
- SetRedSample(q,ScaleCharToQuantum(*p++));
- SetGreenSample(q,ScaleCharToQuantum(*p++));
- SetBlueSample(q,ScaleCharToQuantum(*p++));
- if (image->matte)
- SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p++));
- else
- SetOpacitySample(q,OpaqueOpacity);
- q++;
- }
+ for (x=0; x < (size_t) image->columns; x++)
+ {
+ SetRedSample(q,ScaleCharToQuantum(*p++));
+ SetGreenSample(q,ScaleCharToQuantum(*p++));
+ SetBlueSample(q,ScaleCharToQuantum(*p++));
+ if (image->matte)
+ SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p++));
+ else
+ SetOpacitySample(q,OpaqueOpacity);
+ q++;
+ }
- if (!SyncImagePixels(image))
- break;
- }
+ if (!SyncImagePixels(image))
+ break;
+ }
#if defined(SUPPORT_WEBP_MUX)
- /* Read features out of the WebP container */
- {
- uint32_t webp_flags=0;
- WebPData flag_data;
- WebPData content={stream,length};
+ /* Read features out of the WebP container */
+ {
+ uint32_t webp_flags=0;
+ WebPData flag_data;
+ WebPData content={stream,length};
- WebPMux *mux=WebPMuxCreate(&content,0);
- (void) memset(&flag_data,0,sizeof(flag_data));
- WebPMuxGetFeatures(mux,&webp_flags);
+ WebPMux *mux=WebPMuxCreate(&content,0);
+ (void) memset(&flag_data,0,sizeof(flag_data));
+ WebPMuxGetFeatures(mux,&webp_flags);
- if (webp_flags & ICCP_FLAG) {
- WebPMuxGetChunk(mux,"ICCP",&flag_data);
- AppendImageProfile(image,"ICC",flag_data.bytes,flag_data.size);
- }
+ if (webp_flags & ICCP_FLAG) {
+ WebPMuxGetChunk(mux,"ICCP",&flag_data);
+ AppendImageProfile(image,"ICC",flag_data.bytes,flag_data.size);
+ }
- if (webp_flags & EXIF_FLAG) {
- WebPMuxGetChunk(mux,"EXIF",&flag_data);
- AppendImageProfile(image,"EXIF",flag_data.bytes,flag_data.size);
- }
+ if (webp_flags & EXIF_FLAG) {
+ WebPMuxGetChunk(mux,"EXIF",&flag_data);
+ AppendImageProfile(image,"EXIF",flag_data.bytes,flag_data.size);
+ }
- if (webp_flags & XMP_FLAG) {
- WebPMuxGetChunk(mux,"XMP",&flag_data);
- AppendImageProfile(image,"XMP",flag_data.bytes,flag_data.size);
+ if (webp_flags & XMP_FLAG) {
+ WebPMuxGetChunk(mux,"XMP",&flag_data);
+ AppendImageProfile(image,"XMP",flag_data.bytes,flag_data.size);
+ }
+
+ WebPMuxDelete(mux);
}
+#endif /* defined(SUPPORT_WEBP_MUX) */
- WebPMuxDelete(mux);
+ /*
+ Free scale resource.
+ */
+ free(pixels);
+ pixels=(unsigned char *) NULL;
}
-#endif /* defined(SUPPORT_WEBP_MUX) */
- /*
- Free scale resource.
- */
- free(pixels);
- pixels=(unsigned char *) NULL;
MagickFreeMemory(stream);
CloseBlob(image);
return(image);
diff --git a/configure b/configure
index 9581a4e..83d410b 100755
--- a/configure
+++ b/configure
@@ -27510,7 +27510,7 @@ if ${ac_cv_lib_webp_WebPDecodeRGB+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lwebp $LIBS"
+LIBS="-lwebp -lwebpdemux $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -27541,7 +27541,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_webp_WebPDecodeRGB" >&5
$as_echo "$ac_cv_lib_webp_WebPDecodeRGB" >&6; }
if test "x$ac_cv_lib_webp_WebPDecodeRGB" = xyes; then :
- passed=`expr $passed + 1`; LIB_WEBP='-lwebp'
+ passed=`expr $passed + 1`; LIB_WEBP='-lwebp -lwebpdemux'
else
failed=`expr $failed + 1`
fi
@@ -27552,7 +27552,7 @@ if ${ac_cv_lib_webpmux_WebPMuxSetImage+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lwebpmux -lwebp $LIBS"
+LIBS="-lwebpmux -lwebp -lwebpdemux $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
diff --git a/configure.ac b/configure.ac
index 6d77a20..0776701 100755
--- a/configure.ac
+++ b/configure.ac
@@ -2534,6 +2534,7 @@ then
AC_CHECK_HEADER([webp/encode.h],[passed=`expr $passed + 1`],[failed=`expr $failed + 1`],[])
AC_CHECK_LIB([webp],[WebPDecodeRGB],[passed=`expr $passed + 1`; LIB_WEBP='-lwebp'],[failed=`expr $failed + 1`],[])
AC_CHECK_LIB([webpmux],[WebPMuxSetImage],[LIB_WEBP="$LIB_WEBP -lwebpmux"],[],[-lwebp])
+ AC_CHECK_LIB([webpdemux],[WebPDeMuxGetFrame],[LIB_WEBP="$LIB_WEBP -lwebpdemux"],[],[-lwebp])
AC_MSG_CHECKING(if WEBP package is complete)
if test $passed -gt 0
then
diff --git a/packaging/GraphicsMagick.spec b/packaging/GraphicsMagick.spec
index 519da7c..402f1f9 100755
--- a/packaging/GraphicsMagick.spec
+++ b/packaging/GraphicsMagick.spec
@@ -14,7 +14,6 @@ BuildRequires: libpng-devel
BuildRequires: libtool-ltdl-devel
BuildRequires: libxml2-devel
BuildRequires: pkgconfig(libwebp)
-BuildRequires: pkgconfig(libwebpdecoder)
BuildRequires: pkgconfig(libwebpdemux)
BuildRequires: pkgconfig(libwebpmux)
BuildRequires: xz-devel