Built SDL2_image and _mixer static
This commit is contained in:
		
							
								
								
									
										93
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Android.mk
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Android.mk
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| LOCAL_PATH := $(call my-dir) | ||||
|  | ||||
| ################################################################################ | ||||
| # libexample_util | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
|     example_util.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src | ||||
|  | ||||
| LOCAL_MODULE := example_util | ||||
|  | ||||
| include $(BUILD_STATIC_LIBRARY) | ||||
|  | ||||
| ################################################################################ | ||||
| # cwebp | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| # Note: to enable jpeg/png encoding the sources from AOSP can be used with | ||||
| # minor modification to their Android.mk files. | ||||
| LOCAL_SRC_FILES := \ | ||||
|     cwebp.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpdemux webp | ||||
|  | ||||
| LOCAL_MODULE := cwebp | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
|  | ||||
| ################################################################################ | ||||
| # dwebp | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
|     dwebp.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webpdemux webp | ||||
| LOCAL_MODULE := dwebp | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
|  | ||||
| ################################################################################ | ||||
| # webpmux | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
|     webpmux.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp | ||||
|  | ||||
| LOCAL_MODULE := webpmux_example | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
|  | ||||
| ################################################################################ | ||||
| # img2webp | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
|     img2webp.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webpdemux \ | ||||
|                           webp | ||||
|  | ||||
| LOCAL_MODULE := img2webp_example | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
|  | ||||
| ################################################################################ | ||||
| # webpinfo | ||||
|  | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
|     webpinfo.c \ | ||||
|  | ||||
| LOCAL_CFLAGS := $(WEBP_CFLAGS) | ||||
| LOCAL_STATIC_LIBRARIES := example_util imageio_util webp | ||||
|  | ||||
| LOCAL_MODULE := webpinfo_example | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
							
								
								
									
										119
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Makefile.am
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Makefile.am
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src | ||||
|  | ||||
| bin_PROGRAMS = | ||||
| if BUILD_DEMUX | ||||
|   bin_PROGRAMS += dwebp cwebp | ||||
| endif | ||||
| if BUILD_ANIMDIFF | ||||
|   noinst_PROGRAMS = anim_diff anim_dump | ||||
| endif | ||||
| if BUILD_GIF2WEBP | ||||
|   bin_PROGRAMS += gif2webp | ||||
| endif | ||||
| if BUILD_IMG2WEBP | ||||
|   bin_PROGRAMS += img2webp | ||||
| endif | ||||
| if BUILD_MUX | ||||
|   bin_PROGRAMS += webpmux | ||||
| endif | ||||
| if BUILD_VWEBP | ||||
|   bin_PROGRAMS += vwebp | ||||
| endif | ||||
| if BUILD_WEBPINFO | ||||
|   bin_PROGRAMS += webpinfo | ||||
| endif | ||||
|  | ||||
| noinst_LTLIBRARIES = libexample_util.la | ||||
|  | ||||
| libexample_util_la_SOURCES = example_util.c example_util.h | ||||
| libexample_util_la_LIBADD = ../src/libwebp.la | ||||
|  | ||||
| anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h gifdec.c gifdec.h | ||||
| anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) | ||||
| anim_diff_LDADD  = | ||||
| anim_diff_LDADD += ../src/demux/libwebpdemux.la | ||||
| anim_diff_LDADD += libexample_util.la | ||||
| anim_diff_LDADD += ../imageio/libimageio_util.la | ||||
| anim_diff_LDADD += $(GIF_LIBS) -lm | ||||
|  | ||||
| anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h gifdec.c gifdec.h | ||||
| anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) | ||||
| anim_dump_CPPFLAGS += $(GIF_INCLUDES) | ||||
| anim_dump_LDADD  = | ||||
| anim_dump_LDADD += ../src/demux/libwebpdemux.la | ||||
| anim_dump_LDADD += libexample_util.la | ||||
| anim_dump_LDADD += ../imageio/libimageio_util.la | ||||
| anim_dump_LDADD += ../imageio/libimageenc.la | ||||
| anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm | ||||
|  | ||||
| cwebp_SOURCES  = cwebp.c stopwatch.h | ||||
| cwebp_CPPFLAGS  = $(AM_CPPFLAGS) | ||||
| cwebp_LDADD  = | ||||
| cwebp_LDADD += libexample_util.la | ||||
| cwebp_LDADD += ../imageio/libimageio_util.la | ||||
| cwebp_LDADD += ../imageio/libimagedec.la | ||||
| cwebp_LDADD += ../src/libwebp.la | ||||
| cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) | ||||
|  | ||||
| dwebp_SOURCES = dwebp.c stopwatch.h | ||||
| dwebp_CPPFLAGS  = $(AM_CPPFLAGS) | ||||
| dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) | ||||
| dwebp_LDADD  = | ||||
| dwebp_LDADD += libexample_util.la | ||||
| dwebp_LDADD += ../imageio/libimagedec.la | ||||
| dwebp_LDADD += ../imageio/libimageenc.la | ||||
| dwebp_LDADD += ../imageio/libimageio_util.la | ||||
| dwebp_LDADD += ../src/libwebp.la | ||||
| dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS) | ||||
|  | ||||
| gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h | ||||
| gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) | ||||
| gif2webp_LDADD  = | ||||
| gif2webp_LDADD += libexample_util.la | ||||
| gif2webp_LDADD += ../imageio/libimageio_util.la | ||||
| gif2webp_LDADD += ../src/mux/libwebpmux.la | ||||
| gif2webp_LDADD += ../src/libwebp.la | ||||
| gif2webp_LDADD += $(GIF_LIBS) | ||||
|  | ||||
| vwebp_SOURCES = vwebp.c | ||||
| vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(GL_INCLUDES) | ||||
| vwebp_LDADD  = | ||||
| vwebp_LDADD += libexample_util.la | ||||
| vwebp_LDADD += ../imageio/libimageio_util.la | ||||
| vwebp_LDADD += ../src/demux/libwebpdemux.la | ||||
| vwebp_LDADD += $(GL_LIBS) | ||||
|  | ||||
| webpmux_SOURCES = webpmux.c | ||||
| webpmux_CPPFLAGS = $(AM_CPPFLAGS) | ||||
| webpmux_LDADD  = | ||||
| webpmux_LDADD += libexample_util.la | ||||
| webpmux_LDADD += ../imageio/libimageio_util.la | ||||
| webpmux_LDADD += ../src/mux/libwebpmux.la | ||||
| webpmux_LDADD += ../src/libwebp.la | ||||
|  | ||||
| img2webp_SOURCES = img2webp.c | ||||
| img2webp_CPPFLAGS = $(AM_CPPFLAGS) | ||||
| img2webp_LDADD  = | ||||
| img2webp_LDADD += libexample_util.la | ||||
| img2webp_LDADD += ../imageio/libimageio_util.la | ||||
| img2webp_LDADD += ../imageio/libimagedec.la | ||||
| img2webp_LDADD += ../src/mux/libwebpmux.la | ||||
| img2webp_LDADD += ../src/libwebp.la | ||||
| img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) | ||||
|  | ||||
| webpinfo_SOURCES = webpinfo.c | ||||
| webpinfo_CPPFLAGS = $(AM_CPPFLAGS) | ||||
| webpinfo_LDADD  = | ||||
| webpinfo_LDADD += libexample_util.la | ||||
| webpinfo_LDADD += ../imageio/libimageio_util.la | ||||
| webpinfo_LDADD += ../src/libwebp.la | ||||
|  | ||||
| if BUILD_LIBWEBPDECODER | ||||
|   anim_diff_LDADD += ../src/libwebpdecoder.la | ||||
|   anim_dump_LDADD += ../src/libwebpdecoder.la | ||||
|   vwebp_LDADD += ../src/libwebpdecoder.la | ||||
| else | ||||
|   anim_diff_LDADD += ../src/libwebp.la | ||||
|   anim_dump_LDADD += ../src/libwebp.la | ||||
|   vwebp_LDADD += ../src/libwebp.la | ||||
| endif | ||||
							
								
								
									
										1095
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Makefile.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1095
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/Makefile.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										317
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_diff.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_diff.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,317 @@ | ||||
| // Copyright 2015 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // Checks if given pair of animated GIF/WebP images are identical: | ||||
| // That is: their reconstructed canvases match pixel-by-pixel and their other | ||||
| // animation properties (loop count etc) also match. | ||||
| // | ||||
| // example: anim_diff foo.gif bar.webp | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <limits.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h>  // for 'strtod'. | ||||
| #include <string.h>  // for 'strcmp'. | ||||
|  | ||||
| #include "./anim_util.h" | ||||
| #include "./example_util.h" | ||||
| #include "./unicode.h" | ||||
|  | ||||
| #if defined(_MSC_VER) && _MSC_VER < 1900 | ||||
| #define snprintf _snprintf | ||||
| #endif | ||||
|  | ||||
| // Returns true if 'a + b' will overflow. | ||||
| static int AdditionWillOverflow(int a, int b) { | ||||
|   return (b > 0) && (a > INT_MAX - b); | ||||
| } | ||||
|  | ||||
| static int FramesAreEqual(const uint8_t* const rgba1, | ||||
|                           const uint8_t* const rgba2, int width, int height) { | ||||
|   const int stride = width * 4;  // Always true for 'DecodedFrame.rgba'. | ||||
|   return !memcmp(rgba1, rgba2, stride * height); | ||||
| } | ||||
|  | ||||
| static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst, | ||||
|                                         int max_allowed_diff) { | ||||
|   const int src_a = (src >> 24) & 0xff; | ||||
|   const int src_r = (src >> 16) & 0xff; | ||||
|   const int src_g = (src >> 8) & 0xff; | ||||
|   const int src_b = (src >> 0) & 0xff; | ||||
|   const int dst_a = (dst >> 24) & 0xff; | ||||
|   const int dst_r = (dst >> 16) & 0xff; | ||||
|   const int dst_g = (dst >> 8) & 0xff; | ||||
|   const int dst_b = (dst >> 0) & 0xff; | ||||
|  | ||||
|   return (abs(src_r * src_a - dst_r * dst_a) <= (max_allowed_diff * 255)) && | ||||
|          (abs(src_g * src_a - dst_g * dst_a) <= (max_allowed_diff * 255)) && | ||||
|          (abs(src_b * src_a - dst_b * dst_a) <= (max_allowed_diff * 255)) && | ||||
|          (abs(src_a - dst_a) <= max_allowed_diff); | ||||
| } | ||||
|  | ||||
| static int FramesAreSimilar(const uint8_t* const rgba1, | ||||
|                             const uint8_t* const rgba2, | ||||
|                             int width, int height, int max_allowed_diff) { | ||||
|   int i, j; | ||||
|   assert(max_allowed_diff > 0); | ||||
|   for (j = 0; j < height; ++j) { | ||||
|     for (i = 0; i < width; ++i) { | ||||
|       const int stride = width * 4; | ||||
|       const size_t offset = j * stride + i; | ||||
|       if (!PixelsAreSimilar(rgba1[offset], rgba2[offset], max_allowed_diff)) { | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| // Minimize number of frames by combining successive frames that have at max | ||||
| // 'max_diff' difference per channel between corresponding pixels. | ||||
| static void MinimizeAnimationFrames(AnimatedImage* const img, int max_diff) { | ||||
|   uint32_t i; | ||||
|   for (i = 1; i < img->num_frames; ++i) { | ||||
|     DecodedFrame* const frame1 = &img->frames[i - 1]; | ||||
|     DecodedFrame* const frame2 = &img->frames[i]; | ||||
|     const uint8_t* const rgba1 = frame1->rgba; | ||||
|     const uint8_t* const rgba2 = frame2->rgba; | ||||
|     int should_merge_frames = 0; | ||||
|     // If merging frames will result in integer overflow for 'duration', | ||||
|     // skip merging. | ||||
|     if (AdditionWillOverflow(frame1->duration, frame2->duration)) continue; | ||||
|     if (max_diff > 0) { | ||||
|       should_merge_frames = FramesAreSimilar(rgba1, rgba2, img->canvas_width, | ||||
|                                              img->canvas_height, max_diff); | ||||
|     } else { | ||||
|       should_merge_frames = | ||||
|           FramesAreEqual(rgba1, rgba2, img->canvas_width, img->canvas_height); | ||||
|     } | ||||
|     if (should_merge_frames) {  // Merge 'i+1'th frame into 'i'th frame. | ||||
|       frame1->duration += frame2->duration; | ||||
|       if (i + 1 < img->num_frames) { | ||||
|         memmove(&img->frames[i], &img->frames[i + 1], | ||||
|                 (img->num_frames - i - 1) * sizeof(*img->frames)); | ||||
|       } | ||||
|       --img->num_frames; | ||||
|       --i; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| static int CompareValues(uint32_t a, uint32_t b, const char* output_str) { | ||||
|   if (a != b) { | ||||
|     fprintf(stderr, "%s: %d vs %d\n", output_str, a, b); | ||||
|     return 0; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int CompareBackgroundColor(uint32_t bg1, uint32_t bg2, int premultiply) { | ||||
|   if (premultiply) { | ||||
|     const int alpha1 = (bg1 >> 24) & 0xff; | ||||
|     const int alpha2 = (bg2 >> 24) & 0xff; | ||||
|     if (alpha1 == 0 && alpha2 == 0) return 1; | ||||
|   } | ||||
|   if (bg1 != bg2) { | ||||
|     fprintf(stderr, "Background color mismatch: 0x%08x vs 0x%08x\n", | ||||
|             bg1, bg2); | ||||
|     return 0; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| // Note: As long as frame durations and reconstructed frames are identical, it | ||||
| // is OK for other aspects like offsets, dispose/blend method to vary. | ||||
| static int CompareAnimatedImagePair(const AnimatedImage* const img1, | ||||
|                                     const AnimatedImage* const img2, | ||||
|                                     int premultiply, | ||||
|                                     double min_psnr) { | ||||
|   int ok = 1; | ||||
|   const int is_multi_frame_image = (img1->num_frames > 1); | ||||
|   uint32_t i; | ||||
|  | ||||
|   ok = CompareValues(img1->canvas_width, img2->canvas_width, | ||||
|                      "Canvas width mismatch") && ok; | ||||
|   ok = CompareValues(img1->canvas_height, img2->canvas_height, | ||||
|                      "Canvas height mismatch") && ok; | ||||
|   ok = CompareValues(img1->num_frames, img2->num_frames, | ||||
|                      "Frame count mismatch") && ok; | ||||
|   if (!ok) return 0;  // These are fatal failures, can't proceed. | ||||
|  | ||||
|   if (is_multi_frame_image) {  // Checks relevant for multi-frame images only. | ||||
|     int max_loop_count_workaround = 0; | ||||
|     // Transcodes to webp increase the gif loop count by 1 for compatibility. | ||||
|     // When the gif has the maximum value the webp value will be off by one. | ||||
|     if ((img1->format == ANIM_GIF && img1->loop_count == 65536 && | ||||
|          img2->format == ANIM_WEBP && img2->loop_count == 65535) || | ||||
|         (img1->format == ANIM_WEBP && img1->loop_count == 65535 && | ||||
|          img2->format == ANIM_GIF && img2->loop_count == 65536)) { | ||||
|       max_loop_count_workaround = 1; | ||||
|     } | ||||
|     ok = (max_loop_count_workaround || | ||||
|           CompareValues(img1->loop_count, img2->loop_count, | ||||
|                         "Loop count mismatch")) && ok; | ||||
|     ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor, | ||||
|                                 premultiply) && ok; | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < img1->num_frames; ++i) { | ||||
|     // Pixel-by-pixel comparison. | ||||
|     const uint8_t* const rgba1 = img1->frames[i].rgba; | ||||
|     const uint8_t* const rgba2 = img2->frames[i].rgba; | ||||
|     int max_diff; | ||||
|     double psnr; | ||||
|     if (is_multi_frame_image) {  // Check relevant for multi-frame images only. | ||||
|       const char format[] = "Frame #%d, duration mismatch"; | ||||
|       char tmp[sizeof(format) + 8]; | ||||
|       ok = ok && (snprintf(tmp, sizeof(tmp), format, i) >= 0); | ||||
|       ok = ok && CompareValues(img1->frames[i].duration, | ||||
|                                img2->frames[i].duration, tmp); | ||||
|     } | ||||
|     GetDiffAndPSNR(rgba1, rgba2, img1->canvas_width, img1->canvas_height, | ||||
|                    premultiply, &max_diff, &psnr); | ||||
|     if (min_psnr > 0.) { | ||||
|       if (psnr < min_psnr) { | ||||
|         fprintf(stderr, "Frame #%d, psnr = %.2lf (min_psnr = %f)\n", i, | ||||
|                 psnr, min_psnr); | ||||
|         ok = 0; | ||||
|       } | ||||
|     } else { | ||||
|       if (max_diff != 0) { | ||||
|         fprintf(stderr, "Frame #%d, max pixel diff: %d\n", i, max_diff); | ||||
|         ok = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf("Usage: anim_diff <image1> <image2> [options]\n"); | ||||
|   printf("\nOptions:\n"); | ||||
|   printf("  -dump_frames <folder> dump decoded frames in PAM format\n"); | ||||
|   printf("  -min_psnr <float> ... minimum per-frame PSNR\n"); | ||||
|   printf("  -raw_comparison ..... if this flag is not used, RGB is\n"); | ||||
|   printf("                        premultiplied before comparison\n"); | ||||
|   printf("  -max_diff <int> ..... maximum allowed difference per channel\n" | ||||
|          "                        between corresponding pixels in subsequent\n" | ||||
|          "                        frames\n"); | ||||
|   printf("  -h .................. this help\n"); | ||||
|   printf("  -version ............ print version number and exit\n"); | ||||
| } | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   int return_code = -1; | ||||
|   int dump_frames = 0; | ||||
|   const char* dump_folder = NULL; | ||||
|   double min_psnr = 0.; | ||||
|   int got_input1 = 0; | ||||
|   int got_input2 = 0; | ||||
|   int premultiply = 1; | ||||
|   int max_diff = 0; | ||||
|   int i, c; | ||||
|   const char* files[2] = { NULL, NULL }; | ||||
|   AnimatedImage images[2]; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   for (c = 1; c < argc; ++c) { | ||||
|     int parse_error = 0; | ||||
|     if (!strcmp(argv[c], "-dump_frames")) { | ||||
|       if (c < argc - 1) { | ||||
|         dump_frames = 1; | ||||
|         dump_folder = (const char*)GET_WARGV(argv, ++c); | ||||
|       } else { | ||||
|         parse_error = 1; | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-min_psnr")) { | ||||
|       if (c < argc - 1) { | ||||
|         min_psnr = ExUtilGetFloat(argv[++c], &parse_error); | ||||
|       } else { | ||||
|         parse_error = 1; | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-raw_comparison")) { | ||||
|       premultiply = 0; | ||||
|     } else if (!strcmp(argv[c], "-max_diff")) { | ||||
|       if (c < argc - 1) { | ||||
|         max_diff = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       } else { | ||||
|         parse_error = 1; | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-version")) { | ||||
|       int dec_version, demux_version; | ||||
|       GetAnimatedImageVersions(&dec_version, &demux_version); | ||||
|       printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", | ||||
|              (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, | ||||
|              (dec_version >> 0) & 0xff, | ||||
|              (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, | ||||
|              (demux_version >> 0) & 0xff); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else { | ||||
|       if (!got_input1) { | ||||
|         files[0] = (const char*)GET_WARGV(argv, c); | ||||
|         got_input1 = 1; | ||||
|       } else if (!got_input2) { | ||||
|         files[1] = (const char*)GET_WARGV(argv, c); | ||||
|         got_input2 = 1; | ||||
|       } else { | ||||
|         parse_error = 1; | ||||
|       } | ||||
|     } | ||||
|     if (parse_error) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } | ||||
|   } | ||||
|   if (argc < 3) { | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   if (!got_input2) { | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|  | ||||
|   if (dump_frames) { | ||||
|     WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder); | ||||
|   } | ||||
|  | ||||
|   memset(images, 0, sizeof(images)); | ||||
|   for (i = 0; i < 2; ++i) { | ||||
|     WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]); | ||||
|     if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) { | ||||
|       WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", | ||||
|                (const W_CHAR*)files[i]); | ||||
|       return_code = -2; | ||||
|       goto End; | ||||
|     } else { | ||||
|       MinimizeAnimationFrames(&images[i], max_diff); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (!CompareAnimatedImagePair(&images[0], &images[1], | ||||
|                                 premultiply, min_psnr)) { | ||||
|     WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0], | ||||
|              (const W_CHAR*)files[1]); | ||||
|     return_code = -3; | ||||
|   } else { | ||||
|     WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0], | ||||
|             (const W_CHAR*)files[1]); | ||||
|     return_code = 0; | ||||
|   } | ||||
|  End: | ||||
|   ClearAnimatedImage(&images[0]); | ||||
|   ClearAnimatedImage(&images[1]); | ||||
|   FREE_WARGV_AND_RETURN(return_code); | ||||
| } | ||||
							
								
								
									
										121
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_dump.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_dump.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | ||||
| // Copyright 2017 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // Decodes an animated WebP file and dumps the decoded frames as PNG or TIFF. | ||||
| // | ||||
| // Author: Skal (pascal.massimino@gmail.com) | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h>  // for 'strcmp'. | ||||
|  | ||||
| #include "./anim_util.h" | ||||
| #include "webp/decode.h" | ||||
| #include "../imageio/image_enc.h" | ||||
| #include "./unicode.h" | ||||
|  | ||||
| #if defined(_MSC_VER) && _MSC_VER < 1900 | ||||
| #define snprintf _snprintf | ||||
| #endif | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf("Usage: anim_dump [options] files...\n"); | ||||
|   printf("\nOptions:\n"); | ||||
|   printf("  -folder <string> .... dump folder (default: '.')\n"); | ||||
|   printf("  -prefix <string> .... prefix for dumped frames " | ||||
|                                   "(default: 'dump_')\n"); | ||||
|   printf("  -tiff ............... save frames as TIFF\n"); | ||||
|   printf("  -pam ................ save frames as PAM\n"); | ||||
|   printf("  -h .................. this help\n"); | ||||
|   printf("  -version ............ print version number and exit\n"); | ||||
| } | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   int error = 0; | ||||
|   const W_CHAR* dump_folder = TO_W_CHAR("."); | ||||
|   const W_CHAR* prefix = TO_W_CHAR("dump_"); | ||||
|   const W_CHAR* suffix = TO_W_CHAR("png"); | ||||
|   WebPOutputFileFormat format = PNG; | ||||
|   int c; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   if (argc < 2) { | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|  | ||||
|   for (c = 1; !error && c < argc; ++c) { | ||||
|     if (!strcmp(argv[c], "-folder")) { | ||||
|       if (c + 1 == argc) { | ||||
|         fprintf(stderr, "missing argument after option '%s'\n", argv[c]); | ||||
|         error = 1; | ||||
|         break; | ||||
|       } | ||||
|       dump_folder = GET_WARGV(argv, ++c); | ||||
|     } else if (!strcmp(argv[c], "-prefix")) { | ||||
|       if (c + 1 == argc) { | ||||
|         fprintf(stderr, "missing argument after option '%s'\n", argv[c]); | ||||
|         error = 1; | ||||
|         break; | ||||
|       } | ||||
|       prefix = GET_WARGV(argv, ++c); | ||||
|     } else if (!strcmp(argv[c], "-tiff")) { | ||||
|       format = TIFF; | ||||
|       suffix = TO_W_CHAR("tiff"); | ||||
|     } else if (!strcmp(argv[c], "-pam")) { | ||||
|       format = PAM; | ||||
|       suffix = TO_W_CHAR("pam"); | ||||
|     } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-version")) { | ||||
|       int dec_version, demux_version; | ||||
|       GetAnimatedImageVersions(&dec_version, &demux_version); | ||||
|       printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", | ||||
|              (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, | ||||
|              (dec_version >> 0) & 0xff, | ||||
|              (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, | ||||
|              (demux_version >> 0) & 0xff); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else { | ||||
|       uint32_t i; | ||||
|       AnimatedImage image; | ||||
|       const W_CHAR* const file = GET_WARGV(argv, c); | ||||
|       memset(&image, 0, sizeof(image)); | ||||
|       WPRINTF("Decoding file: %s as %s/%sxxxx.%s\n", | ||||
|               file, dump_folder, prefix, suffix); | ||||
|       if (!ReadAnimatedImage((const char*)file, &image, 0, NULL)) { | ||||
|         WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", file); | ||||
|         error = 1; | ||||
|         break; | ||||
|       } | ||||
|       for (i = 0; !error && i < image.num_frames; ++i) { | ||||
|         W_CHAR out_file[1024]; | ||||
|         WebPDecBuffer buffer; | ||||
|         WebPInitDecBuffer(&buffer); | ||||
|         buffer.colorspace = MODE_RGBA; | ||||
|         buffer.is_external_memory = 1; | ||||
|         buffer.width = image.canvas_width; | ||||
|         buffer.height = image.canvas_height; | ||||
|         buffer.u.RGBA.rgba = image.frames[i].rgba; | ||||
|         buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t); | ||||
|         buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height; | ||||
|         WSNPRINTF(out_file, sizeof(out_file), "%s/%s%.4d.%s", | ||||
|                   dump_folder, prefix, i, suffix); | ||||
|         if (!WebPSaveImage(&buffer, format, (const char*)out_file)) { | ||||
|           WFPRINTF(stderr, "Error while saving image '%s'\n", out_file); | ||||
|           error = 1; | ||||
|         } | ||||
|         WebPFreeDecBuffer(&buffer); | ||||
|       } | ||||
|       ClearAnimatedImage(&image); | ||||
|     } | ||||
|   } | ||||
|   FREE_WARGV_AND_RETURN(error ? 1 : 0); | ||||
| } | ||||
							
								
								
									
										779
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_util.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										779
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_util.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,779 @@ | ||||
| // Copyright 2015 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // Utilities for animated images | ||||
|  | ||||
| #include "./anim_util.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #if defined(WEBP_HAVE_GIF) | ||||
| #include <gif_lib.h> | ||||
| #endif | ||||
| #include "webp/format_constants.h" | ||||
| #include "webp/decode.h" | ||||
| #include "webp/demux.h" | ||||
| #include "../imageio/imageio_util.h" | ||||
| #include "./gifdec.h" | ||||
| #include "./unicode.h" | ||||
| #include "./unicode_gif.h" | ||||
|  | ||||
| #if defined(_MSC_VER) && _MSC_VER < 1900 | ||||
| #define snprintf _snprintf | ||||
| #endif | ||||
|  | ||||
| static const int kNumChannels = 4; | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // Common utilities. | ||||
|  | ||||
| #if defined(WEBP_HAVE_GIF) | ||||
| // Returns true if the frame covers the full canvas. | ||||
| static int IsFullFrame(int width, int height, | ||||
|                        int canvas_width, int canvas_height) { | ||||
|   return (width == canvas_width && height == canvas_height); | ||||
| } | ||||
| #endif // WEBP_HAVE_GIF | ||||
|  | ||||
| static int CheckSizeForOverflow(uint64_t size) { | ||||
|   return (size == (size_t)size); | ||||
| } | ||||
|  | ||||
| static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) { | ||||
|   uint32_t i; | ||||
|   uint8_t* mem = NULL; | ||||
|   DecodedFrame* frames = NULL; | ||||
|   const uint64_t rgba_size = | ||||
|       (uint64_t)image->canvas_width * kNumChannels * image->canvas_height; | ||||
|   const uint64_t total_size = (uint64_t)num_frames * rgba_size * sizeof(*mem); | ||||
|   const uint64_t total_frame_size = (uint64_t)num_frames * sizeof(*frames); | ||||
|   if (!CheckSizeForOverflow(total_size) || | ||||
|       !CheckSizeForOverflow(total_frame_size)) { | ||||
|     return 0; | ||||
|   } | ||||
|   mem = (uint8_t*)malloc((size_t)total_size); | ||||
|   frames = (DecodedFrame*)malloc((size_t)total_frame_size); | ||||
|  | ||||
|   if (mem == NULL || frames == NULL) { | ||||
|     free(mem); | ||||
|     free(frames); | ||||
|     return 0; | ||||
|   } | ||||
|   free(image->raw_mem); | ||||
|   image->num_frames = num_frames; | ||||
|   image->frames = frames; | ||||
|   for (i = 0; i < num_frames; ++i) { | ||||
|     frames[i].rgba = mem + i * rgba_size; | ||||
|     frames[i].duration = 0; | ||||
|     frames[i].is_key_frame = 0; | ||||
|   } | ||||
|   image->raw_mem = mem; | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| void ClearAnimatedImage(AnimatedImage* const image) { | ||||
|   if (image != NULL) { | ||||
|     free(image->raw_mem); | ||||
|     free(image->frames); | ||||
|     image->num_frames = 0; | ||||
|     image->frames = NULL; | ||||
|     image->raw_mem = NULL; | ||||
|   } | ||||
| } | ||||
|  | ||||
| #if defined(WEBP_HAVE_GIF) | ||||
| // Clear the canvas to transparent. | ||||
| static void ZeroFillCanvas(uint8_t* rgba, | ||||
|                            uint32_t canvas_width, uint32_t canvas_height) { | ||||
|   memset(rgba, 0, canvas_width * kNumChannels * canvas_height); | ||||
| } | ||||
|  | ||||
| // Clear given frame rectangle to transparent. | ||||
| static void ZeroFillFrameRect(uint8_t* rgba, int rgba_stride, int x_offset, | ||||
|                               int y_offset, int width, int height) { | ||||
|   int j; | ||||
|   assert(width * kNumChannels <= rgba_stride); | ||||
|   rgba += y_offset * rgba_stride + x_offset * kNumChannels; | ||||
|   for (j = 0; j < height; ++j) { | ||||
|     memset(rgba, 0, width * kNumChannels); | ||||
|     rgba += rgba_stride; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Copy width * height pixels from 'src' to 'dst'. | ||||
| static void CopyCanvas(const uint8_t* src, uint8_t* dst, | ||||
|                        uint32_t width, uint32_t height) { | ||||
|   assert(src != NULL && dst != NULL); | ||||
|   memcpy(dst, src, width * kNumChannels * height); | ||||
| } | ||||
|  | ||||
| // Copy pixels in the given rectangle from 'src' to 'dst' honoring the 'stride'. | ||||
| static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride, | ||||
|                                int x_offset, int y_offset, | ||||
|                                int width, int height) { | ||||
|   int j; | ||||
|   const int width_in_bytes = width * kNumChannels; | ||||
|   const size_t offset = y_offset * stride + x_offset * kNumChannels; | ||||
|   assert(width_in_bytes <= stride); | ||||
|   src += offset; | ||||
|   dst += offset; | ||||
|   for (j = 0; j < height; ++j) { | ||||
|     memcpy(dst, src, width_in_bytes); | ||||
|     src += stride; | ||||
|     dst += stride; | ||||
|   } | ||||
| } | ||||
| #endif // WEBP_HAVE_GIF | ||||
|  | ||||
| // Canonicalize all transparent pixels to transparent black to aid comparison. | ||||
| static void CleanupTransparentPixels(uint32_t* rgba, | ||||
|                                      uint32_t width, uint32_t height) { | ||||
|   const uint32_t* const rgba_end = rgba + width * height; | ||||
|   while (rgba < rgba_end) { | ||||
|     const uint8_t alpha = (*rgba >> 24) & 0xff; | ||||
|     if (alpha == 0) { | ||||
|       *rgba = 0; | ||||
|     } | ||||
|     ++rgba; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Dump frame to a PAM file. Returns true on success. | ||||
| static int DumpFrame(const char filename[], const char dump_folder[], | ||||
|                      uint32_t frame_num, const uint8_t rgba[], | ||||
|                      int canvas_width, int canvas_height) { | ||||
|   int ok = 0; | ||||
|   size_t max_len; | ||||
|   int y; | ||||
|   const W_CHAR* base_name = NULL; | ||||
|   W_CHAR* file_name = NULL; | ||||
|   FILE* f = NULL; | ||||
|   const char* row; | ||||
|  | ||||
|   if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR("."); | ||||
|  | ||||
|   base_name = WSTRRCHR(filename, '/'); | ||||
|   base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1; | ||||
|   max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name) | ||||
|           + strlen("_frame_") + strlen(".pam") + 8; | ||||
|   file_name = (W_CHAR*)malloc(max_len * sizeof(*file_name)); | ||||
|   if (file_name == NULL) goto End; | ||||
|  | ||||
|   if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam", | ||||
|                 (const W_CHAR*)dump_folder, base_name, frame_num) < 0) { | ||||
|     fprintf(stderr, "Error while generating file name\n"); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   f = WFOPEN(file_name, "wb"); | ||||
|   if (f == NULL) { | ||||
|     WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name); | ||||
|     ok = 0; | ||||
|     goto End; | ||||
|   } | ||||
|   if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n" | ||||
|               "DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", | ||||
|               canvas_width, canvas_height) < 0) { | ||||
|     WFPRINTF(stderr, "Write error for file %s\n", file_name); | ||||
|     goto End; | ||||
|   } | ||||
|   row = (const char*)rgba; | ||||
|   for (y = 0; y < canvas_height; ++y) { | ||||
|     if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) { | ||||
|       WFPRINTF(stderr, "Error writing to file: %s\n", file_name); | ||||
|       goto End; | ||||
|     } | ||||
|     row += canvas_width * kNumChannels; | ||||
|   } | ||||
|   ok = 1; | ||||
|  End: | ||||
|   if (f != NULL) fclose(f); | ||||
|   free(file_name); | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // WebP Decoding. | ||||
|  | ||||
| // Returns true if this is a valid WebP bitstream. | ||||
| static int IsWebP(const WebPData* const webp_data) { | ||||
|   return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0); | ||||
| } | ||||
|  | ||||
| // Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct. | ||||
| static int ReadAnimatedWebP(const char filename[], | ||||
|                             const WebPData* const webp_data, | ||||
|                             AnimatedImage* const image, int dump_frames, | ||||
|                             const char dump_folder[]) { | ||||
|   int ok = 0; | ||||
|   int dump_ok = 1; | ||||
|   uint32_t frame_index = 0; | ||||
|   int prev_frame_timestamp = 0; | ||||
|   WebPAnimDecoder* dec; | ||||
|   WebPAnimInfo anim_info; | ||||
|  | ||||
|   memset(image, 0, sizeof(*image)); | ||||
|  | ||||
|   dec = WebPAnimDecoderNew(webp_data, NULL); | ||||
|   if (dec == NULL) { | ||||
|     WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   if (!WebPAnimDecoderGetInfo(dec, &anim_info)) { | ||||
|     fprintf(stderr, "Error getting global info about the animation\n"); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   // Animation properties. | ||||
|   image->canvas_width = anim_info.canvas_width; | ||||
|   image->canvas_height = anim_info.canvas_height; | ||||
|   image->loop_count = anim_info.loop_count; | ||||
|   image->bgcolor = anim_info.bgcolor; | ||||
|  | ||||
|   // Allocate frames. | ||||
|   if (!AllocateFrames(image, anim_info.frame_count)) return 0; | ||||
|  | ||||
|   // Decode frames. | ||||
|   while (WebPAnimDecoderHasMoreFrames(dec)) { | ||||
|     DecodedFrame* curr_frame; | ||||
|     uint8_t* curr_rgba; | ||||
|     uint8_t* frame_rgba; | ||||
|     int timestamp; | ||||
|  | ||||
|     if (!WebPAnimDecoderGetNext(dec, &frame_rgba, ×tamp)) { | ||||
|       fprintf(stderr, "Error decoding frame #%u\n", frame_index); | ||||
|       goto End; | ||||
|     } | ||||
|     assert(frame_index < anim_info.frame_count); | ||||
|     curr_frame = &image->frames[frame_index]; | ||||
|     curr_rgba = curr_frame->rgba; | ||||
|     curr_frame->duration = timestamp - prev_frame_timestamp; | ||||
|     curr_frame->is_key_frame = 0;  // Unused. | ||||
|     memcpy(curr_rgba, frame_rgba, | ||||
|            image->canvas_width * kNumChannels * image->canvas_height); | ||||
|  | ||||
|     // Needed only because we may want to compare with GIF later. | ||||
|     CleanupTransparentPixels((uint32_t*)curr_rgba, | ||||
|                              image->canvas_width, image->canvas_height); | ||||
|  | ||||
|     if (dump_frames && dump_ok) { | ||||
|       dump_ok = DumpFrame(filename, dump_folder, frame_index, curr_rgba, | ||||
|                           image->canvas_width, image->canvas_height); | ||||
|       if (!dump_ok) {  // Print error once, but continue decode loop. | ||||
|         fprintf(stderr, "Error dumping frames to %s\n", dump_folder); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ++frame_index; | ||||
|     prev_frame_timestamp = timestamp; | ||||
|   } | ||||
|   ok = dump_ok; | ||||
|   if (ok) image->format = ANIM_WEBP; | ||||
|  | ||||
|  End: | ||||
|   WebPAnimDecoderDelete(dec); | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // GIF Decoding. | ||||
|  | ||||
| #if defined(WEBP_HAVE_GIF) | ||||
|  | ||||
| // Returns true if this is a valid GIF bitstream. | ||||
| static int IsGIF(const WebPData* const data) { | ||||
|   return data->size > GIF_STAMP_LEN && | ||||
|          (!memcmp(GIF_STAMP, data->bytes, GIF_STAMP_LEN) || | ||||
|           !memcmp(GIF87_STAMP, data->bytes, GIF_STAMP_LEN) || | ||||
|           !memcmp(GIF89_STAMP, data->bytes, GIF_STAMP_LEN)); | ||||
| } | ||||
|  | ||||
| // GIFLIB_MAJOR is only defined in libgif >= 4.2.0. | ||||
| #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) | ||||
| # define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR) | ||||
| # define LOCAL_GIF_PREREQ(maj, min) \ | ||||
|     (LOCAL_GIF_VERSION >= (((maj) << 8) | (min))) | ||||
| #else | ||||
| # define LOCAL_GIF_VERSION 0 | ||||
| # define LOCAL_GIF_PREREQ(maj, min) 0 | ||||
| #endif | ||||
|  | ||||
| #if !LOCAL_GIF_PREREQ(5, 0) | ||||
|  | ||||
| // Added in v5.0 | ||||
| typedef struct { | ||||
|   int DisposalMode; | ||||
| #define DISPOSAL_UNSPECIFIED      0       // No disposal specified | ||||
| #define DISPOSE_DO_NOT            1       // Leave image in place | ||||
| #define DISPOSE_BACKGROUND        2       // Set area to background color | ||||
| #define DISPOSE_PREVIOUS          3       // Restore to previous content | ||||
|   int UserInputFlag;       // User confirmation required before disposal | ||||
|   int DelayTime;           // Pre-display delay in 0.01sec units | ||||
|   int TransparentColor;    // Palette index for transparency, -1 if none | ||||
| #define NO_TRANSPARENT_COLOR     -1 | ||||
| } GraphicsControlBlock; | ||||
|  | ||||
| static int DGifExtensionToGCB(const size_t GifExtensionLength, | ||||
|                               const GifByteType* GifExtension, | ||||
|                               GraphicsControlBlock* gcb) { | ||||
|   if (GifExtensionLength != 4) { | ||||
|     return GIF_ERROR; | ||||
|   } | ||||
|   gcb->DisposalMode = (GifExtension[0] >> 2) & 0x07; | ||||
|   gcb->UserInputFlag = (GifExtension[0] & 0x02) != 0; | ||||
|   gcb->DelayTime = GifExtension[1] | (GifExtension[2] << 8); | ||||
|   if (GifExtension[0] & 0x01) { | ||||
|     gcb->TransparentColor = (int)GifExtension[3]; | ||||
|   } else { | ||||
|     gcb->TransparentColor = NO_TRANSPARENT_COLOR; | ||||
|   } | ||||
|   return GIF_OK; | ||||
| } | ||||
|  | ||||
| static int DGifSavedExtensionToGCB(GifFileType* GifFile, int ImageIndex, | ||||
|                                    GraphicsControlBlock* gcb) { | ||||
|   int i; | ||||
|   if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) { | ||||
|     return GIF_ERROR; | ||||
|   } | ||||
|   gcb->DisposalMode = DISPOSAL_UNSPECIFIED; | ||||
|   gcb->UserInputFlag = 0; | ||||
|   gcb->DelayTime = 0; | ||||
|   gcb->TransparentColor = NO_TRANSPARENT_COLOR; | ||||
|  | ||||
|   for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) { | ||||
|     ExtensionBlock* ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i]; | ||||
|     if (ep->Function == GRAPHICS_EXT_FUNC_CODE) { | ||||
|       return DGifExtensionToGCB( | ||||
|           ep->ByteCount, (const GifByteType*)ep->Bytes, gcb); | ||||
|     } | ||||
|   } | ||||
|   return GIF_ERROR; | ||||
| } | ||||
|  | ||||
| #define CONTINUE_EXT_FUNC_CODE 0x00 | ||||
|  | ||||
| // Signature was changed in v5.0 | ||||
| #define DGifOpenFileName(a, b) DGifOpenFileName(a) | ||||
|  | ||||
| #endif  // !LOCAL_GIF_PREREQ(5, 0) | ||||
|  | ||||
| // Signature changed in v5.1 | ||||
| #if !LOCAL_GIF_PREREQ(5, 1) | ||||
| #define DGifCloseFile(a, b) DGifCloseFile(a) | ||||
| #endif | ||||
|  | ||||
| static int IsKeyFrameGIF(const GifImageDesc* prev_desc, int prev_dispose, | ||||
|                          const DecodedFrame* const prev_frame, | ||||
|                          int canvas_width, int canvas_height) { | ||||
|   if (prev_frame == NULL) return 1; | ||||
|   if (prev_dispose == DISPOSE_BACKGROUND) { | ||||
|     if (IsFullFrame(prev_desc->Width, prev_desc->Height, | ||||
|                     canvas_width, canvas_height)) { | ||||
|       return 1; | ||||
|     } | ||||
|     if (prev_frame->is_key_frame) return 1; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static int GetTransparentIndexGIF(GifFileType* gif) { | ||||
|   GraphicsControlBlock first_gcb; | ||||
|   memset(&first_gcb, 0, sizeof(first_gcb)); | ||||
|   DGifSavedExtensionToGCB(gif, 0, &first_gcb); | ||||
|   return first_gcb.TransparentColor; | ||||
| } | ||||
|  | ||||
| static uint32_t GetBackgroundColorGIF(GifFileType* gif) { | ||||
|   const int transparent_index = GetTransparentIndexGIF(gif); | ||||
|   const ColorMapObject* const color_map = gif->SColorMap; | ||||
|   if (transparent_index != NO_TRANSPARENT_COLOR && | ||||
|       gif->SBackGroundColor == transparent_index) { | ||||
|     return 0x00000000;  // Special case: transparent black. | ||||
|   } else if (color_map == NULL || color_map->Colors == NULL | ||||
|              || gif->SBackGroundColor >= color_map->ColorCount) { | ||||
|     return 0xffffffff;  // Invalid: assume white. | ||||
|   } else { | ||||
|     const GifColorType color = color_map->Colors[gif->SBackGroundColor]; | ||||
|     return (0xff << 24) | | ||||
|            (color.Red << 16) | | ||||
|            (color.Green << 8) | | ||||
|            (color.Blue << 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Find appropriate app extension and get loop count from the next extension. | ||||
| // We use Chrome's interpretation of the 'loop_count' semantics: | ||||
| //   if not present -> loop once | ||||
| //   if present and loop_count == 0, return 0 ('infinite'). | ||||
| //   if present and loop_count != 0, it's the number of *extra* loops | ||||
| //     so we need to return loop_count + 1 as total loop number. | ||||
| static uint32_t GetLoopCountGIF(const GifFileType* const gif) { | ||||
|   int i; | ||||
|   for (i = 0; i < gif->ImageCount; ++i) { | ||||
|     const SavedImage* const image = &gif->SavedImages[i]; | ||||
|     int j; | ||||
|     for (j = 0; (j + 1) < image->ExtensionBlockCount; ++j) { | ||||
|       const ExtensionBlock* const eb1 = image->ExtensionBlocks + j; | ||||
|       const ExtensionBlock* const eb2 = image->ExtensionBlocks + j + 1; | ||||
|       const char* const signature = (const char*)eb1->Bytes; | ||||
|       const int signature_is_ok = | ||||
|           (eb1->Function == APPLICATION_EXT_FUNC_CODE) && | ||||
|           (eb1->ByteCount == 11) && | ||||
|           (!memcmp(signature, "NETSCAPE2.0", 11) || | ||||
|            !memcmp(signature, "ANIMEXTS1.0", 11)); | ||||
|       if (signature_is_ok && | ||||
|           eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 && | ||||
|           eb2->Bytes[0] == 1) { | ||||
|         const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) + | ||||
|                                     ((uint32_t)(eb2->Bytes[1]) << 0); | ||||
|         return (extra_loop > 0) ? extra_loop + 1 : 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 1;  // Default. | ||||
| } | ||||
|  | ||||
| // Get duration of 'n'th frame in milliseconds. | ||||
| static int GetFrameDurationGIF(GifFileType* gif, int n) { | ||||
|   GraphicsControlBlock gcb; | ||||
|   memset(&gcb, 0, sizeof(gcb)); | ||||
|   DGifSavedExtensionToGCB(gif, n, &gcb); | ||||
|   return gcb.DelayTime * 10; | ||||
| } | ||||
|  | ||||
| // Returns true if frame 'target' completely covers 'covered'. | ||||
| static int CoversFrameGIF(const GifImageDesc* const target, | ||||
|                           const GifImageDesc* const covered) { | ||||
|   return target->Left <= covered->Left && | ||||
|          covered->Left + covered->Width <= target->Left + target->Width && | ||||
|          target->Top <= covered->Top && | ||||
|          covered->Top + covered->Height <= target->Top + target->Height; | ||||
| } | ||||
|  | ||||
| static void RemapPixelsGIF(const uint8_t* const src, | ||||
|                            const ColorMapObject* const cmap, | ||||
|                            int transparent_color, int len, uint8_t* dst) { | ||||
|   int i; | ||||
|   for (i = 0; i < len; ++i) { | ||||
|     if (src[i] != transparent_color) { | ||||
|       // If a pixel in the current frame is transparent, we don't modify it, so | ||||
|       // that we can see-through the corresponding pixel from an earlier frame. | ||||
|       const GifColorType c = cmap->Colors[src[i]]; | ||||
|       dst[4 * i + 0] = c.Red; | ||||
|       dst[4 * i + 1] = c.Green; | ||||
|       dst[4 * i + 2] = c.Blue; | ||||
|       dst[4 * i + 3] = 0xff; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| static int ReadFrameGIF(const SavedImage* const gif_image, | ||||
|                         const ColorMapObject* cmap, int transparent_color, | ||||
|                         int out_stride, uint8_t* const dst) { | ||||
|   const GifImageDesc* image_desc = &gif_image->ImageDesc; | ||||
|   const uint8_t* in; | ||||
|   uint8_t* out; | ||||
|   int j; | ||||
|  | ||||
|   if (image_desc->ColorMap) cmap = image_desc->ColorMap; | ||||
|  | ||||
|   if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) { | ||||
|     fprintf(stderr, "Potentially corrupt color map.\n"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   in = (const uint8_t*)gif_image->RasterBits; | ||||
|   out = dst + image_desc->Top * out_stride + image_desc->Left * kNumChannels; | ||||
|  | ||||
|   for (j = 0; j < image_desc->Height; ++j) { | ||||
|     RemapPixelsGIF(in, cmap, transparent_color, image_desc->Width, out); | ||||
|     in += image_desc->Width; | ||||
|     out += out_stride; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| // Read animated GIF bitstream from 'filename' into 'AnimatedImage' struct. | ||||
| static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image, | ||||
|                            int dump_frames, const char dump_folder[]) { | ||||
|   uint32_t frame_count; | ||||
|   uint32_t canvas_width, canvas_height; | ||||
|   uint32_t i; | ||||
|   int gif_error; | ||||
|   GifFileType* gif; | ||||
|  | ||||
|   gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL); | ||||
|   if (gif == NULL) { | ||||
|     WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   gif_error = DGifSlurp(gif); | ||||
|   if (gif_error != GIF_OK) { | ||||
|     WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename); | ||||
|     GIFDisplayError(gif, gif_error); | ||||
|     DGifCloseFile(gif, NULL); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   // Animation properties. | ||||
|   image->canvas_width = (uint32_t)gif->SWidth; | ||||
|   image->canvas_height = (uint32_t)gif->SHeight; | ||||
|   if (image->canvas_width > MAX_CANVAS_SIZE || | ||||
|       image->canvas_height > MAX_CANVAS_SIZE) { | ||||
|     fprintf(stderr, "Invalid canvas dimension: %d x %d\n", | ||||
|             image->canvas_width, image->canvas_height); | ||||
|     DGifCloseFile(gif, NULL); | ||||
|     return 0; | ||||
|   } | ||||
|   image->loop_count = GetLoopCountGIF(gif); | ||||
|   image->bgcolor = GetBackgroundColorGIF(gif); | ||||
|  | ||||
|   frame_count = (uint32_t)gif->ImageCount; | ||||
|   if (frame_count == 0) { | ||||
|     DGifCloseFile(gif, NULL); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (image->canvas_width == 0 || image->canvas_height == 0) { | ||||
|     image->canvas_width = gif->SavedImages[0].ImageDesc.Width; | ||||
|     image->canvas_height = gif->SavedImages[0].ImageDesc.Height; | ||||
|     gif->SavedImages[0].ImageDesc.Left = 0; | ||||
|     gif->SavedImages[0].ImageDesc.Top = 0; | ||||
|     if (image->canvas_width == 0 || image->canvas_height == 0) { | ||||
|       fprintf(stderr, "Invalid canvas size in GIF.\n"); | ||||
|       DGifCloseFile(gif, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|   // Allocate frames. | ||||
|   AllocateFrames(image, frame_count); | ||||
|  | ||||
|   canvas_width = image->canvas_width; | ||||
|   canvas_height = image->canvas_height; | ||||
|  | ||||
|   // Decode and reconstruct frames. | ||||
|   for (i = 0; i < frame_count; ++i) { | ||||
|     const int canvas_width_in_bytes = canvas_width * kNumChannels; | ||||
|     const SavedImage* const curr_gif_image = &gif->SavedImages[i]; | ||||
|     GraphicsControlBlock curr_gcb; | ||||
|     DecodedFrame* curr_frame; | ||||
|     uint8_t* curr_rgba; | ||||
|  | ||||
|     memset(&curr_gcb, 0, sizeof(curr_gcb)); | ||||
|     DGifSavedExtensionToGCB(gif, i, &curr_gcb); | ||||
|  | ||||
|     curr_frame = &image->frames[i]; | ||||
|     curr_rgba = curr_frame->rgba; | ||||
|     curr_frame->duration = GetFrameDurationGIF(gif, i); | ||||
|     // Force frames with a small or no duration to 100ms to be consistent | ||||
|     // with web browsers and other transcoding tools (like gif2webp itself). | ||||
|     if (curr_frame->duration <= 10) curr_frame->duration = 100; | ||||
|  | ||||
|     if (i == 0) {  // Initialize as transparent. | ||||
|       curr_frame->is_key_frame = 1; | ||||
|       ZeroFillCanvas(curr_rgba, canvas_width, canvas_height); | ||||
|     } else { | ||||
|       DecodedFrame* const prev_frame = &image->frames[i - 1]; | ||||
|       const GifImageDesc* const prev_desc = &gif->SavedImages[i - 1].ImageDesc; | ||||
|       GraphicsControlBlock prev_gcb; | ||||
|       memset(&prev_gcb, 0, sizeof(prev_gcb)); | ||||
|       DGifSavedExtensionToGCB(gif, i - 1, &prev_gcb); | ||||
|  | ||||
|       curr_frame->is_key_frame = | ||||
|           IsKeyFrameGIF(prev_desc, prev_gcb.DisposalMode, prev_frame, | ||||
|                         canvas_width, canvas_height); | ||||
|  | ||||
|       if (curr_frame->is_key_frame) {  // Initialize as transparent. | ||||
|         ZeroFillCanvas(curr_rgba, canvas_width, canvas_height); | ||||
|       } else { | ||||
|         int prev_frame_disposed, curr_frame_opaque; | ||||
|         int prev_frame_completely_covered; | ||||
|         // Initialize with previous canvas. | ||||
|         uint8_t* const prev_rgba = image->frames[i - 1].rgba; | ||||
|         CopyCanvas(prev_rgba, curr_rgba, canvas_width, canvas_height); | ||||
|  | ||||
|         // Dispose previous frame rectangle. | ||||
|         prev_frame_disposed = | ||||
|             (prev_gcb.DisposalMode == DISPOSE_BACKGROUND || | ||||
|              prev_gcb.DisposalMode == DISPOSE_PREVIOUS); | ||||
|         curr_frame_opaque = | ||||
|             (curr_gcb.TransparentColor == NO_TRANSPARENT_COLOR); | ||||
|         prev_frame_completely_covered = | ||||
|             curr_frame_opaque && | ||||
|             CoversFrameGIF(&curr_gif_image->ImageDesc, prev_desc); | ||||
|  | ||||
|         if (prev_frame_disposed && !prev_frame_completely_covered) { | ||||
|           switch (prev_gcb.DisposalMode) { | ||||
|             case DISPOSE_BACKGROUND: { | ||||
|               ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes, | ||||
|                                 prev_desc->Left, prev_desc->Top, | ||||
|                                 prev_desc->Width, prev_desc->Height); | ||||
|               break; | ||||
|             } | ||||
|             case DISPOSE_PREVIOUS: { | ||||
|               int src_frame_num = i - 2; | ||||
|               while (src_frame_num >= 0) { | ||||
|                 GraphicsControlBlock src_frame_gcb; | ||||
|                 memset(&src_frame_gcb, 0, sizeof(src_frame_gcb)); | ||||
|                 DGifSavedExtensionToGCB(gif, src_frame_num, &src_frame_gcb); | ||||
|                 if (src_frame_gcb.DisposalMode != DISPOSE_PREVIOUS) break; | ||||
|                 --src_frame_num; | ||||
|               } | ||||
|               if (src_frame_num >= 0) { | ||||
|                 // Restore pixels inside previous frame rectangle to | ||||
|                 // corresponding pixels in source canvas. | ||||
|                 uint8_t* const src_frame_rgba = | ||||
|                     image->frames[src_frame_num].rgba; | ||||
|                 CopyFrameRectangle(src_frame_rgba, curr_rgba, | ||||
|                                    canvas_width_in_bytes, | ||||
|                                    prev_desc->Left, prev_desc->Top, | ||||
|                                    prev_desc->Width, prev_desc->Height); | ||||
|               } else { | ||||
|                 // Source canvas doesn't exist. So clear previous frame | ||||
|                 // rectangle to background. | ||||
|                 ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes, | ||||
|                                   prev_desc->Left, prev_desc->Top, | ||||
|                                   prev_desc->Width, prev_desc->Height); | ||||
|               } | ||||
|               break; | ||||
|             } | ||||
|             default: | ||||
|               break;  // Nothing to do. | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Decode current frame. | ||||
|     if (!ReadFrameGIF(curr_gif_image, gif->SColorMap, curr_gcb.TransparentColor, | ||||
|                       canvas_width_in_bytes, curr_rgba)) { | ||||
|       DGifCloseFile(gif, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     if (dump_frames) { | ||||
|       if (!DumpFrame(filename, dump_folder, i, curr_rgba, | ||||
|                      canvas_width, canvas_height)) { | ||||
|         DGifCloseFile(gif, NULL); | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   image->format = ANIM_GIF; | ||||
|   DGifCloseFile(gif, NULL); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| static int IsGIF(const WebPData* const data) { | ||||
|   (void)data; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image, | ||||
|                            int dump_frames, const char dump_folder[]) { | ||||
|   (void)filename; | ||||
|   (void)image; | ||||
|   (void)dump_frames; | ||||
|   (void)dump_folder; | ||||
|   fprintf(stderr, "GIF support not compiled. Please install the libgif-dev " | ||||
|           "package before building.\n"); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| #endif  // WEBP_HAVE_GIF | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
|  | ||||
| int ReadAnimatedImage(const char filename[], AnimatedImage* const image, | ||||
|                       int dump_frames, const char dump_folder[]) { | ||||
|   int ok = 0; | ||||
|   WebPData webp_data; | ||||
|  | ||||
|   WebPDataInit(&webp_data); | ||||
|   memset(image, 0, sizeof(*image)); | ||||
|  | ||||
|   if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) { | ||||
|     WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (IsWebP(&webp_data)) { | ||||
|     ok = ReadAnimatedWebP(filename, &webp_data, image, dump_frames, | ||||
|                           dump_folder); | ||||
|   } else if (IsGIF(&webp_data)) { | ||||
|     ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder); | ||||
|   } else { | ||||
|     WFPRINTF(stderr, | ||||
|              "Unknown file type: %s. Supported file types are WebP and GIF\n", | ||||
|              (const W_CHAR*)filename); | ||||
|     ok = 0; | ||||
|   } | ||||
|   if (!ok) ClearAnimatedImage(image); | ||||
|   WebPDataClear(&webp_data); | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| static void Accumulate(double v1, double v2, double* const max_diff, | ||||
|                        double* const sse) { | ||||
|   const double diff = fabs(v1 - v2); | ||||
|   if (diff > *max_diff) *max_diff = diff; | ||||
|   *sse += diff * diff; | ||||
| } | ||||
|  | ||||
| void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], | ||||
|                     uint32_t width, uint32_t height, int premultiply, | ||||
|                     int* const max_diff, double* const psnr) { | ||||
|   const uint32_t stride = width * kNumChannels; | ||||
|   const int kAlphaChannel = kNumChannels - 1; | ||||
|   double f_max_diff = 0.; | ||||
|   double sse = 0.; | ||||
|   uint32_t x, y; | ||||
|   for (y = 0; y < height; ++y) { | ||||
|     for (x = 0; x < stride; x += kNumChannels) { | ||||
|       int k; | ||||
|       const size_t offset = (size_t)y * stride + x; | ||||
|       const int alpha1 = rgba1[offset + kAlphaChannel]; | ||||
|       const int alpha2 = rgba2[offset + kAlphaChannel]; | ||||
|       Accumulate(alpha1, alpha2, &f_max_diff, &sse); | ||||
|       if (!premultiply) { | ||||
|         for (k = 0; k < kAlphaChannel; ++k) { | ||||
|           Accumulate(rgba1[offset + k], rgba2[offset + k], &f_max_diff, &sse); | ||||
|         } | ||||
|       } else { | ||||
|         // premultiply R/G/B channels with alpha value | ||||
|         for (k = 0; k < kAlphaChannel; ++k) { | ||||
|           Accumulate(rgba1[offset + k] * alpha1 / 255., | ||||
|                      rgba2[offset + k] * alpha2 / 255., | ||||
|                      &f_max_diff, &sse); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   *max_diff = (int)f_max_diff; | ||||
|   if (*max_diff == 0) { | ||||
|     *psnr = 99.;  // PSNR when images are identical. | ||||
|   } else { | ||||
|     sse /= stride * height; | ||||
|     *psnr = 4.3429448 * log(255. * 255. / sse); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GetAnimatedImageVersions(int* const decoder_version, | ||||
|                               int* const demux_version) { | ||||
|   *decoder_version = WebPGetDecoderVersion(); | ||||
|   *demux_version = WebPGetDemuxVersion(); | ||||
| } | ||||
							
								
								
									
										73
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_util.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/anim_util.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| // Copyright 2015 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // Utilities for animated images | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_ANIM_UTIL_H_ | ||||
| #define WEBP_EXAMPLES_ANIM_UTIL_H_ | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #include "webp/types.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef enum { | ||||
|   ANIM_GIF, | ||||
|   ANIM_WEBP | ||||
| } AnimatedFileFormat; | ||||
|  | ||||
| typedef struct { | ||||
|   uint8_t* rgba;         // Decoded and reconstructed full frame. | ||||
|   int duration;          // Frame duration in milliseconds. | ||||
|   int is_key_frame;      // True if this frame is a key-frame. | ||||
| } DecodedFrame; | ||||
|  | ||||
| typedef struct { | ||||
|   AnimatedFileFormat format; | ||||
|   uint32_t canvas_width; | ||||
|   uint32_t canvas_height; | ||||
|   uint32_t bgcolor; | ||||
|   uint32_t loop_count; | ||||
|   DecodedFrame* frames; | ||||
|   uint32_t num_frames; | ||||
|   void* raw_mem; | ||||
| } AnimatedImage; | ||||
|  | ||||
| // Deallocate everything in 'image' (but not the object itself). | ||||
| void ClearAnimatedImage(AnimatedImage* const image); | ||||
|  | ||||
| // Read animated image file into 'AnimatedImage' struct. | ||||
| // If 'dump_frames' is true, dump frames to 'dump_folder'. | ||||
| // Previous content of 'image' is obliterated. | ||||
| // Upon successful return, content of 'image' must be deleted by | ||||
| // calling 'ClearAnimatedImage'. | ||||
| int ReadAnimatedImage(const char filename[], AnimatedImage* const image, | ||||
|                       int dump_frames, const char dump_folder[]); | ||||
|  | ||||
| // Given two RGBA buffers, calculate max pixel difference and PSNR. | ||||
| // If 'premultiply' is true, R/G/B values will be pre-multiplied by the | ||||
| // transparency before comparison. | ||||
| void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], | ||||
|                     uint32_t width, uint32_t height, int premultiply, | ||||
|                     int* const max_diff, double* const psnr); | ||||
|  | ||||
| // Return library versions used by anim_util. | ||||
| void GetAnimatedImageVersions(int* const decoder_version, | ||||
|                               int* const demux_version); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| }    // extern "C" | ||||
| #endif | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_ANIM_UTIL_H_ | ||||
							
								
								
									
										1182
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/cwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1182
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/cwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										420
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/dwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/dwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,420 @@ | ||||
| // Copyright 2010 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  Command-line tool for decoding a WebP image. | ||||
| // | ||||
| // Author: Skal (pascal.massimino@gmail.com) | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #include "../examples/example_util.h" | ||||
| #include "../imageio/image_enc.h" | ||||
| #include "../imageio/webpdec.h" | ||||
| #include "./stopwatch.h" | ||||
| #include "./unicode.h" | ||||
|  | ||||
| static int verbose = 0; | ||||
| static int quiet = 0; | ||||
| #ifndef WEBP_DLL | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| extern void* VP8GetCPUInfo;   // opaque forward declaration. | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| }    // extern "C" | ||||
| #endif | ||||
| #endif  // WEBP_DLL | ||||
|  | ||||
|  | ||||
| static int SaveOutput(const WebPDecBuffer* const buffer, | ||||
|                       WebPOutputFileFormat format, const char* const out_file) { | ||||
|   const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-"); | ||||
|   int ok = 1; | ||||
|   Stopwatch stop_watch; | ||||
|  | ||||
|   if (verbose) { | ||||
|     StopwatchReset(&stop_watch); | ||||
|   } | ||||
|   ok = WebPSaveImage(buffer, format, out_file); | ||||
|  | ||||
|   if (ok) { | ||||
|     if (!quiet) { | ||||
|       if (use_stdout) { | ||||
|         fprintf(stderr, "Saved to stdout\n"); | ||||
|       } else { | ||||
|         WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file); | ||||
|       } | ||||
|     } | ||||
|     if (verbose) { | ||||
|       const double write_time = StopwatchReadAndReset(&stop_watch); | ||||
|       fprintf(stderr, "Time to write output: %.3fs\n", write_time); | ||||
|     } | ||||
|   } else { | ||||
|     if (use_stdout) { | ||||
|       fprintf(stderr, "Error writing to stdout !!\n"); | ||||
|     } else { | ||||
|       WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file); | ||||
|     } | ||||
|   } | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf("Usage: dwebp in_file [options] [-o out_file]\n\n" | ||||
|          "Decodes the WebP image file to PNG format [Default]\n" | ||||
|          "Use following options to convert into alternate image formats:\n" | ||||
|          "  -pam ......... save the raw RGBA samples as a color PAM\n" | ||||
|          "  -ppm ......... save the raw RGB samples as a color PPM\n" | ||||
|          "  -bmp ......... save as uncompressed BMP format\n" | ||||
|          "  -tiff ........ save as uncompressed TIFF format\n" | ||||
|          "  -pgm ......... save the raw YUV samples as a grayscale PGM\n" | ||||
|          "                 file with IMC4 layout\n" | ||||
|          "  -yuv ......... save the raw YUV samples in flat layout\n" | ||||
|          "\n" | ||||
|          " Other options are:\n" | ||||
|          "  -version ..... print version number and exit\n" | ||||
|          "  -nofancy ..... don't use the fancy YUV420 upscaler\n" | ||||
|          "  -nofilter .... disable in-loop filtering\n" | ||||
|          "  -nodither .... disable dithering\n" | ||||
|          "  -dither <d> .. dithering strength (in 0..100)\n" | ||||
|          "  -alpha_dither  use alpha-plane dithering if needed\n" | ||||
|          "  -mt .......... use multi-threading\n" | ||||
|          "  -crop <x> <y> <w> <h> ... crop output with the given rectangle\n" | ||||
|          "  -resize <w> <h> ......... scale the output (*after* any cropping)\n" | ||||
|          "  -flip ........ flip the output vertically\n" | ||||
|          "  -alpha ....... only save the alpha plane\n" | ||||
|          "  -incremental . use incremental decoding (useful for tests)\n" | ||||
|          "  -h ........... this help message\n" | ||||
|          "  -v ........... verbose (e.g. print encoding/decoding times)\n" | ||||
|          "  -quiet ....... quiet mode, don't print anything\n" | ||||
| #ifndef WEBP_DLL | ||||
|          "  -noasm ....... disable all assembly optimizations\n" | ||||
| #endif | ||||
|         ); | ||||
| } | ||||
|  | ||||
| static const char* const kFormatType[] = { | ||||
|   "unspecified", "lossy", "lossless" | ||||
| }; | ||||
|  | ||||
| static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config, | ||||
|                                        WebPOutputFileFormat format, | ||||
|                                        int use_external_memory) { | ||||
|   uint8_t* external_buffer = NULL; | ||||
|   WebPDecBuffer* const output_buffer = &config->output; | ||||
|   int w = config->input.width; | ||||
|   int h = config->input.height; | ||||
|   if (config->options.use_scaling) { | ||||
|     w = config->options.scaled_width; | ||||
|     h = config->options.scaled_height; | ||||
|   } else if (config->options.use_cropping) { | ||||
|     w = config->options.crop_width; | ||||
|     h = config->options.crop_height; | ||||
|   } | ||||
|   if (format >= RGB && format <= rgbA_4444) { | ||||
|     const int bpp = (format == RGB || format == BGR) ? 3 | ||||
|                   : (format == RGBA_4444 || format == rgbA_4444 || | ||||
|                      format == RGB_565) ? 2 | ||||
|                   : 4; | ||||
|     uint32_t stride = bpp * w + 7;   // <- just for exercising | ||||
|     external_buffer = (uint8_t*)malloc(stride * h); | ||||
|     if (external_buffer == NULL) return NULL; | ||||
|     output_buffer->u.RGBA.stride = stride; | ||||
|     output_buffer->u.RGBA.size = stride * h; | ||||
|     output_buffer->u.RGBA.rgba = external_buffer; | ||||
|   } else {    // YUV and YUVA | ||||
|     const int has_alpha = WebPIsAlphaMode(output_buffer->colorspace); | ||||
|     uint8_t* tmp; | ||||
|     uint32_t stride = w + 3; | ||||
|     uint32_t uv_stride = (w + 1) / 2 + 13; | ||||
|     uint32_t total_size = stride * h * (has_alpha ? 2 : 1) | ||||
|                         + 2 * uv_stride * (h + 1) / 2; | ||||
|     assert(format >= YUV && format <= YUVA); | ||||
|     external_buffer = (uint8_t*)malloc(total_size); | ||||
|     if (external_buffer == NULL) return NULL; | ||||
|     tmp = external_buffer; | ||||
|     output_buffer->u.YUVA.y = tmp; | ||||
|     output_buffer->u.YUVA.y_stride = stride; | ||||
|     output_buffer->u.YUVA.y_size = stride * h; | ||||
|     tmp += output_buffer->u.YUVA.y_size; | ||||
|     if (has_alpha) { | ||||
|       output_buffer->u.YUVA.a = tmp; | ||||
|       output_buffer->u.YUVA.a_stride = stride; | ||||
|       output_buffer->u.YUVA.a_size = stride * h; | ||||
|       tmp += output_buffer->u.YUVA.a_size; | ||||
|     } else { | ||||
|       output_buffer->u.YUVA.a = NULL; | ||||
|       output_buffer->u.YUVA.a_stride = 0; | ||||
|     } | ||||
|     output_buffer->u.YUVA.u = tmp; | ||||
|     output_buffer->u.YUVA.u_stride = uv_stride; | ||||
|     output_buffer->u.YUVA.u_size = uv_stride * (h + 1) / 2; | ||||
|     tmp += output_buffer->u.YUVA.u_size; | ||||
|  | ||||
|     output_buffer->u.YUVA.v = tmp; | ||||
|     output_buffer->u.YUVA.v_stride = uv_stride; | ||||
|     output_buffer->u.YUVA.v_size = uv_stride * (h + 1) / 2; | ||||
|     tmp += output_buffer->u.YUVA.v_size; | ||||
|     assert(tmp <= external_buffer + total_size); | ||||
|   } | ||||
|   output_buffer->is_external_memory = use_external_memory; | ||||
|   return external_buffer; | ||||
| } | ||||
|  | ||||
| int main(int argc, const char *argv[]) { | ||||
|   int ok = 0; | ||||
|   const char *in_file = NULL; | ||||
|   const char *out_file = NULL; | ||||
|  | ||||
|   WebPDecoderConfig config; | ||||
|   WebPDecBuffer* const output_buffer = &config.output; | ||||
|   WebPBitstreamFeatures* const bitstream = &config.input; | ||||
|   WebPOutputFileFormat format = PNG; | ||||
|   uint8_t* external_buffer = NULL; | ||||
|   int use_external_memory = 0; | ||||
|   const uint8_t* data = NULL; | ||||
|  | ||||
|   int incremental = 0; | ||||
|   int c; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   if (!WebPInitDecoderConfig(&config)) { | ||||
|     fprintf(stderr, "Library version mismatch!\n"); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|  | ||||
|   for (c = 1; c < argc; ++c) { | ||||
|     int parse_error = 0; | ||||
|     if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-o") && c < argc - 1) { | ||||
|       out_file = (const char*)GET_WARGV(argv, ++c); | ||||
|     } else if (!strcmp(argv[c], "-alpha")) { | ||||
|       format = ALPHA_PLANE_ONLY; | ||||
|     } else if (!strcmp(argv[c], "-nofancy")) { | ||||
|       config.options.no_fancy_upsampling = 1; | ||||
|     } else if (!strcmp(argv[c], "-nofilter")) { | ||||
|       config.options.bypass_filtering = 1; | ||||
|     } else if (!strcmp(argv[c], "-pam")) { | ||||
|       format = PAM; | ||||
|     } else if (!strcmp(argv[c], "-ppm")) { | ||||
|       format = PPM; | ||||
|     } else if (!strcmp(argv[c], "-bmp")) { | ||||
|       format = BMP; | ||||
|     } else if (!strcmp(argv[c], "-tiff")) { | ||||
|       format = TIFF; | ||||
|     } else if (!strcmp(argv[c], "-quiet")) { | ||||
|       quiet = 1; | ||||
|     } else if (!strcmp(argv[c], "-version")) { | ||||
|       const int version = WebPGetDecoderVersion(); | ||||
|       printf("%d.%d.%d\n", | ||||
|              (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-pgm")) { | ||||
|       format = PGM; | ||||
|     } else if (!strcmp(argv[c], "-yuv")) { | ||||
|       format = RAW_YUV; | ||||
|     } else if (!strcmp(argv[c], "-pixel_format") && c < argc - 1) { | ||||
|       const char* const fmt = argv[++c]; | ||||
|       if      (!strcmp(fmt, "RGB"))  format = RGB; | ||||
|       else if (!strcmp(fmt, "RGBA")) format = RGBA; | ||||
|       else if (!strcmp(fmt, "BGR"))  format = BGR; | ||||
|       else if (!strcmp(fmt, "BGRA")) format = BGRA; | ||||
|       else if (!strcmp(fmt, "ARGB")) format = ARGB; | ||||
|       else if (!strcmp(fmt, "RGBA_4444")) format = RGBA_4444; | ||||
|       else if (!strcmp(fmt, "RGB_565")) format = RGB_565; | ||||
|       else if (!strcmp(fmt, "rgbA")) format = rgbA; | ||||
|       else if (!strcmp(fmt, "bgrA")) format = bgrA; | ||||
|       else if (!strcmp(fmt, "Argb")) format = Argb; | ||||
|       else if (!strcmp(fmt, "rgbA_4444")) format = rgbA_4444; | ||||
|       else if (!strcmp(fmt, "YUV"))  format = YUV; | ||||
|       else if (!strcmp(fmt, "YUVA")) format = YUVA; | ||||
|       else { | ||||
|         fprintf(stderr, "Can't parse pixel_format %s\n", fmt); | ||||
|         parse_error = 1; | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-external_memory") && c < argc - 1) { | ||||
|       use_external_memory = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       parse_error |= (use_external_memory > 2 || use_external_memory < 0); | ||||
|       if (parse_error) { | ||||
|         fprintf(stderr, "Can't parse 'external_memory' value %s\n", argv[c]); | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-mt")) { | ||||
|       config.options.use_threads = 1; | ||||
|     } else if (!strcmp(argv[c], "-alpha_dither")) { | ||||
|       config.options.alpha_dithering_strength = 100; | ||||
|     } else if (!strcmp(argv[c], "-nodither")) { | ||||
|       config.options.dithering_strength = 0; | ||||
|     } else if (!strcmp(argv[c], "-dither") && c < argc - 1) { | ||||
|       config.options.dithering_strength = | ||||
|           ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-crop") && c < argc - 4) { | ||||
|       config.options.use_cropping = 1; | ||||
|       config.options.crop_left   = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       config.options.crop_top    = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       config.options.crop_width  = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       config.options.crop_height = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if ((!strcmp(argv[c], "-scale") || !strcmp(argv[c], "-resize")) && | ||||
|                c < argc - 2) {  // '-scale' is left for compatibility | ||||
|       config.options.use_scaling = 1; | ||||
|       config.options.scaled_width  = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       config.options.scaled_height = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-flip")) { | ||||
|       config.options.flip = 1; | ||||
|     } else if (!strcmp(argv[c], "-v")) { | ||||
|       verbose = 1; | ||||
| #ifndef WEBP_DLL | ||||
|     } else if (!strcmp(argv[c], "-noasm")) { | ||||
|       VP8GetCPUInfo = NULL; | ||||
| #endif | ||||
|     } else if (!strcmp(argv[c], "-incremental")) { | ||||
|       incremental = 1; | ||||
|     } else if (!strcmp(argv[c], "--")) { | ||||
|       if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c); | ||||
|       break; | ||||
|     } else if (argv[c][0] == '-') { | ||||
|       fprintf(stderr, "Unknown option '%s'\n", argv[c]); | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } else { | ||||
|       in_file = (const char*)GET_WARGV(argv, c); | ||||
|     } | ||||
|  | ||||
|     if (parse_error) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (in_file == NULL) { | ||||
|     fprintf(stderr, "missing input file!!\n"); | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|  | ||||
|   if (quiet) verbose = 0; | ||||
|  | ||||
|   { | ||||
|     VP8StatusCode status = VP8_STATUS_OK; | ||||
|     size_t data_size = 0; | ||||
|     if (!LoadWebP(in_file, &data, &data_size, bitstream)) { | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } | ||||
|  | ||||
|     switch (format) { | ||||
|       case PNG: | ||||
| #ifdef HAVE_WINCODEC_H | ||||
|         output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; | ||||
| #else | ||||
|         output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; | ||||
| #endif | ||||
|         break; | ||||
|       case PAM: | ||||
|         output_buffer->colorspace = MODE_RGBA; | ||||
|         break; | ||||
|       case PPM: | ||||
|         output_buffer->colorspace = MODE_RGB;  // drops alpha for PPM | ||||
|         break; | ||||
|       case BMP: | ||||
|         output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; | ||||
|         break; | ||||
|       case TIFF: | ||||
|         output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; | ||||
|         break; | ||||
|       case PGM: | ||||
|       case RAW_YUV: | ||||
|         output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV; | ||||
|         break; | ||||
|       case ALPHA_PLANE_ONLY: | ||||
|         output_buffer->colorspace = MODE_YUVA; | ||||
|         break; | ||||
|       // forced modes: | ||||
|       case RGB: output_buffer->colorspace = MODE_RGB; break; | ||||
|       case RGBA: output_buffer->colorspace = MODE_RGBA; break; | ||||
|       case BGR: output_buffer->colorspace = MODE_BGR; break; | ||||
|       case BGRA: output_buffer->colorspace = MODE_BGRA; break; | ||||
|       case ARGB: output_buffer->colorspace = MODE_ARGB; break; | ||||
|       case RGBA_4444: output_buffer->colorspace = MODE_RGBA_4444; break; | ||||
|       case RGB_565: output_buffer->colorspace = MODE_RGB_565; break; | ||||
|       case rgbA: output_buffer->colorspace = MODE_rgbA; break; | ||||
|       case bgrA: output_buffer->colorspace = MODE_bgrA; break; | ||||
|       case Argb: output_buffer->colorspace = MODE_Argb; break; | ||||
|       case rgbA_4444: output_buffer->colorspace = MODE_rgbA_4444; break; | ||||
|       case YUV: output_buffer->colorspace = MODE_YUV; break; | ||||
|       case YUVA: output_buffer->colorspace = MODE_YUVA; break; | ||||
|       default: goto Exit; | ||||
|     } | ||||
|  | ||||
|     if (use_external_memory > 0 && format >= RGB) { | ||||
|       external_buffer = AllocateExternalBuffer(&config, format, | ||||
|                                                use_external_memory); | ||||
|       if (external_buffer == NULL) goto Exit; | ||||
|     } | ||||
|  | ||||
|     { | ||||
|       Stopwatch stop_watch; | ||||
|       if (verbose) StopwatchReset(&stop_watch); | ||||
|  | ||||
|       if (incremental) { | ||||
|         status = DecodeWebPIncremental(data, data_size, &config); | ||||
|       } else { | ||||
|         status = DecodeWebP(data, data_size, &config); | ||||
|       } | ||||
|       if (verbose) { | ||||
|         const double decode_time = StopwatchReadAndReset(&stop_watch); | ||||
|         fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ok = (status == VP8_STATUS_OK); | ||||
|     if (!ok) { | ||||
|       PrintWebPError(in_file, status); | ||||
|       goto Exit; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (out_file != NULL) { | ||||
|     if (!quiet) { | ||||
|       WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file); | ||||
|       fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n", | ||||
|               output_buffer->width, output_buffer->height, | ||||
|               bitstream->has_alpha ? " (with alpha)" : "", | ||||
|               kFormatType[bitstream->format]); | ||||
|     } | ||||
|     ok = SaveOutput(output_buffer, format, out_file); | ||||
|   } else { | ||||
|     if (!quiet) { | ||||
|       WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file); | ||||
|       fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n", | ||||
|               output_buffer->width, output_buffer->height, | ||||
|               bitstream->has_alpha ? " (with alpha)" : "", | ||||
|               kFormatType[bitstream->format]); | ||||
|       fprintf(stderr, "Nothing written; " | ||||
|                       "use -o flag to save the result as e.g. PNG.\n"); | ||||
|     } | ||||
|   } | ||||
|  Exit: | ||||
|   WebPFreeDecBuffer(output_buffer); | ||||
|   free((void*)external_buffer); | ||||
|   free((void*)data); | ||||
|   FREE_WARGV_AND_RETURN(ok ? 0 : -1); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
							
								
								
									
										135
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/example_util.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/example_util.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| // Copyright 2012 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  Utility functions used by the example programs. | ||||
| // | ||||
|  | ||||
| #include "./example_util.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "webp/mux_types.h" | ||||
| #include "../imageio/imageio_util.h" | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // String parsing | ||||
|  | ||||
| uint32_t ExUtilGetUInt(const char* const v, int base, int* const error) { | ||||
|   char* end = NULL; | ||||
|   const uint32_t n = (v != NULL) ? (uint32_t)strtoul(v, &end, base) : 0u; | ||||
|   if (end == v && error != NULL && !*error) { | ||||
|     *error = 1; | ||||
|     fprintf(stderr, "Error! '%s' is not an integer.\n", | ||||
|             (v != NULL) ? v : "(null)"); | ||||
|   } | ||||
|   return n; | ||||
| } | ||||
|  | ||||
| int ExUtilGetInt(const char* const v, int base, int* const error) { | ||||
|   return (int)ExUtilGetUInt(v, base, error); | ||||
| } | ||||
|  | ||||
| int ExUtilGetInts(const char* v, int base, int max_output, int output[]) { | ||||
|   int n, error = 0; | ||||
|   for (n = 0; v != NULL && n < max_output; ++n) { | ||||
|     const int value = ExUtilGetInt(v, base, &error); | ||||
|     if (error) return -1; | ||||
|     output[n] = value; | ||||
|     v = strchr(v, ','); | ||||
|     if (v != NULL) ++v;   // skip over the trailing ',' | ||||
|   } | ||||
|   return n; | ||||
| } | ||||
|  | ||||
| float ExUtilGetFloat(const char* const v, int* const error) { | ||||
|   char* end = NULL; | ||||
|   const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f; | ||||
|   if (end == v && error != NULL && !*error) { | ||||
|     *error = 1; | ||||
|     fprintf(stderr, "Error! '%s' is not a floating point number.\n", | ||||
|             (v != NULL) ? v : "(null)"); | ||||
|   } | ||||
|   return f; | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| static void ResetCommandLineArguments(int argc, const char* argv[], | ||||
|                                       CommandLineArguments* const args) { | ||||
|   assert(args != NULL); | ||||
|   args->argc_ = argc; | ||||
|   args->argv_ = argv; | ||||
|   args->own_argv_ = 0; | ||||
|   WebPDataInit(&args->argv_data_); | ||||
| } | ||||
|  | ||||
| void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) { | ||||
|   if (args != NULL) { | ||||
|     if (args->own_argv_) { | ||||
|       free((void*)args->argv_); | ||||
|       WebPDataClear(&args->argv_data_); | ||||
|     } | ||||
|     ResetCommandLineArguments(0, NULL, args); | ||||
|   } | ||||
| } | ||||
|  | ||||
| #define MAX_ARGC 16384 | ||||
| int ExUtilInitCommandLineArguments(int argc, const char* argv[], | ||||
|                                    CommandLineArguments* const args) { | ||||
|   if (args == NULL || argv == NULL) return 0; | ||||
|   ResetCommandLineArguments(argc, argv, args); | ||||
|   if (argc == 1 && argv[0][0] != '-') { | ||||
|     char* cur; | ||||
|     const char sep[] = " \t\r\n\f\v"; | ||||
|  | ||||
| #if defined(_WIN32) && defined(_UNICODE) | ||||
|     fprintf(stderr, | ||||
|             "Error: Reading arguments from a file is a feature unavailable " | ||||
|             "with Unicode binaries.\n"); | ||||
|     return 0; | ||||
| #endif | ||||
|  | ||||
|     if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) { | ||||
|       return 0; | ||||
|     } | ||||
|     args->own_argv_ = 1; | ||||
|     args->argv_ = (const char**)malloc(MAX_ARGC * sizeof(*args->argv_)); | ||||
|     if (args->argv_ == NULL) return 0; | ||||
|  | ||||
|     argc = 0; | ||||
|     for (cur = strtok((char*)args->argv_data_.bytes, sep); | ||||
|          cur != NULL; | ||||
|          cur = strtok(NULL, sep)) { | ||||
|       if (argc == MAX_ARGC) { | ||||
|         fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC); | ||||
|         return 0; | ||||
|       } | ||||
|       assert(strlen(cur) != 0); | ||||
|       args->argv_[argc++] = cur; | ||||
|     } | ||||
|     args->argc_ = argc; | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| int ExUtilReadFileToWebPData(const char* const filename, | ||||
|                              WebPData* const webp_data) { | ||||
|   const uint8_t* data; | ||||
|   size_t size; | ||||
|   if (webp_data == NULL) return 0; | ||||
|   if (!ImgIoUtilReadFile(filename, &data, &size)) return 0; | ||||
|   webp_data->bytes = data; | ||||
|   webp_data->size = size; | ||||
|   return 1; | ||||
| } | ||||
							
								
								
									
										70
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/example_util.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/example_util.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| // Copyright 2012 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  Utility functions used by the example programs. | ||||
| // | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_ | ||||
| #define WEBP_EXAMPLES_EXAMPLE_UTIL_H_ | ||||
|  | ||||
| #include "webp/types.h" | ||||
| #include "webp/mux_types.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // String parsing | ||||
|  | ||||
| // Parses 'v' using strto(ul|l|d)(). If error is non-NULL, '*error' is set to | ||||
| // true on failure while on success it is left unmodified to allow chaining of | ||||
| // calls. An error is only printed on the first occurrence. | ||||
| uint32_t ExUtilGetUInt(const char* const v, int base, int* const error); | ||||
| int ExUtilGetInt(const char* const v, int base, int* const error); | ||||
| float ExUtilGetFloat(const char* const v, int* const error); | ||||
|  | ||||
| // This variant of ExUtilGetInt() will parse multiple integers from a | ||||
| // comma-separated list. Up to 'max_output' integers are parsed. | ||||
| // The result is placed in the output[] array, and the number of integers | ||||
| // actually parsed is returned, or -1 if an error occurred. | ||||
| int ExUtilGetInts(const char* v, int base, int max_output, int output[]); | ||||
|  | ||||
| // Reads a file named 'filename' into a WebPData structure. The content of | ||||
| // webp_data is overwritten. Returns false in case of error. | ||||
| int ExUtilReadFileToWebPData(const char* const filename, | ||||
|                              WebPData* const webp_data); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Command-line arguments | ||||
|  | ||||
| typedef struct { | ||||
|   int argc_; | ||||
|   const char** argv_; | ||||
|   WebPData argv_data_; | ||||
|   int own_argv_; | ||||
| } CommandLineArguments; | ||||
|  | ||||
| // Initializes the structure from the command-line parameters. If there is | ||||
| // only one parameter and it does not start with a '-', then it is assumed to | ||||
| // be a file name. This file will be read and tokenized into command-line | ||||
| // arguments. The content of 'args' is overwritten. | ||||
| // Returns false in case of error (memory allocation failure, non | ||||
| // existing file, too many arguments, ...). | ||||
| int ExUtilInitCommandLineArguments(int argc, const char* argv[], | ||||
|                                    CommandLineArguments* const args); | ||||
|  | ||||
| // Deallocate all memory and reset 'args'. | ||||
| void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| }    // extern "C" | ||||
| #endif | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_EXAMPLE_UTIL_H_ | ||||
							
								
								
									
										604
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gif2webp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										604
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gif2webp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,604 @@ | ||||
| // Copyright 2012 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  simple tool to convert animated GIFs to WebP | ||||
| // | ||||
| // Authors: Skal (pascal.massimino@gmail.com) | ||||
| //          Urvang (urvang@google.com) | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef WEBP_HAVE_GIF | ||||
|  | ||||
| #if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
|  | ||||
| #include <gif_lib.h> | ||||
| #include "webp/encode.h" | ||||
| #include "webp/mux.h" | ||||
| #include "../examples/example_util.h" | ||||
| #include "../imageio/imageio_util.h" | ||||
| #include "./gifdec.h" | ||||
| #include "./unicode.h" | ||||
| #include "./unicode_gif.h" | ||||
|  | ||||
| #if !defined(STDIN_FILENO) | ||||
| #define STDIN_FILENO 0 | ||||
| #endif | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| static int transparent_index = GIF_INDEX_INVALID;  // Opaque by default. | ||||
|  | ||||
| static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { | ||||
|   "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", | ||||
|   "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" | ||||
| }; | ||||
|  | ||||
| static const char* ErrorString(WebPMuxError err) { | ||||
|   assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); | ||||
|   return kErrorMessages[-err]; | ||||
| } | ||||
|  | ||||
| enum { | ||||
|   METADATA_ICC  = (1 << 0), | ||||
|   METADATA_XMP  = (1 << 1), | ||||
|   METADATA_ALL  = METADATA_ICC | METADATA_XMP | ||||
| }; | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf("Usage:\n"); | ||||
|   printf(" gif2webp [options] gif_file -o webp_file\n"); | ||||
|   printf("Options:\n"); | ||||
|   printf("  -h / -help ............. this help\n"); | ||||
|   printf("  -lossy ................. encode image using lossy compression\n"); | ||||
|   printf("  -mixed ................. for each frame in the image, pick lossy\n" | ||||
|          "                           or lossless compression heuristically\n"); | ||||
|   printf("  -q <float> ............. quality factor (0:small..100:big)\n"); | ||||
|   printf("  -m <int> ............... compression method (0=fast, 6=slowest)\n"); | ||||
|   printf("  -min_size .............. minimize output size (default:off)\n" | ||||
|          "                           lossless compression by default; can be\n" | ||||
|          "                           combined with -q, -m, -lossy or -mixed\n" | ||||
|          "                           options\n"); | ||||
|   printf("  -kmin <int> ............ min distance between key frames\n"); | ||||
|   printf("  -kmax <int> ............ max distance between key frames\n"); | ||||
|   printf("  -f <int> ............... filter strength (0=off..100)\n"); | ||||
|   printf("  -metadata <string> ..... comma separated list of metadata to\n"); | ||||
|   printf("                           "); | ||||
|   printf("copy from the input to the output if present\n"); | ||||
|   printf("                           "); | ||||
|   printf("Valid values: all, none, icc, xmp (default)\n"); | ||||
|   printf("  -loop_compatibility .... use compatibility mode for Chrome\n"); | ||||
|   printf("                           version prior to M62 (inclusive)\n"); | ||||
|   printf("  -mt .................... use multi-threading if available\n"); | ||||
|   printf("\n"); | ||||
|   printf("  -version ............... print version number and exit\n"); | ||||
|   printf("  -v ..................... verbose\n"); | ||||
|   printf("  -quiet ................. don't print anything\n"); | ||||
|   printf("\n"); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| int main(int argc, const char *argv[]) { | ||||
|   int verbose = 0; | ||||
|   int gif_error = GIF_ERROR; | ||||
|   WebPMuxError err = WEBP_MUX_OK; | ||||
|   int ok = 0; | ||||
|   const W_CHAR *in_file = NULL, *out_file = NULL; | ||||
|   GifFileType* gif = NULL; | ||||
|   int frame_duration = 0; | ||||
|   int frame_timestamp = 0; | ||||
|   GIFDisposeMethod orig_dispose = GIF_DISPOSE_NONE; | ||||
|  | ||||
|   WebPPicture frame;                // Frame rectangle only (not disposed). | ||||
|   WebPPicture curr_canvas;          // Not disposed. | ||||
|   WebPPicture prev_canvas;          // Disposed. | ||||
|  | ||||
|   WebPAnimEncoder* enc = NULL; | ||||
|   WebPAnimEncoderOptions enc_options; | ||||
|   WebPConfig config; | ||||
|  | ||||
|   int frame_number = 0;     // Whether we are processing the first frame. | ||||
|   int done; | ||||
|   int c; | ||||
|   int quiet = 0; | ||||
|   WebPData webp_data; | ||||
|  | ||||
|   int keep_metadata = METADATA_XMP;  // ICC not output by default. | ||||
|   WebPData icc_data; | ||||
|   int stored_icc = 0;         // Whether we have already stored an ICC profile. | ||||
|   WebPData xmp_data; | ||||
|   int stored_xmp = 0;         // Whether we have already stored an XMP profile. | ||||
|   int loop_count = 0;         // default: infinite | ||||
|   int stored_loop_count = 0;  // Whether we have found an explicit loop count. | ||||
|   int loop_compatibility = 0; | ||||
|   WebPMux* mux = NULL; | ||||
|  | ||||
|   int default_kmin = 1;  // Whether to use default kmin value. | ||||
|   int default_kmax = 1; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) || | ||||
|       !WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) || | ||||
|       !WebPPictureInit(&prev_canvas)) { | ||||
|     fprintf(stderr, "Error! Version mismatch!\n"); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|   config.lossless = 1;  // Use lossless compression by default. | ||||
|  | ||||
|   WebPDataInit(&webp_data); | ||||
|   WebPDataInit(&icc_data); | ||||
|   WebPDataInit(&xmp_data); | ||||
|  | ||||
|   if (argc == 1) { | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(0); | ||||
|   } | ||||
|  | ||||
|   for (c = 1; c < argc; ++c) { | ||||
|     int parse_error = 0; | ||||
|     if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-o") && c < argc - 1) { | ||||
|       out_file = GET_WARGV(argv, ++c); | ||||
|     } else if (!strcmp(argv[c], "-lossy")) { | ||||
|       config.lossless = 0; | ||||
|     } else if (!strcmp(argv[c], "-mixed")) { | ||||
|       enc_options.allow_mixed = 1; | ||||
|       config.lossless = 0; | ||||
|     } else if (!strcmp(argv[c], "-loop_compatibility")) { | ||||
|       loop_compatibility = 1; | ||||
|     } else if (!strcmp(argv[c], "-q") && c < argc - 1) { | ||||
|       config.quality = ExUtilGetFloat(argv[++c], &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-m") && c < argc - 1) { | ||||
|       config.method = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-min_size")) { | ||||
|       enc_options.minimize_size = 1; | ||||
|     } else if (!strcmp(argv[c], "-kmax") && c < argc - 1) { | ||||
|       enc_options.kmax = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       default_kmax = 0; | ||||
|     } else if (!strcmp(argv[c], "-kmin") && c < argc - 1) { | ||||
|       enc_options.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       default_kmin = 0; | ||||
|     } else if (!strcmp(argv[c], "-f") && c < argc - 1) { | ||||
|       config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-metadata") && c < argc - 1) { | ||||
|       static const struct { | ||||
|         const char* option; | ||||
|         int flag; | ||||
|       } kTokens[] = { | ||||
|         { "all",  METADATA_ALL }, | ||||
|         { "none", 0 }, | ||||
|         { "icc",  METADATA_ICC }, | ||||
|         { "xmp",  METADATA_XMP }, | ||||
|       }; | ||||
|       const size_t kNumTokens = sizeof(kTokens) / sizeof(*kTokens); | ||||
|       const char* start = argv[++c]; | ||||
|       const char* const end = start + strlen(start); | ||||
|  | ||||
|       keep_metadata = 0; | ||||
|       while (start < end) { | ||||
|         size_t i; | ||||
|         const char* token = strchr(start, ','); | ||||
|         if (token == NULL) token = end; | ||||
|  | ||||
|         for (i = 0; i < kNumTokens; ++i) { | ||||
|           if ((size_t)(token - start) == strlen(kTokens[i].option) && | ||||
|               !strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) { | ||||
|             if (kTokens[i].flag != 0) { | ||||
|               keep_metadata |= kTokens[i].flag; | ||||
|             } else { | ||||
|               keep_metadata = 0; | ||||
|             } | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|         if (i == kNumTokens) { | ||||
|           fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", | ||||
|                   (int)(token - start), start); | ||||
|           Help(); | ||||
|           FREE_WARGV_AND_RETURN(-1); | ||||
|         } | ||||
|         start = token + 1; | ||||
|       } | ||||
|     } else if (!strcmp(argv[c], "-mt")) { | ||||
|       ++config.thread_level; | ||||
|     } else if (!strcmp(argv[c], "-version")) { | ||||
|       const int enc_version = WebPGetEncoderVersion(); | ||||
|       const int mux_version = WebPGetMuxVersion(); | ||||
|       printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n", | ||||
|              (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, | ||||
|              enc_version & 0xff, (mux_version >> 16) & 0xff, | ||||
|              (mux_version >> 8) & 0xff, mux_version & 0xff); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-quiet")) { | ||||
|       quiet = 1; | ||||
|       enc_options.verbose = 0; | ||||
|     } else if (!strcmp(argv[c], "-v")) { | ||||
|       verbose = 1; | ||||
|       enc_options.verbose = 1; | ||||
|     } else if (!strcmp(argv[c], "--")) { | ||||
|       if (c < argc - 1) in_file = GET_WARGV(argv, ++c); | ||||
|       break; | ||||
|     } else if (argv[c][0] == '-') { | ||||
|       fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } else { | ||||
|       in_file = GET_WARGV(argv, c); | ||||
|     } | ||||
|  | ||||
|     if (parse_error) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Appropriate default kmin, kmax values for lossy and lossless. | ||||
|   if (default_kmin) { | ||||
|     enc_options.kmin = config.lossless ? 9 : 3; | ||||
|   } | ||||
|   if (default_kmax) { | ||||
|     enc_options.kmax = config.lossless ? 17 : 5; | ||||
|   } | ||||
|  | ||||
|   if (!WebPValidateConfig(&config)) { | ||||
|     fprintf(stderr, "Error! Invalid configuration.\n"); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   if (in_file == NULL) { | ||||
|     fprintf(stderr, "No input file specified!\n"); | ||||
|     Help(); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   // Start the decoder object | ||||
|   gif = DGifOpenFileUnicode(in_file, &gif_error); | ||||
|   if (gif == NULL) goto End; | ||||
|  | ||||
|   // Loop over GIF images | ||||
|   done = 0; | ||||
|   do { | ||||
|     GifRecordType type; | ||||
|     if (DGifGetRecordType(gif, &type) == GIF_ERROR) goto End; | ||||
|  | ||||
|     switch (type) { | ||||
|       case IMAGE_DESC_RECORD_TYPE: { | ||||
|         GIFFrameRect gif_rect; | ||||
|         GifImageDesc* const image_desc = &gif->Image; | ||||
|  | ||||
|         if (!DGifGetImageDesc(gif)) goto End; | ||||
|  | ||||
|         if (frame_number == 0) { | ||||
|           if (verbose) { | ||||
|             printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight); | ||||
|           } | ||||
|           // Fix some broken GIF global headers that report | ||||
|           // 0 x 0 screen dimension. | ||||
|           if (gif->SWidth == 0 || gif->SHeight == 0) { | ||||
|             image_desc->Left = 0; | ||||
|             image_desc->Top = 0; | ||||
|             gif->SWidth = image_desc->Width; | ||||
|             gif->SHeight = image_desc->Height; | ||||
|             if (gif->SWidth <= 0 || gif->SHeight <= 0) { | ||||
|               goto End; | ||||
|             } | ||||
|             if (verbose) { | ||||
|               printf("Fixed canvas screen dimension to: %d x %d\n", | ||||
|                      gif->SWidth, gif->SHeight); | ||||
|             } | ||||
|           } | ||||
|           // Allocate current buffer. | ||||
|           frame.width = gif->SWidth; | ||||
|           frame.height = gif->SHeight; | ||||
|           frame.use_argb = 1; | ||||
|           if (!WebPPictureAlloc(&frame)) goto End; | ||||
|           GIFClearPic(&frame, NULL); | ||||
|           WebPPictureCopy(&frame, &curr_canvas); | ||||
|           WebPPictureCopy(&frame, &prev_canvas); | ||||
|  | ||||
|           // Background color. | ||||
|           GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor, | ||||
|                                 transparent_index, | ||||
|                                 &enc_options.anim_params.bgcolor); | ||||
|  | ||||
|           // Initialize encoder. | ||||
|           enc = WebPAnimEncoderNew(curr_canvas.width, curr_canvas.height, | ||||
|                                    &enc_options); | ||||
|           if (enc == NULL) { | ||||
|             fprintf(stderr, | ||||
|                     "Error! Could not create encoder object. Possibly due to " | ||||
|                     "a memory error.\n"); | ||||
|             goto End; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         // Some even more broken GIF can have sub-rect with zero width/height. | ||||
|         if (image_desc->Width == 0 || image_desc->Height == 0) { | ||||
|           image_desc->Width = gif->SWidth; | ||||
|           image_desc->Height = gif->SHeight; | ||||
|         } | ||||
|  | ||||
|         if (!GIFReadFrame(gif, transparent_index, &gif_rect, &frame)) { | ||||
|           goto End; | ||||
|         } | ||||
|         // Blend frame rectangle with previous canvas to compose full canvas. | ||||
|         // Note that 'curr_canvas' is same as 'prev_canvas' at this point. | ||||
|         GIFBlendFrames(&frame, &gif_rect, &curr_canvas); | ||||
|  | ||||
|         if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) { | ||||
|           fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number, | ||||
|                   WebPAnimEncoderGetError(enc)); | ||||
|           goto End; | ||||
|         } else { | ||||
|           ++frame_number; | ||||
|         } | ||||
|  | ||||
|         // Update canvases. | ||||
|         GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas); | ||||
|         GIFCopyPixels(&curr_canvas, &prev_canvas); | ||||
|  | ||||
|         // Force frames with a small or no duration to 100ms to be consistent | ||||
|         // with web browsers and other transcoding tools. This also avoids | ||||
|         // incorrect durations between frames when padding frames are | ||||
|         // discarded. | ||||
|         if (frame_duration <= 10) { | ||||
|           frame_duration = 100; | ||||
|         } | ||||
|  | ||||
|         // Update timestamp (for next frame). | ||||
|         frame_timestamp += frame_duration; | ||||
|  | ||||
|         // In GIF, graphic control extensions are optional for a frame, so we | ||||
|         // may not get one before reading the next frame. To handle this case, | ||||
|         // we reset frame properties to reasonable defaults for the next frame. | ||||
|         orig_dispose = GIF_DISPOSE_NONE; | ||||
|         frame_duration = 0; | ||||
|         transparent_index = GIF_INDEX_INVALID; | ||||
|         break; | ||||
|       } | ||||
|       case EXTENSION_RECORD_TYPE: { | ||||
|         int extension; | ||||
|         GifByteType *data = NULL; | ||||
|         if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) { | ||||
|           goto End; | ||||
|         } | ||||
|         if (data == NULL) continue; | ||||
|  | ||||
|         switch (extension) { | ||||
|           case COMMENT_EXT_FUNC_CODE: { | ||||
|             break;  // Do nothing for now. | ||||
|           } | ||||
|           case GRAPHICS_EXT_FUNC_CODE: { | ||||
|             if (!GIFReadGraphicsExtension(data, &frame_duration, &orig_dispose, | ||||
|                                           &transparent_index)) { | ||||
|               goto End; | ||||
|             } | ||||
|             break; | ||||
|           } | ||||
|           case PLAINTEXT_EXT_FUNC_CODE: { | ||||
|             break; | ||||
|           } | ||||
|           case APPLICATION_EXT_FUNC_CODE: { | ||||
|             if (data[0] != 11) break;    // Chunk is too short | ||||
|             if (!memcmp(data + 1, "NETSCAPE2.0", 11) || | ||||
|                 !memcmp(data + 1, "ANIMEXTS1.0", 11)) { | ||||
|               if (!GIFReadLoopCount(gif, &data, &loop_count)) { | ||||
|                 goto End; | ||||
|               } | ||||
|               if (verbose) { | ||||
|                 fprintf(stderr, "Loop count: %d\n", loop_count); | ||||
|               } | ||||
|               stored_loop_count = loop_compatibility ? (loop_count != 0) : 1; | ||||
|             } else {  // An extension containing metadata. | ||||
|               // We only store the first encountered chunk of each type, and | ||||
|               // only if requested by the user. | ||||
|               const int is_xmp = (keep_metadata & METADATA_XMP) && | ||||
|                                  !stored_xmp && | ||||
|                                  !memcmp(data + 1, "XMP DataXMP", 11); | ||||
|               const int is_icc = (keep_metadata & METADATA_ICC) && | ||||
|                                  !stored_icc && | ||||
|                                  !memcmp(data + 1, "ICCRGBG1012", 11); | ||||
|               if (is_xmp || is_icc) { | ||||
|                 if (!GIFReadMetadata(gif, &data, | ||||
|                                      is_xmp ? &xmp_data : &icc_data)) { | ||||
|                   goto End; | ||||
|                 } | ||||
|                 if (is_icc) { | ||||
|                   stored_icc = 1; | ||||
|                 } else if (is_xmp) { | ||||
|                   stored_xmp = 1; | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|             break; | ||||
|           } | ||||
|           default: { | ||||
|             break;  // skip | ||||
|           } | ||||
|         } | ||||
|         while (data != NULL) { | ||||
|           if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) goto End; | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|       case TERMINATE_RECORD_TYPE: { | ||||
|         done = 1; | ||||
|         break; | ||||
|       } | ||||
|       default: { | ||||
|         if (verbose) { | ||||
|           fprintf(stderr, "Skipping over unknown record type %d\n", type); | ||||
|         } | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } while (!done); | ||||
|  | ||||
|   // Last NULL frame. | ||||
|   if (!WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL)) { | ||||
|     fprintf(stderr, "Error flushing WebP muxer.\n"); | ||||
|     fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); | ||||
|   } | ||||
|  | ||||
|   if (!WebPAnimEncoderAssemble(enc, &webp_data)) { | ||||
|     fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   if (!loop_compatibility) { | ||||
|     if (!stored_loop_count) { | ||||
|       // if no loop-count element is seen, the default is '1' (loop-once) | ||||
|       // and we need to signal it explicitly in WebP. Note however that | ||||
|       // in case there's a single frame, we still don't need to store it. | ||||
|       if (frame_number > 1) { | ||||
|         stored_loop_count = 1; | ||||
|         loop_count = 1; | ||||
|       } | ||||
|     } else if (loop_count > 0 && loop_count < 65535) { | ||||
|       // adapt GIF's semantic to WebP's (except in the infinite-loop case) | ||||
|       loop_count += 1; | ||||
|     } | ||||
|   } | ||||
|   // loop_count of 0 is the default (infinite), so no need to signal it | ||||
|   if (loop_count == 0) stored_loop_count = 0; | ||||
|  | ||||
|   if (stored_loop_count || stored_icc || stored_xmp) { | ||||
|     // Re-mux to add loop count and/or metadata as needed. | ||||
|     mux = WebPMuxCreate(&webp_data, 1); | ||||
|     if (mux == NULL) { | ||||
|       fprintf(stderr, "ERROR: Could not re-mux to add loop count/metadata.\n"); | ||||
|       goto End; | ||||
|     } | ||||
|     WebPDataClear(&webp_data); | ||||
|  | ||||
|     if (stored_loop_count) {  // Update loop count. | ||||
|       WebPMuxAnimParams new_params; | ||||
|       err = WebPMuxGetAnimationParams(mux, &new_params); | ||||
|       if (err != WEBP_MUX_OK) { | ||||
|         fprintf(stderr, "ERROR (%s): Could not fetch loop count.\n", | ||||
|                 ErrorString(err)); | ||||
|         goto End; | ||||
|       } | ||||
|       new_params.loop_count = loop_count; | ||||
|       err = WebPMuxSetAnimationParams(mux, &new_params); | ||||
|       if (err != WEBP_MUX_OK) { | ||||
|         fprintf(stderr, "ERROR (%s): Could not update loop count.\n", | ||||
|                 ErrorString(err)); | ||||
|         goto End; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (stored_icc) {   // Add ICCP chunk. | ||||
|       err = WebPMuxSetChunk(mux, "ICCP", &icc_data, 1); | ||||
|       if (verbose) { | ||||
|         fprintf(stderr, "ICC size: %d\n", (int)icc_data.size); | ||||
|       } | ||||
|       if (err != WEBP_MUX_OK) { | ||||
|         fprintf(stderr, "ERROR (%s): Could not set ICC chunk.\n", | ||||
|                 ErrorString(err)); | ||||
|         goto End; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (stored_xmp) {   // Add XMP chunk. | ||||
|       err = WebPMuxSetChunk(mux, "XMP ", &xmp_data, 1); | ||||
|       if (verbose) { | ||||
|         fprintf(stderr, "XMP size: %d\n", (int)xmp_data.size); | ||||
|       } | ||||
|       if (err != WEBP_MUX_OK) { | ||||
|         fprintf(stderr, "ERROR (%s): Could not set XMP chunk.\n", | ||||
|                 ErrorString(err)); | ||||
|         goto End; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     err = WebPMuxAssemble(mux, &webp_data); | ||||
|     if (err != WEBP_MUX_OK) { | ||||
|       fprintf(stderr, "ERROR (%s): Could not assemble when re-muxing to add " | ||||
|               "loop count/metadata.\n", ErrorString(err)); | ||||
|       goto End; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (out_file != NULL) { | ||||
|     if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes, | ||||
|                             webp_data.size)) { | ||||
|       WFPRINTF(stderr, "Error writing output file: %s\n", out_file); | ||||
|       goto End; | ||||
|     } | ||||
|     if (!quiet) { | ||||
|       if (!WSTRCMP(out_file, "-")) { | ||||
|         fprintf(stderr, "Saved %d bytes to STDIO\n", | ||||
|                 (int)webp_data.size); | ||||
|       } else { | ||||
|         WFPRINTF(stderr, "Saved output file (%d bytes): %s\n", | ||||
|                  (int)webp_data.size, out_file); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     if (!quiet) { | ||||
|       fprintf(stderr, "Nothing written; use -o flag to save the result " | ||||
|                       "(%d bytes).\n", (int)webp_data.size); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // All OK. | ||||
|   ok = 1; | ||||
|   gif_error = GIF_OK; | ||||
|  | ||||
|  End: | ||||
|   WebPDataClear(&icc_data); | ||||
|   WebPDataClear(&xmp_data); | ||||
|   WebPMuxDelete(mux); | ||||
|   WebPDataClear(&webp_data); | ||||
|   WebPPictureFree(&frame); | ||||
|   WebPPictureFree(&curr_canvas); | ||||
|   WebPPictureFree(&prev_canvas); | ||||
|   WebPAnimEncoderDelete(enc); | ||||
|  | ||||
|   if (gif_error != GIF_OK) { | ||||
|     GIFDisplayError(gif, gif_error); | ||||
|   } | ||||
|   if (gif != NULL) { | ||||
| #if LOCAL_GIF_PREREQ(5,1) | ||||
|     DGifCloseFile(gif, &gif_error); | ||||
| #else | ||||
|     DGifCloseFile(gif); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   FREE_WARGV_AND_RETURN(!ok); | ||||
| } | ||||
|  | ||||
| #else  // !WEBP_HAVE_GIF | ||||
|  | ||||
| int main(int argc, const char *argv[]) { | ||||
|   fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]); | ||||
|   (void)argc; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
							
								
								
									
										416
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gifdec.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gifdec.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,416 @@ | ||||
| // Copyright 2012 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // GIF decode. | ||||
|  | ||||
| #include "./gifdec.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #ifdef WEBP_HAVE_GIF | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "webp/encode.h" | ||||
| #include "webp/mux_types.h" | ||||
|  | ||||
| #define GIF_TRANSPARENT_COLOR 0x00000000u | ||||
| #define GIF_WHITE_COLOR       0xffffffffu | ||||
| #define GIF_TRANSPARENT_MASK  0x01 | ||||
| #define GIF_DISPOSE_MASK      0x07 | ||||
| #define GIF_DISPOSE_SHIFT     2 | ||||
|  | ||||
| // from utils/utils.h | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| extern void WebPCopyPlane(const uint8_t* src, int src_stride, | ||||
|                           uint8_t* dst, int dst_stride, | ||||
|                           int width, int height); | ||||
| extern void WebPCopyPixels(const WebPPicture* const src, | ||||
|                            WebPPicture* const dst); | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void GIFGetBackgroundColor(const ColorMapObject* const color_map, | ||||
|                            int bgcolor_index, int transparent_index, | ||||
|                            uint32_t* const bgcolor) { | ||||
|   if (transparent_index != GIF_INDEX_INVALID && | ||||
|       bgcolor_index == transparent_index) { | ||||
|     *bgcolor = GIF_TRANSPARENT_COLOR;  // Special case. | ||||
|   } else if (color_map == NULL || color_map->Colors == NULL | ||||
|              || bgcolor_index >= color_map->ColorCount) { | ||||
|     *bgcolor = GIF_WHITE_COLOR; | ||||
|     fprintf(stderr, | ||||
|             "GIF decode warning: invalid background color index. Assuming " | ||||
|             "white background.\n"); | ||||
|   } else { | ||||
|     const GifColorType color = color_map->Colors[bgcolor_index]; | ||||
|     *bgcolor = (0xffu       << 24) | ||||
|              | (color.Red   << 16) | ||||
|              | (color.Green <<  8) | ||||
|              | (color.Blue  <<  0); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration, | ||||
|                              GIFDisposeMethod* const dispose, | ||||
|                              int* const transparent_index) { | ||||
|   const int flags = buf[1]; | ||||
|   const int dispose_raw = (flags >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK; | ||||
|   const int duration_raw = buf[2] | (buf[3] << 8);  // In 10 ms units. | ||||
|   if (buf[0] != 4) return 0; | ||||
|   *duration = duration_raw * 10;  // Duration is in 1 ms units. | ||||
|   switch (dispose_raw) { | ||||
|     case 3: | ||||
|       *dispose = GIF_DISPOSE_RESTORE_PREVIOUS; | ||||
|       break; | ||||
|     case 2: | ||||
|       *dispose = GIF_DISPOSE_BACKGROUND; | ||||
|       break; | ||||
|     case 1: | ||||
|     case 0: | ||||
|     default: | ||||
|       *dispose = GIF_DISPOSE_NONE; | ||||
|       break; | ||||
|   } | ||||
|   *transparent_index = | ||||
|       (flags & GIF_TRANSPARENT_MASK) ? buf[4] : GIF_INDEX_INVALID; | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int Remap(const GifFileType* const gif, const uint8_t* const src, | ||||
|                  int len, int transparent_index, uint32_t* dst) { | ||||
|   int i; | ||||
|   const GifColorType* colors; | ||||
|   const ColorMapObject* const cmap = | ||||
|       gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap; | ||||
|   if (cmap == NULL) return 1; | ||||
|   if (cmap->Colors == NULL || cmap->ColorCount <= 0) return 0; | ||||
|   colors = cmap->Colors; | ||||
|  | ||||
|   for (i = 0; i < len; ++i) { | ||||
|     if (src[i] == transparent_index) { | ||||
|       dst[i] = GIF_TRANSPARENT_COLOR; | ||||
|     } else if (src[i] < cmap->ColorCount) { | ||||
|       const GifColorType c = colors[src[i]]; | ||||
|       dst[i] = c.Blue | (c.Green << 8) | (c.Red << 16) | (0xffu << 24); | ||||
|     } else { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int GIFReadFrame(GifFileType* const gif, int transparent_index, | ||||
|                  GIFFrameRect* const gif_rect, WebPPicture* const picture) { | ||||
|   WebPPicture sub_image; | ||||
|   const GifImageDesc* const image_desc = &gif->Image; | ||||
|   uint32_t* dst = NULL; | ||||
|   uint8_t* tmp = NULL; | ||||
|   const GIFFrameRect rect = { | ||||
|       image_desc->Left, image_desc->Top, image_desc->Width, image_desc->Height | ||||
|   }; | ||||
|   const uint64_t memory_needed = 4 * rect.width * (uint64_t)rect.height; | ||||
|   int ok = 0; | ||||
|   *gif_rect = rect; | ||||
|  | ||||
|   if (memory_needed != (size_t)memory_needed || memory_needed > (4ULL << 32)) { | ||||
|     fprintf(stderr, "Image is too large (%d x %d).", rect.width, rect.height); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   // Use a view for the sub-picture: | ||||
|   if (!WebPPictureView(picture, rect.x_offset, rect.y_offset, | ||||
|                        rect.width, rect.height, &sub_image)) { | ||||
|     fprintf(stderr, "Sub-image %dx%d at position %d,%d is invalid!\n", | ||||
|             rect.width, rect.height, rect.x_offset, rect.y_offset); | ||||
|     return 0; | ||||
|   } | ||||
|   dst = sub_image.argb; | ||||
|  | ||||
|   tmp = (uint8_t*)malloc(rect.width * sizeof(*tmp)); | ||||
|   if (tmp == NULL) goto End; | ||||
|  | ||||
|   if (image_desc->Interlace) {  // Interlaced image. | ||||
|     // We need 4 passes, with the following offsets and jumps. | ||||
|     const int interlace_offsets[] = { 0, 4, 2, 1 }; | ||||
|     const int interlace_jumps[]   = { 8, 8, 4, 2 }; | ||||
|     int pass; | ||||
|     for (pass = 0; pass < 4; ++pass) { | ||||
|       const size_t stride = (size_t)sub_image.argb_stride; | ||||
|       int y = interlace_offsets[pass]; | ||||
|       uint32_t* row = dst + y * stride; | ||||
|       const size_t jump = interlace_jumps[pass] * stride; | ||||
|       for (; y < rect.height; y += interlace_jumps[pass], row += jump) { | ||||
|         if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End; | ||||
|         if (!Remap(gif, tmp, rect.width, transparent_index, row)) goto End; | ||||
|       } | ||||
|     } | ||||
|   } else {  // Non-interlaced image. | ||||
|     int y; | ||||
|     uint32_t* ptr = dst; | ||||
|     for (y = 0; y < rect.height; ++y, ptr += sub_image.argb_stride) { | ||||
|       if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End; | ||||
|       if (!Remap(gif, tmp, rect.width, transparent_index, ptr)) goto End; | ||||
|     } | ||||
|   } | ||||
|   ok = 1; | ||||
|  | ||||
|  End: | ||||
|   if (!ok) picture->error_code = sub_image.error_code; | ||||
|   WebPPictureFree(&sub_image); | ||||
|   free(tmp); | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| int GIFReadLoopCount(GifFileType* const gif, GifByteType** const buf, | ||||
|                      int* const loop_count) { | ||||
|   assert(!memcmp(*buf + 1, "NETSCAPE2.0", 11) || | ||||
|          !memcmp(*buf + 1, "ANIMEXTS1.0", 11)); | ||||
|   if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) { | ||||
|     return 0; | ||||
|   } | ||||
|   if (*buf == NULL) { | ||||
|     return 0;  // Loop count sub-block missing. | ||||
|   } | ||||
|   if ((*buf)[0] < 3 || (*buf)[1] != 1) { | ||||
|     return 0;   // wrong size/marker | ||||
|   } | ||||
|   *loop_count = (*buf)[2] | ((*buf)[3] << 8); | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int GIFReadMetadata(GifFileType* const gif, GifByteType** const buf, | ||||
|                     WebPData* const metadata) { | ||||
|   const int is_xmp = !memcmp(*buf + 1, "XMP DataXMP", 11); | ||||
|   const int is_icc = !memcmp(*buf + 1, "ICCRGBG1012", 11); | ||||
|   assert(is_xmp || is_icc); | ||||
|   (void)is_icc;  // silence unused warning. | ||||
|   // Construct metadata from sub-blocks. | ||||
|   // Usual case (including ICC profile): In each sub-block, the | ||||
|   // first byte specifies its size in bytes (0 to 255) and the | ||||
|   // rest of the bytes contain the data. | ||||
|   // Special case for XMP data: In each sub-block, the first byte | ||||
|   // is also part of the XMP payload. XMP in GIF also has a 257 | ||||
|   // byte padding data. See the XMP specification for details. | ||||
|   while (1) { | ||||
|     WebPData subblock; | ||||
|     const uint8_t* tmp; | ||||
|     if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (*buf == NULL) break;  // Finished. | ||||
|     subblock.size = is_xmp ? (*buf)[0] + 1 : (*buf)[0]; | ||||
|     assert(subblock.size > 0); | ||||
|     subblock.bytes = is_xmp ? *buf : *buf + 1; | ||||
|     // Note: We store returned value in 'tmp' first, to avoid | ||||
|     // leaking old memory in metadata->bytes on error. | ||||
|     tmp = (uint8_t*)realloc((void*)metadata->bytes, | ||||
|                             metadata->size + subblock.size); | ||||
|     if (tmp == NULL) { | ||||
|       return 0; | ||||
|     } | ||||
|     memcpy((void*)(tmp + metadata->size), | ||||
|            subblock.bytes, subblock.size); | ||||
|     metadata->bytes = tmp; | ||||
|     metadata->size += subblock.size; | ||||
|   } | ||||
|   if (is_xmp) { | ||||
|     // XMP padding data is 0x01, 0xff, 0xfe ... 0x01, 0x00. | ||||
|     const size_t xmp_pading_size = 257; | ||||
|     if (metadata->size > xmp_pading_size) { | ||||
|       metadata->size -= xmp_pading_size; | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static void ClearRectangle(WebPPicture* const picture, | ||||
|                            int left, int top, int width, int height) { | ||||
|   int i, j; | ||||
|   const size_t stride = picture->argb_stride; | ||||
|   uint32_t* dst = picture->argb + top * stride + left; | ||||
|   for (j = 0; j < height; ++j, dst += stride) { | ||||
|     for (i = 0; i < width; ++i) dst[i] = GIF_TRANSPARENT_COLOR; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GIFClearPic(WebPPicture* const pic, const GIFFrameRect* const rect) { | ||||
|   if (rect != NULL) { | ||||
|     ClearRectangle(pic, rect->x_offset, rect->y_offset, | ||||
|                    rect->width, rect->height); | ||||
|   } else { | ||||
|     ClearRectangle(pic, 0, 0, pic->width, pic->height); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GIFCopyPixels(const WebPPicture* const src, WebPPicture* const dst) { | ||||
|   WebPCopyPixels(src, dst); | ||||
| } | ||||
|  | ||||
| void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, | ||||
|                      const WebPPicture* const prev_canvas, | ||||
|                      WebPPicture* const curr_canvas) { | ||||
|   assert(rect != NULL); | ||||
|   if (dispose == GIF_DISPOSE_BACKGROUND) { | ||||
|     GIFClearPic(curr_canvas, rect); | ||||
|   } else if (dispose == GIF_DISPOSE_RESTORE_PREVIOUS) { | ||||
|     const size_t src_stride = prev_canvas->argb_stride; | ||||
|     const uint32_t* const src = prev_canvas->argb + rect->x_offset | ||||
|                               + rect->y_offset * src_stride; | ||||
|     const size_t dst_stride = curr_canvas->argb_stride; | ||||
|     uint32_t* const dst = curr_canvas->argb + rect->x_offset | ||||
|                         + rect->y_offset * dst_stride; | ||||
|     assert(prev_canvas != NULL); | ||||
|     WebPCopyPlane((uint8_t*)src, (int)(4 * src_stride), | ||||
|                   (uint8_t*)dst, (int)(4 * dst_stride), | ||||
|                   4 * rect->width, rect->height); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GIFBlendFrames(const WebPPicture* const src, | ||||
|                     const GIFFrameRect* const rect, WebPPicture* const dst) { | ||||
|   int i, j; | ||||
|   const size_t src_stride = src->argb_stride; | ||||
|   const size_t dst_stride = dst->argb_stride; | ||||
|   assert(src->width == dst->width && src->height == dst->height); | ||||
|   for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) { | ||||
|     for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) { | ||||
|       const uint32_t src_pixel = src->argb[j * src_stride + i]; | ||||
|       const int src_alpha = src_pixel >> 24; | ||||
|       if (src_alpha != 0) { | ||||
|         dst->argb[j * dst_stride + i] = src_pixel; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GIFDisplayError(const GifFileType* const gif, int gif_error) { | ||||
|   // libgif 4.2.0 has retired PrintGifError() and added GifErrorString(). | ||||
| #if LOCAL_GIF_PREREQ(4,2) | ||||
| #if LOCAL_GIF_PREREQ(5,0) | ||||
|   // Static string actually, hence the const char* cast. | ||||
|   const char* error_str = (const char*)GifErrorString( | ||||
|       (gif == NULL) ? gif_error : gif->Error); | ||||
| #else | ||||
|   const char* error_str = (const char*)GifErrorString(); | ||||
|   (void)gif; | ||||
| #endif | ||||
|   if (error_str == NULL) error_str = "Unknown error"; | ||||
|   fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str); | ||||
| #else | ||||
|   (void)gif; | ||||
|   fprintf(stderr, "GIFLib Error %d: ", gif_error); | ||||
|   PrintGifError(); | ||||
|   fprintf(stderr, "\n"); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #else  // !WEBP_HAVE_GIF | ||||
|  | ||||
| static void ErrorGIFNotAvailable() { | ||||
|   fprintf(stderr, "GIF support not compiled. Please install the libgif-dev " | ||||
|           "package before building.\n"); | ||||
| } | ||||
|  | ||||
| void GIFGetBackgroundColor(const struct ColorMapObject* const color_map, | ||||
|                            int bgcolor_index, int transparent_index, | ||||
|                            uint32_t* const bgcolor) { | ||||
|   (void)color_map; | ||||
|   (void)bgcolor_index; | ||||
|   (void)transparent_index; | ||||
|   (void)bgcolor; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| int GIFReadGraphicsExtension(const GifByteType* const data, int* const duration, | ||||
|                              GIFDisposeMethod* const dispose, | ||||
|                              int* const transparent_index) { | ||||
|   (void)data; | ||||
|   (void)duration; | ||||
|   (void)dispose; | ||||
|   (void)transparent_index; | ||||
|   ErrorGIFNotAvailable(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int GIFReadFrame(struct GifFileType* const gif, int transparent_index, | ||||
|                  GIFFrameRect* const gif_rect, | ||||
|                  struct WebPPicture* const picture) { | ||||
|   (void)gif; | ||||
|   (void)transparent_index; | ||||
|   (void)gif_rect; | ||||
|   (void)picture; | ||||
|   ErrorGIFNotAvailable(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf, | ||||
|                      int* const loop_count) { | ||||
|   (void)gif; | ||||
|   (void)buf; | ||||
|   (void)loop_count; | ||||
|   ErrorGIFNotAvailable(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf, | ||||
|                     struct WebPData* const metadata) { | ||||
|   (void)gif; | ||||
|   (void)buf; | ||||
|   (void)metadata; | ||||
|   ErrorGIFNotAvailable(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, | ||||
|                      const struct WebPPicture* const prev_canvas, | ||||
|                      struct WebPPicture* const curr_canvas) { | ||||
|   (void)dispose; | ||||
|   (void)rect; | ||||
|   (void)prev_canvas; | ||||
|   (void)curr_canvas; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| void GIFBlendFrames(const struct WebPPicture* const src, | ||||
|                     const GIFFrameRect* const rect, | ||||
|                     struct WebPPicture* const dst) { | ||||
|   (void)src; | ||||
|   (void)rect; | ||||
|   (void)dst; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| void GIFDisplayError(const struct GifFileType* const gif, int gif_error) { | ||||
|   (void)gif; | ||||
|   (void)gif_error; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| void GIFClearPic(struct WebPPicture* const pic, | ||||
|                  const GIFFrameRect* const rect) { | ||||
|   (void)pic; | ||||
|   (void)rect; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| void GIFCopyPixels(const struct WebPPicture* const src, | ||||
|                    struct WebPPicture* const dst) { | ||||
|   (void)src; | ||||
|   (void)dst; | ||||
|   ErrorGIFNotAvailable(); | ||||
| } | ||||
|  | ||||
| #endif  // WEBP_HAVE_GIF | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
							
								
								
									
										116
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gifdec.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/gifdec.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | ||||
| // Copyright 2014 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // GIF decode. | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_GIFDEC_H_ | ||||
| #define WEBP_EXAMPLES_GIFDEC_H_ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include "webp/types.h" | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef WEBP_HAVE_GIF | ||||
| #include <gif_lib.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| // GIFLIB_MAJOR is only defined in libgif >= 4.2.0. | ||||
| #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) | ||||
| # define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR) | ||||
| # define LOCAL_GIF_PREREQ(maj, min) \ | ||||
|     (LOCAL_GIF_VERSION >= (((maj) << 8) | (min))) | ||||
| #else | ||||
| # define LOCAL_GIF_VERSION 0 | ||||
| # define LOCAL_GIF_PREREQ(maj, min) 0 | ||||
| #endif | ||||
|  | ||||
| #define GIF_INDEX_INVALID (-1) | ||||
|  | ||||
| typedef enum GIFDisposeMethod { | ||||
|   GIF_DISPOSE_NONE, | ||||
|   GIF_DISPOSE_BACKGROUND, | ||||
|   GIF_DISPOSE_RESTORE_PREVIOUS | ||||
| } GIFDisposeMethod; | ||||
|  | ||||
| typedef struct { | ||||
|   int x_offset, y_offset, width, height; | ||||
| } GIFFrameRect; | ||||
|  | ||||
| struct WebPData; | ||||
| struct WebPPicture; | ||||
|  | ||||
| #ifndef WEBP_HAVE_GIF | ||||
| struct ColorMapObject; | ||||
| struct GifFileType; | ||||
| typedef unsigned char GifByteType; | ||||
| #endif | ||||
|  | ||||
| // Given the index of background color and transparent color, returns the | ||||
| // corresponding background color (in BGRA format) in 'bgcolor'. | ||||
| void GIFGetBackgroundColor(const struct ColorMapObject* const color_map, | ||||
|                            int bgcolor_index, int transparent_index, | ||||
|                            uint32_t* const bgcolor); | ||||
|  | ||||
| // Parses the given graphics extension data to get frame duration (in 1ms | ||||
| // units), dispose method and transparent color index. | ||||
| // Returns true on success. | ||||
| int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration, | ||||
|                              GIFDisposeMethod* const dispose, | ||||
|                              int* const transparent_index); | ||||
|  | ||||
| // Reads the next GIF frame from 'gif' into 'picture'. Also, returns the GIF | ||||
| // frame dimensions and offsets in 'rect'. | ||||
| // Returns true on success. | ||||
| int GIFReadFrame(struct GifFileType* const gif, int transparent_index, | ||||
|                  GIFFrameRect* const gif_rect, | ||||
|                  struct WebPPicture* const picture); | ||||
|  | ||||
| // Parses loop count from the given Netscape extension data. | ||||
| int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf, | ||||
|                      int* const loop_count); | ||||
|  | ||||
| // Parses the given ICC or XMP extension data and stores it into 'metadata'. | ||||
| // Returns true on success. | ||||
| int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf, | ||||
|                     struct WebPData* const metadata); | ||||
|  | ||||
| // Dispose the pixels within 'rect' of 'curr_canvas' based on 'dispose' method | ||||
| // and 'prev_canvas'. | ||||
| void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, | ||||
|                      const struct WebPPicture* const prev_canvas, | ||||
|                      struct WebPPicture* const curr_canvas); | ||||
|  | ||||
| // Given 'src' picture and its frame rectangle 'rect', blend it into 'dst'. | ||||
| void GIFBlendFrames(const struct WebPPicture* const src, | ||||
|                     const GIFFrameRect* const rect, | ||||
|                     struct WebPPicture* const dst); | ||||
|  | ||||
| // Prints an error string based on 'gif_error'. | ||||
| void GIFDisplayError(const struct GifFileType* const gif, int gif_error); | ||||
|  | ||||
| // In the given 'pic', clear the pixels in 'rect' to transparent color. | ||||
| void GIFClearPic(struct WebPPicture* const pic, const GIFFrameRect* const rect); | ||||
|  | ||||
| // Copy pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are assumed | ||||
| // to be already allocated. | ||||
| void GIFCopyPixels(const struct WebPPicture* const src, | ||||
|                    struct WebPPicture* const dst); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| }    // extern "C" | ||||
| #endif | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_GIFDEC_H_ | ||||
							
								
								
									
										324
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/img2webp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/img2webp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,324 @@ | ||||
| // Copyright 2016 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  generate an animated WebP out of a sequence of images | ||||
| //  (PNG, JPEG, ...) | ||||
| // | ||||
| //  Example usage: | ||||
| //     img2webp -o out.webp -q 40 -mixed -duration 40 input??.png | ||||
| // | ||||
| // Author: skal@google.com (Pascal Massimino) | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #include "../examples/example_util.h" | ||||
| #include "../imageio/image_dec.h" | ||||
| #include "../imageio/imageio_util.h" | ||||
| #include "./stopwatch.h" | ||||
| #include "./unicode.h" | ||||
| #include "webp/encode.h" | ||||
| #include "webp/mux.h" | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf("Usage:\n\n"); | ||||
|   printf("  img2webp [file-level options] [image files...] " | ||||
|          "[per-frame options...]\n"); | ||||
|   printf("\n"); | ||||
|  | ||||
|   printf("File-level options (only used at the start of compression):\n"); | ||||
|   printf(" -min_size ............ minimize size\n"); | ||||
|   printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n"); | ||||
|   printf(" -kmax <int> .......... maximum number of frame between key-frames\n" | ||||
|          "                        (0=only keyframes)\n"); | ||||
|   printf(" -kmin <int> .......... minimum number of frame between key-frames\n" | ||||
|          "                        (0=disable key-frames altogether)\n"); | ||||
|   printf(" -mixed ............... use mixed lossy/lossless automatic mode\n"); | ||||
|   printf(" -v ................... verbose mode\n"); | ||||
|   printf(" -h ................... this help\n"); | ||||
|   printf(" -version ............. print version number and exit\n"); | ||||
|   printf("\n"); | ||||
|  | ||||
|   printf("Per-frame options (only used for subsequent images input):\n"); | ||||
|   printf(" -d <int> ............. frame duration in ms (default: 100)\n"); | ||||
|   printf(" -lossless  ........... use lossless mode (default)\n"); | ||||
|   printf(" -lossy ... ........... use lossy mode\n"); | ||||
|   printf(" -q <float> ........... quality\n"); | ||||
|   printf(" -m <int> ............. method to use\n"); | ||||
|  | ||||
|   printf("\n"); | ||||
|   printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n" | ||||
|          "                  -d 80 in2.tiff -o out.webp\n"); | ||||
|   printf("\nNote: if a single file name is passed as the argument, the " | ||||
|          "arguments will be\n"); | ||||
|   printf("tokenized from this file. The file name must not start with " | ||||
|          "the character '-'.\n"); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| static int ReadImage(const char filename[], WebPPicture* const pic) { | ||||
|   const uint8_t* data = NULL; | ||||
|   size_t data_size = 0; | ||||
|   WebPImageReader reader; | ||||
|   int ok; | ||||
| #ifdef HAVE_WINCODEC_H | ||||
|   // Try to decode the file using WIC falling back to the other readers for | ||||
|   // e.g., WebP. | ||||
|   ok = ReadPictureWithWIC(filename, pic, 1, NULL); | ||||
|   if (ok) return 1; | ||||
| #endif | ||||
|   if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0; | ||||
|   reader = WebPGuessImageReader(data, data_size); | ||||
|   ok = reader(data, data_size, pic, 1, NULL); | ||||
|   free((void*)data); | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| static int SetLoopCount(int loop_count, WebPData* const webp_data) { | ||||
|   int ok = 1; | ||||
|   WebPMuxError err; | ||||
|   uint32_t features; | ||||
|   WebPMuxAnimParams new_params; | ||||
|   WebPMux* const mux = WebPMuxCreate(webp_data, 1); | ||||
|   if (mux == NULL) return 0; | ||||
|  | ||||
|   err = WebPMuxGetFeatures(mux, &features); | ||||
|   ok = (err == WEBP_MUX_OK); | ||||
|   if (!ok || !(features & ANIMATION_FLAG)) goto End; | ||||
|  | ||||
|   err = WebPMuxGetAnimationParams(mux, &new_params); | ||||
|   ok = (err == WEBP_MUX_OK); | ||||
|   if (ok) { | ||||
|     new_params.loop_count = loop_count; | ||||
|     err = WebPMuxSetAnimationParams(mux, &new_params); | ||||
|     ok = (err == WEBP_MUX_OK); | ||||
|   } | ||||
|   if (ok) { | ||||
|     WebPDataClear(webp_data); | ||||
|     err = WebPMuxAssemble(mux, webp_data); | ||||
|     ok = (err == WEBP_MUX_OK); | ||||
|   } | ||||
|  | ||||
|  End: | ||||
|   WebPMuxDelete(mux); | ||||
|   if (!ok) { | ||||
|     fprintf(stderr, "Error during loop-count setting\n"); | ||||
|   } | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   const char* output = NULL; | ||||
|   WebPAnimEncoder* enc = NULL; | ||||
|   int verbose = 0; | ||||
|   int pic_num = 0; | ||||
|   int duration = 100; | ||||
|   int timestamp_ms = 0; | ||||
|   int loop_count = 0; | ||||
|   int width = 0, height = 0; | ||||
|   WebPAnimEncoderOptions anim_config; | ||||
|   WebPConfig config; | ||||
|   WebPPicture pic; | ||||
|   WebPData webp_data; | ||||
|   int c; | ||||
|   int have_input = 0; | ||||
|   CommandLineArguments cmd_args; | ||||
|   int ok; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args); | ||||
|   if (!ok) FREE_WARGV_AND_RETURN(1); | ||||
|  | ||||
|   argc = cmd_args.argc_; | ||||
|   argv = cmd_args.argv_; | ||||
|  | ||||
|   WebPDataInit(&webp_data); | ||||
|   if (!WebPAnimEncoderOptionsInit(&anim_config) || | ||||
|       !WebPConfigInit(&config) || | ||||
|       !WebPPictureInit(&pic)) { | ||||
|     fprintf(stderr, "Library version mismatch!\n"); | ||||
|     ok = 0; | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   // 1st pass of option parsing | ||||
|   for (c = 0; ok && c < argc; ++c) { | ||||
|     if (argv[c][0] == '-') { | ||||
|       int parse_error = 0; | ||||
|       if (!strcmp(argv[c], "-o") && c + 1 < argc) { | ||||
|         argv[c] = NULL; | ||||
|         output = (const char*)GET_WARGV_SHIFTED(argv, ++c); | ||||
|       } else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) { | ||||
|         argv[c] = NULL; | ||||
|         anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       } else if (!strcmp(argv[c], "-kmax") && c + 1 < argc) { | ||||
|         argv[c] = NULL; | ||||
|         anim_config.kmax = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       } else if (!strcmp(argv[c], "-loop") && c + 1 < argc) { | ||||
|         argv[c] = NULL; | ||||
|         loop_count = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|         if (loop_count < 0) { | ||||
|           fprintf(stderr, "Invalid non-positive loop-count (%d)\n", loop_count); | ||||
|           parse_error = 1; | ||||
|         } | ||||
|       } else if (!strcmp(argv[c], "-min_size")) { | ||||
|         anim_config.minimize_size = 1; | ||||
|       } else if (!strcmp(argv[c], "-mixed")) { | ||||
|         anim_config.allow_mixed = 1; | ||||
|         config.lossless = 0; | ||||
|       } else if (!strcmp(argv[c], "-v")) { | ||||
|         verbose = 1; | ||||
|       } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|         Help(); | ||||
|         goto End; | ||||
|       } else if (!strcmp(argv[c], "-version")) { | ||||
|         const int enc_version = WebPGetEncoderVersion(); | ||||
|         const int mux_version = WebPGetMuxVersion(); | ||||
|         printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n", | ||||
|                (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, | ||||
|                enc_version & 0xff, (mux_version >> 16) & 0xff, | ||||
|                (mux_version >> 8) & 0xff, mux_version & 0xff); | ||||
|         goto End; | ||||
|       } else { | ||||
|         continue; | ||||
|       } | ||||
|       ok = !parse_error; | ||||
|       if (!ok) goto End; | ||||
|       argv[c] = NULL;   // mark option as 'parsed' during 1st pass | ||||
|     } else { | ||||
|       have_input |= 1; | ||||
|     } | ||||
|   } | ||||
|   if (!have_input) { | ||||
|     fprintf(stderr, "No input file(s) for generating animation!\n"); | ||||
|     goto End; | ||||
|   } | ||||
|  | ||||
|   // image-reading pass | ||||
|   pic_num = 0; | ||||
|   config.lossless = 1; | ||||
|   for (c = 0; ok && c < argc; ++c) { | ||||
|     if (argv[c] == NULL) continue; | ||||
|     if (argv[c][0] == '-') {    // parse local options | ||||
|       int parse_error = 0; | ||||
|       if (!strcmp(argv[c], "-lossy")) { | ||||
|         if (!anim_config.allow_mixed) config.lossless = 0; | ||||
|       } else if (!strcmp(argv[c], "-lossless")) { | ||||
|         if (!anim_config.allow_mixed) config.lossless = 1; | ||||
|       } else if (!strcmp(argv[c], "-q") && c + 1 < argc) { | ||||
|         config.quality = ExUtilGetFloat(argv[++c], &parse_error); | ||||
|       } else if (!strcmp(argv[c], "-m") && c + 1 < argc) { | ||||
|         config.method = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|       } else if (!strcmp(argv[c], "-d") && c + 1 < argc) { | ||||
|         duration = ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|         if (duration <= 0) { | ||||
|           fprintf(stderr, "Invalid negative duration (%d)\n", duration); | ||||
|           parse_error = 1; | ||||
|         } | ||||
|       } else { | ||||
|         parse_error = 1;   // shouldn't be here. | ||||
|         fprintf(stderr, "Unknown option [%s]\n", argv[c]); | ||||
|       } | ||||
|       ok = !parse_error; | ||||
|       if (!ok) goto End; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (ok) { | ||||
|       ok = WebPValidateConfig(&config); | ||||
|       if (!ok) { | ||||
|         fprintf(stderr, "Invalid configuration.\n"); | ||||
|         goto End; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // read next input image | ||||
|     pic.use_argb = 1; | ||||
|     ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic); | ||||
|     if (!ok) goto End; | ||||
|  | ||||
|     if (enc == NULL) { | ||||
|       width  = pic.width; | ||||
|       height = pic.height; | ||||
|       enc = WebPAnimEncoderNew(width, height, &anim_config); | ||||
|       ok = (enc != NULL); | ||||
|       if (!ok) { | ||||
|         fprintf(stderr, "Could not create WebPAnimEncoder object.\n"); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (ok) { | ||||
|       ok = (width == pic.width && height == pic.height); | ||||
|       if (!ok) { | ||||
|         fprintf(stderr, "Frame #%d dimension mismatched! " | ||||
|                         "Got %d x %d. Was expecting %d x %d.\n", | ||||
|                 pic_num, pic.width, pic.height, width, height); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (ok) { | ||||
|       ok = WebPAnimEncoderAdd(enc, &pic, timestamp_ms, &config); | ||||
|       if (!ok) { | ||||
|         fprintf(stderr, "Error while adding frame #%d\n", pic_num); | ||||
|       } | ||||
|     } | ||||
|     WebPPictureFree(&pic); | ||||
|     if (!ok) goto End; | ||||
|  | ||||
|     if (verbose) { | ||||
|       WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n", | ||||
|                pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c)); | ||||
|     } | ||||
|     timestamp_ms += duration; | ||||
|     ++pic_num; | ||||
|   } | ||||
|  | ||||
|   // add a last fake frame to signal the last duration | ||||
|   ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL); | ||||
|   ok = ok && WebPAnimEncoderAssemble(enc, &webp_data); | ||||
|   if (!ok) { | ||||
|     fprintf(stderr, "Error during final animation assembly.\n"); | ||||
|   } | ||||
|  | ||||
|  End: | ||||
|   // free resources | ||||
|   WebPAnimEncoderDelete(enc); | ||||
|  | ||||
|   if (ok && loop_count > 0) {  // Re-mux to add loop count. | ||||
|     ok = SetLoopCount(loop_count, &webp_data); | ||||
|   } | ||||
|  | ||||
|   if (ok) { | ||||
|     if (output != NULL) { | ||||
|       ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size); | ||||
|       if (ok) WFPRINTF(stderr, "output file: %s     ", (const W_CHAR*)output); | ||||
|     } else { | ||||
|       fprintf(stderr, "[no output file specified]   "); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (ok) { | ||||
|     fprintf(stderr, "[%d frames, %u bytes].\n", | ||||
|             pic_num, (unsigned int)webp_data.size); | ||||
|   } | ||||
|   WebPDataClear(&webp_data); | ||||
|   ExUtilDeleteCommandLineArguments(&cmd_args); | ||||
|   FREE_WARGV_AND_RETURN(ok ? 0 : 1); | ||||
| } | ||||
							
								
								
									
										63
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/stopwatch.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/stopwatch.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| // Copyright 2011 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  Helper functions to measure elapsed time. | ||||
| // | ||||
| // Author: Mikolaj Zalewski (mikolajz@google.com) | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_STOPWATCH_H_ | ||||
| #define WEBP_EXAMPLES_STOPWATCH_H_ | ||||
|  | ||||
| #include "webp/types.h" | ||||
|  | ||||
| #if defined _WIN32 && !defined __GNUC__ | ||||
| #include <windows.h> | ||||
|  | ||||
| typedef LARGE_INTEGER Stopwatch; | ||||
|  | ||||
| static WEBP_INLINE void StopwatchReset(Stopwatch* watch) { | ||||
|   QueryPerformanceCounter(watch); | ||||
| } | ||||
|  | ||||
| static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { | ||||
|   const LARGE_INTEGER old_value = *watch; | ||||
|   LARGE_INTEGER freq; | ||||
|   if (!QueryPerformanceCounter(watch)) | ||||
|     return 0.0; | ||||
|   if (!QueryPerformanceFrequency(&freq)) | ||||
|     return 0.0; | ||||
|   if (freq.QuadPart == 0) | ||||
|     return 0.0; | ||||
|   return (watch->QuadPart - old_value.QuadPart) / (double)freq.QuadPart; | ||||
| } | ||||
|  | ||||
|  | ||||
| #else    /* !_WIN32 */ | ||||
| #include <string.h>  // memcpy | ||||
| #include <sys/time.h> | ||||
|  | ||||
| typedef struct timeval Stopwatch; | ||||
|  | ||||
| static WEBP_INLINE void StopwatchReset(Stopwatch* watch) { | ||||
|   gettimeofday(watch, NULL); | ||||
| } | ||||
|  | ||||
| static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { | ||||
|   struct timeval old_value; | ||||
|   double delta_sec, delta_usec; | ||||
|   memcpy(&old_value, watch, sizeof(old_value)); | ||||
|   gettimeofday(watch, NULL); | ||||
|   delta_sec = (double)watch->tv_sec - old_value.tv_sec; | ||||
|   delta_usec = (double)watch->tv_usec - old_value.tv_usec; | ||||
|   return delta_sec + delta_usec / 1000000.0; | ||||
| } | ||||
|  | ||||
| #endif   /* _WIN32 */ | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_STOPWATCH_H_ | ||||
							
								
								
									
										
											BIN
										
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/test.webp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/test.webp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										4
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/test_ref.ppm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/test_ref.ppm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										101
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/unicode.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/unicode.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| // Copyright 2018 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // Unicode support for Windows. The main idea is to maintain an array of Unicode | ||||
| // arguments (wargv) and use it only for file paths. The regular argv is used | ||||
| // for everything else. | ||||
| // | ||||
| // Author: Yannis Guyon (yguyon@google.com) | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_UNICODE_H_ | ||||
| #define WEBP_EXAMPLES_UNICODE_H_ | ||||
|  | ||||
| #if defined(_WIN32) && defined(_UNICODE) | ||||
|  | ||||
| // wchar_t is used instead of TCHAR because we only perform additional work when | ||||
| // Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t. | ||||
|  | ||||
| #include <wchar.h> | ||||
| #include <windows.h> | ||||
| #include <shellapi.h> | ||||
|  | ||||
| // Create a wchar_t array containing Unicode parameters. | ||||
| #define INIT_WARGV(ARGC, ARGV)                                                \ | ||||
|   int wargc;                                                                  \ | ||||
|   const W_CHAR** const wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); \ | ||||
|   do {                                                                        \ | ||||
|     if (wargv == NULL || wargc != (ARGC)) {                                   \ | ||||
|       fprintf(stderr, "Error: Unable to get Unicode arguments.\n");           \ | ||||
|       FREE_WARGV_AND_RETURN(-1);                                              \ | ||||
|     }                                                                         \ | ||||
|   } while (0) | ||||
|  | ||||
| // Use this to get a Unicode argument (e.g. file path). | ||||
| #define GET_WARGV(UNUSED, C) wargv[C] | ||||
| // For cases where argv is shifted by one compared to wargv. | ||||
| #define GET_WARGV_SHIFTED(UNUSED, C) wargv[(C) + 1] | ||||
| #define GET_WARGV_OR_NULL() wargv | ||||
|  | ||||
| // Release resources. LocalFree() is needed after CommandLineToArgvW(). | ||||
| #define FREE_WARGV() LOCAL_FREE((W_CHAR** const)wargv) | ||||
| #define LOCAL_FREE(WARGV)                  \ | ||||
|   do {                                     \ | ||||
|     if ((WARGV) != NULL) LocalFree(WARGV); \ | ||||
|   } while (0) | ||||
|  | ||||
| #define W_CHAR wchar_t  // WCHAR without underscore might already be defined. | ||||
| #define TO_W_CHAR(STR) (L##STR) | ||||
|  | ||||
| #define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT)) | ||||
|  | ||||
| #define WPRINTF(STR, ...) wprintf(TO_W_CHAR(STR), __VA_ARGS__) | ||||
| #define WFPRINTF(STDERR, STR, ...) fwprintf(STDERR, TO_W_CHAR(STR), __VA_ARGS__) | ||||
|  | ||||
| #define WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME) | ||||
| #define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) | ||||
| #define WSTRRCHR(FILENAME, STR) wcsrchr((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) | ||||
| #define WSNPRINTF(A, B, STR, ...) _snwprintf(A, B, TO_W_CHAR(STR), __VA_ARGS__) | ||||
|  | ||||
| #else | ||||
|  | ||||
| // Unicode file paths work as is on Unix platforms, and no extra work is done on | ||||
| // Windows either if Unicode is disabled. | ||||
|  | ||||
| #define INIT_WARGV(ARGC, ARGV) | ||||
|  | ||||
| #define GET_WARGV(ARGV, C) (ARGV)[C] | ||||
| #define GET_WARGV_SHIFTED(ARGV, C) (ARGV)[C] | ||||
| #define GET_WARGV_OR_NULL() NULL | ||||
|  | ||||
| #define FREE_WARGV() | ||||
| #define LOCAL_FREE(WARGV) | ||||
|  | ||||
| #define W_CHAR char | ||||
| #define TO_W_CHAR(STR) (STR) | ||||
|  | ||||
| #define WFOPEN(ARG, OPT) fopen(ARG, OPT) | ||||
|  | ||||
| #define WPRINTF(STR, ...) printf(STR, __VA_ARGS__) | ||||
| #define WFPRINTF(STDERR, STR, ...) fprintf(STDERR, STR, __VA_ARGS__) | ||||
|  | ||||
| #define WSTRLEN(FILENAME) strlen(FILENAME) | ||||
| #define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR) | ||||
| #define WSTRRCHR(FILENAME, STR) strrchr(FILENAME, STR) | ||||
| #define WSNPRINTF(A, B, STR, ...) snprintf(A, B, STR, __VA_ARGS__) | ||||
|  | ||||
| #endif  // defined(_WIN32) && defined(_UNICODE) | ||||
|  | ||||
| // Don't forget to free wargv before returning (e.g. from main). | ||||
| #define FREE_WARGV_AND_RETURN(VALUE) \ | ||||
|   do {                               \ | ||||
|     FREE_WARGV();                    \ | ||||
|     return (VALUE);                  \ | ||||
|   } while (0) | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_UNICODE_H_ | ||||
							
								
								
									
										75
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/unicode_gif.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/unicode_gif.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| // Copyright 2018 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| // giflib doesn't have a Unicode DGifOpenFileName(). Let's make one. | ||||
| // | ||||
| // Author: Yannis Guyon (yguyon@google.com) | ||||
|  | ||||
| #ifndef WEBP_EXAMPLES_UNICODE_GIF_H_ | ||||
| #define WEBP_EXAMPLES_UNICODE_GIF_H_ | ||||
|  | ||||
| #include "./unicode.h" | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h"  // For WEBP_HAVE_GIF | ||||
| #endif | ||||
|  | ||||
| #if defined(WEBP_HAVE_GIF) | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #include <fcntl.h>  // Not standard, needed for _topen and flags. | ||||
| #include <io.h> | ||||
| #endif | ||||
|  | ||||
| #include <gif_lib.h> | ||||
| #include <string.h> | ||||
| #include "./gifdec.h" | ||||
|  | ||||
| #if !defined(STDIN_FILENO) | ||||
| #define STDIN_FILENO 0 | ||||
| #endif | ||||
|  | ||||
| static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) { | ||||
|   if (!WSTRCMP(file_name, "-")) { | ||||
| #if LOCAL_GIF_PREREQ(5, 0) | ||||
|     return DGifOpenFileHandle(STDIN_FILENO, error); | ||||
| #else | ||||
|     (void)error; | ||||
|     return DGifOpenFileHandle(STDIN_FILENO); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
| #if defined(_WIN32) && defined(_UNICODE) | ||||
|  | ||||
|   int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY); | ||||
|   if (file_handle == -1) { | ||||
|     if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED; | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
| #if LOCAL_GIF_PREREQ(5, 0) | ||||
|   return DGifOpenFileHandle(file_handle, error); | ||||
| #else | ||||
|   return DGifOpenFileHandle(file_handle); | ||||
| #endif | ||||
|  | ||||
| #else | ||||
|  | ||||
| #if LOCAL_GIF_PREREQ(5, 0) | ||||
|   return DGifOpenFileName(file_name, error); | ||||
| #else | ||||
|   return DGifOpenFileName(file_name); | ||||
| #endif | ||||
|  | ||||
| #endif  // defined(_WIN32) && defined(_UNICODE) | ||||
|   // DGifCloseFile() is called later. | ||||
| } | ||||
|  | ||||
| #endif  // defined(WEBP_HAVE_GIF) | ||||
|  | ||||
| #endif  // WEBP_EXAMPLES_UNICODE_GIF_H_ | ||||
							
								
								
									
										628
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/vwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/vwebp.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,628 @@ | ||||
| // Copyright 2011 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style license | ||||
| // that can be found in the COPYING file in the root of the source | ||||
| // tree. An additional intellectual property rights grant can be found | ||||
| // in the file PATENTS. All contributing project authors may | ||||
| // be found in the AUTHORS file in the root of the source tree. | ||||
| // ----------------------------------------------------------------------------- | ||||
| // | ||||
| //  Simple OpenGL-based WebP file viewer. | ||||
| // | ||||
| // Author: Skal (pascal.massimino@gmail.com) | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "webp/config.h" | ||||
| #endif | ||||
|  | ||||
| #if defined(__unix__) || defined(__CYGWIN__) | ||||
| #define _POSIX_C_SOURCE 200112L  // for setenv | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #if defined(WEBP_HAVE_GL) | ||||
|  | ||||
| #if defined(HAVE_GLUT_GLUT_H) | ||||
| #include <GLUT/glut.h> | ||||
| #else | ||||
| #include <GL/glut.h> | ||||
| #ifdef FREEGLUT | ||||
| #include <GL/freeglut.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef WEBP_HAVE_QCMS | ||||
| #include <qcms.h> | ||||
| #endif | ||||
|  | ||||
| #include "webp/decode.h" | ||||
| #include "webp/demux.h" | ||||
|  | ||||
| #include "../examples/example_util.h" | ||||
| #include "../imageio/imageio_util.h" | ||||
| #include "./unicode.h" | ||||
|  | ||||
| #if defined(_MSC_VER) && _MSC_VER < 1900 | ||||
| #define snprintf _snprintf | ||||
| #endif | ||||
|  | ||||
| // Unfortunate global variables. Gathered into a struct for comfort. | ||||
| static struct { | ||||
|   int has_animation; | ||||
|   int has_color_profile; | ||||
|   int done; | ||||
|   int decoding_error; | ||||
|   int print_info; | ||||
|   int only_deltas; | ||||
|   int use_color_profile; | ||||
|   int draw_anim_background_color; | ||||
|  | ||||
|   int canvas_width, canvas_height; | ||||
|   int loop_count; | ||||
|   uint32_t bg_color; | ||||
|  | ||||
|   const char* file_name; | ||||
|   WebPData data; | ||||
|   WebPDecoderConfig config; | ||||
|   const WebPDecBuffer* pic; | ||||
|   WebPDemuxer* dmux; | ||||
|   WebPIterator curr_frame; | ||||
|   WebPIterator prev_frame; | ||||
|   WebPChunkIterator iccp; | ||||
|   int viewport_width, viewport_height; | ||||
| } kParams; | ||||
|  | ||||
| static void ClearPreviousPic(void) { | ||||
|   WebPFreeDecBuffer((WebPDecBuffer*)kParams.pic); | ||||
|   kParams.pic = NULL; | ||||
| } | ||||
|  | ||||
| static void ClearParams(void) { | ||||
|   ClearPreviousPic(); | ||||
|   WebPDataClear(&kParams.data); | ||||
|   WebPDemuxReleaseIterator(&kParams.curr_frame); | ||||
|   WebPDemuxReleaseIterator(&kParams.prev_frame); | ||||
|   WebPDemuxReleaseChunkIterator(&kParams.iccp); | ||||
|   WebPDemuxDelete(kParams.dmux); | ||||
|   kParams.dmux = NULL; | ||||
| } | ||||
|  | ||||
| // Sets the previous frame to the dimensions of the canvas and has it dispose | ||||
| // to background to cause the canvas to be cleared. | ||||
| static void ClearPreviousFrame(void) { | ||||
|   WebPIterator* const prev = &kParams.prev_frame; | ||||
|   prev->width = kParams.canvas_width; | ||||
|   prev->height = kParams.canvas_height; | ||||
|   prev->x_offset = prev->y_offset = 0; | ||||
|   prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // Color profile handling | ||||
| static int ApplyColorProfile(const WebPData* const profile, | ||||
|                              WebPDecBuffer* const rgba) { | ||||
| #ifdef WEBP_HAVE_QCMS | ||||
|   int i, ok = 0; | ||||
|   uint8_t* line; | ||||
|   uint8_t major_revision; | ||||
|   qcms_profile* input_profile = NULL; | ||||
|   qcms_profile* output_profile = NULL; | ||||
|   qcms_transform* transform = NULL; | ||||
|   const qcms_data_type input_type = QCMS_DATA_RGBA_8; | ||||
|   const qcms_data_type output_type = QCMS_DATA_RGBA_8; | ||||
|   const qcms_intent intent = QCMS_INTENT_DEFAULT; | ||||
|  | ||||
|   if (profile == NULL || rgba == NULL) return 0; | ||||
|   if (profile->bytes == NULL || profile->size < 10) return 1; | ||||
|   major_revision = profile->bytes[8]; | ||||
|  | ||||
|   qcms_enable_iccv4(); | ||||
|   input_profile = qcms_profile_from_memory(profile->bytes, profile->size); | ||||
|   // qcms_profile_is_bogus() is broken with ICCv4. | ||||
|   if (input_profile == NULL || | ||||
|       (major_revision < 4 && qcms_profile_is_bogus(input_profile))) { | ||||
|     fprintf(stderr, "Color profile is bogus!\n"); | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   output_profile = qcms_profile_sRGB(); | ||||
|   if (output_profile == NULL) { | ||||
|     fprintf(stderr, "Error creating output color profile!\n"); | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   qcms_profile_precache_output_transform(output_profile); | ||||
|   transform = qcms_transform_create(input_profile, input_type, | ||||
|                                     output_profile, output_type, | ||||
|                                     intent); | ||||
|   if (transform == NULL) { | ||||
|     fprintf(stderr, "Error creating color transform!\n"); | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   line = rgba->u.RGBA.rgba; | ||||
|   for (i = 0; i < rgba->height; ++i, line += rgba->u.RGBA.stride) { | ||||
|     qcms_transform_data(transform, line, line, rgba->width); | ||||
|   } | ||||
|   ok = 1; | ||||
|  | ||||
|  Error: | ||||
|   if (input_profile != NULL) qcms_profile_release(input_profile); | ||||
|   if (output_profile != NULL) qcms_profile_release(output_profile); | ||||
|   if (transform != NULL) qcms_transform_release(transform); | ||||
|   return ok; | ||||
| #else | ||||
|   (void)profile; | ||||
|   (void)rgba; | ||||
|   return 1; | ||||
| #endif  // WEBP_HAVE_QCMS | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // File decoding | ||||
|  | ||||
| static int Decode(void) {   // Fills kParams.curr_frame | ||||
|   const WebPIterator* const curr = &kParams.curr_frame; | ||||
|   WebPDecoderConfig* const config = &kParams.config; | ||||
|   WebPDecBuffer* const output_buffer = &config->output; | ||||
|   int ok = 0; | ||||
|  | ||||
|   ClearPreviousPic(); | ||||
|   output_buffer->colorspace = MODE_RGBA; | ||||
|   ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size, | ||||
|                    config) == VP8_STATUS_OK); | ||||
|   if (!ok) { | ||||
|     fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num); | ||||
|   } else { | ||||
|     kParams.pic = output_buffer; | ||||
|     if (kParams.use_color_profile) { | ||||
|       ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer); | ||||
|       if (!ok) { | ||||
|         fprintf(stderr, "Applying color profile to frame #%d failed!\n", | ||||
|                 curr->frame_num); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return ok; | ||||
| } | ||||
|  | ||||
| static void decode_callback(int what) { | ||||
|   if (what == 0 && !kParams.done) { | ||||
|     int duration = 0; | ||||
|     if (kParams.dmux != NULL) { | ||||
|       WebPIterator* const curr = &kParams.curr_frame; | ||||
|       if (!WebPDemuxNextFrame(curr)) { | ||||
|         WebPDemuxReleaseIterator(curr); | ||||
|         if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { | ||||
|           --kParams.loop_count; | ||||
|           kParams.done = (kParams.loop_count == 0); | ||||
|           if (kParams.done) return; | ||||
|           ClearPreviousFrame(); | ||||
|         } else { | ||||
|           kParams.decoding_error = 1; | ||||
|           kParams.done = 1; | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|       duration = curr->duration; | ||||
|       // Behavior copied from Chrome, cf: | ||||
|       // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/ | ||||
|       // platform/graphics/DeferredImageDecoder.cpp? | ||||
|       // rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246 | ||||
|       if (duration <= 10) duration = 100; | ||||
|     } | ||||
|     if (!Decode()) { | ||||
|       kParams.decoding_error = 1; | ||||
|       kParams.done = 1; | ||||
|     } else { | ||||
|       glutPostRedisplay(); | ||||
|       glutTimerFunc(duration, decode_callback, what); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Callbacks | ||||
|  | ||||
| static void HandleKey(unsigned char key, int pos_x, int pos_y) { | ||||
|   // Note: rescaling the window or toggling some features during an animation | ||||
|   // generates visual artifacts. This is not fixed because refreshing the frame | ||||
|   // may require rendering the whole animation from start till current frame. | ||||
|   (void)pos_x; | ||||
|   (void)pos_y; | ||||
|   if (key == 'q' || key == 'Q' || key == 27 /* Esc */) { | ||||
| #ifdef FREEGLUT | ||||
|     glutLeaveMainLoop(); | ||||
| #else | ||||
|     ClearParams(); | ||||
|     exit(0); | ||||
| #endif | ||||
|   } else if (key == 'c') { | ||||
|     if (kParams.has_color_profile && !kParams.decoding_error) { | ||||
|       kParams.use_color_profile = 1 - kParams.use_color_profile; | ||||
|  | ||||
|       if (kParams.has_animation) { | ||||
|         // Restart the completed animation to pickup the color profile change. | ||||
|         if (kParams.done && kParams.loop_count == 0) { | ||||
|           kParams.loop_count = | ||||
|               (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT) + 1; | ||||
|           kParams.done = 0; | ||||
|           // Start the decode loop immediately. | ||||
|           glutTimerFunc(0, decode_callback, 0); | ||||
|         } | ||||
|       } else { | ||||
|         Decode(); | ||||
|         glutPostRedisplay(); | ||||
|       } | ||||
|     } | ||||
|   } else if (key == 'b') { | ||||
|     kParams.draw_anim_background_color = 1 - kParams.draw_anim_background_color; | ||||
|     if (!kParams.has_animation) ClearPreviousFrame(); | ||||
|     glutPostRedisplay(); | ||||
|   } else if (key == 'i') { | ||||
|     kParams.print_info = 1 - kParams.print_info; | ||||
|     if (!kParams.has_animation) ClearPreviousFrame(); | ||||
|     glutPostRedisplay(); | ||||
|   } else if (key == 'd') { | ||||
|     kParams.only_deltas = 1 - kParams.only_deltas; | ||||
|     glutPostRedisplay(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| static void HandleReshape(int width, int height) { | ||||
|   // Note: reshape doesn't preserve aspect ratio, and might | ||||
|   // be handling larger-than-screen pictures incorrectly. | ||||
|   glViewport(0, 0, width, height); | ||||
|   glMatrixMode(GL_PROJECTION); | ||||
|   glLoadIdentity(); | ||||
|   glMatrixMode(GL_MODELVIEW); | ||||
|   glLoadIdentity(); | ||||
|   kParams.viewport_width = width; | ||||
|   kParams.viewport_height = height; | ||||
|   if (!kParams.has_animation) ClearPreviousFrame(); | ||||
| } | ||||
|  | ||||
| static void PrintString(const char* const text) { | ||||
|   void* const font = GLUT_BITMAP_9_BY_15; | ||||
|   int i; | ||||
|   for (i = 0; text[i]; ++i) { | ||||
|     glutBitmapCharacter(font, text[i]); | ||||
|   } | ||||
| } | ||||
|  | ||||
| static float GetColorf(uint32_t color, int shift) { | ||||
|   return ((color >> shift) & 0xff) / 255.f; | ||||
| } | ||||
|  | ||||
| static void DrawCheckerBoard(void) { | ||||
|   const int square_size = 8;  // must be a power of 2 | ||||
|   int x, y; | ||||
|   GLint viewport[4];  // x, y, width, height | ||||
|  | ||||
|   glPushMatrix(); | ||||
|  | ||||
|   glGetIntegerv(GL_VIEWPORT, viewport); | ||||
|   // shift to integer coordinates with (0,0) being top-left. | ||||
|   glOrtho(0, viewport[2], viewport[3], 0, -1, 1); | ||||
|   for (y = 0; y < viewport[3]; y += square_size) { | ||||
|     for (x = 0; x < viewport[2]; x += square_size) { | ||||
|       const GLubyte color = 128 + 64 * (!((x + y) & square_size)); | ||||
|       glColor3ub(color, color, color); | ||||
|       glRecti(x, y, x + square_size, y + square_size); | ||||
|     } | ||||
|   } | ||||
|   glPopMatrix(); | ||||
| } | ||||
|  | ||||
| static void DrawBackground(void) { | ||||
|   // Whole window cleared with clear color, checkerboard rendered on top of it. | ||||
|   glClear(GL_COLOR_BUFFER_BIT); | ||||
|   DrawCheckerBoard(); | ||||
|  | ||||
|   // ANIM background color rendered (blend) on top. Default is white for still | ||||
|   // images (without ANIM chunk). glClear() can't be used for that (no blend). | ||||
|   if (kParams.draw_anim_background_color) { | ||||
|     glPushMatrix(); | ||||
|     glLoadIdentity(); | ||||
|     glColor4f(GetColorf(kParams.bg_color, 16),  // BGRA from spec | ||||
|               GetColorf(kParams.bg_color, 8), | ||||
|               GetColorf(kParams.bg_color, 0), | ||||
|               GetColorf(kParams.bg_color, 24)); | ||||
|     glRecti(-1, -1, +1, +1); | ||||
|     glPopMatrix(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Draw background in a scissored rectangle. | ||||
| static void DrawBackgroundScissored(int window_x, int window_y, int frame_w, | ||||
|                                     int frame_h) { | ||||
|   // Only update the requested area, not the whole canvas. | ||||
|   window_x = window_x * kParams.viewport_width / kParams.canvas_width; | ||||
|   window_y = window_y * kParams.viewport_height / kParams.canvas_height; | ||||
|   frame_w = frame_w * kParams.viewport_width / kParams.canvas_width; | ||||
|   frame_h = frame_h * kParams.viewport_height / kParams.canvas_height; | ||||
|  | ||||
|   // glScissor() takes window coordinates (0,0 at bottom left). | ||||
|   window_y = kParams.viewport_height - window_y - frame_h; | ||||
|  | ||||
|   glEnable(GL_SCISSOR_TEST); | ||||
|   glScissor(window_x, window_y, frame_w, frame_h); | ||||
|   DrawBackground(); | ||||
|   glDisable(GL_SCISSOR_TEST); | ||||
| } | ||||
|  | ||||
| static void HandleDisplay(void) { | ||||
|   const WebPDecBuffer* const pic = kParams.pic; | ||||
|   const WebPIterator* const curr = &kParams.curr_frame; | ||||
|   WebPIterator* const prev = &kParams.prev_frame; | ||||
|   GLfloat xoff, yoff; | ||||
|   if (pic == NULL) return; | ||||
|   glPushMatrix(); | ||||
|   glPixelZoom((GLfloat)(+1. / kParams.canvas_width * kParams.viewport_width), | ||||
|               (GLfloat)(-1. / kParams.canvas_height * kParams.viewport_height)); | ||||
|   xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width); | ||||
|   yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height); | ||||
|   glRasterPos2f(-1.f + xoff, 1.f - yoff); | ||||
|   glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|   glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); | ||||
|  | ||||
|   if (kParams.only_deltas) { | ||||
|     DrawBackground(); | ||||
|   } else { | ||||
|     // The rectangle of the previous frame might be different than the current | ||||
|     // frame, so we may need to DrawBackgroundScissored for both. | ||||
|     if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { | ||||
|       // Clear the previous frame rectangle. | ||||
|       DrawBackgroundScissored(prev->x_offset, prev->y_offset, prev->width, | ||||
|                               prev->height); | ||||
|     } | ||||
|     if (curr->blend_method == WEBP_MUX_NO_BLEND) { | ||||
|       // We simulate no-blending behavior by first clearing the current frame | ||||
|       // rectangle and then alpha-blending against it. | ||||
|       DrawBackgroundScissored(curr->x_offset, curr->y_offset, curr->width, | ||||
|                               curr->height); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   *prev = *curr; | ||||
|  | ||||
|   glDrawPixels(pic->width, pic->height, | ||||
|                GL_RGBA, GL_UNSIGNED_BYTE, | ||||
|                (GLvoid*)pic->u.RGBA.rgba); | ||||
|   if (kParams.print_info) { | ||||
|     char tmp[32]; | ||||
|  | ||||
|     glColor4f(0.90f, 0.0f, 0.90f, 1.0f); | ||||
|     glRasterPos2f(-0.95f, 0.90f); | ||||
|     PrintString(kParams.file_name); | ||||
|  | ||||
|     snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height); | ||||
|     glColor4f(0.90f, 0.0f, 0.90f, 1.0f); | ||||
|     glRasterPos2f(-0.95f, 0.80f); | ||||
|     PrintString(tmp); | ||||
|     if (curr->x_offset != 0 || curr->y_offset != 0) { | ||||
|       snprintf(tmp, sizeof(tmp), " (offset:%d,%d)", | ||||
|                curr->x_offset, curr->y_offset); | ||||
|       glRasterPos2f(-0.95f, 0.70f); | ||||
|       PrintString(tmp); | ||||
|     } | ||||
|   } | ||||
|   glPopMatrix(); | ||||
| #if defined(__APPLE__) || defined(_WIN32) | ||||
|   glFlush(); | ||||
| #else | ||||
|   glutSwapBuffers(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void StartDisplay(void) { | ||||
|   const int width = kParams.canvas_width; | ||||
|   const int height = kParams.canvas_height; | ||||
|   // TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be | ||||
|   // partially displayed with animated webp + alpha. | ||||
| #if defined(__APPLE__) || defined(_WIN32) | ||||
|   glutInitDisplayMode(GLUT_RGBA); | ||||
| #else | ||||
|   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); | ||||
| #endif | ||||
|   glutInitWindowSize(width, height); | ||||
|   glutCreateWindow("WebP viewer"); | ||||
|   glutDisplayFunc(HandleDisplay); | ||||
|   glutReshapeFunc(HandleReshape); | ||||
|   glutIdleFunc(NULL); | ||||
|   glutKeyboardFunc(HandleKey); | ||||
|   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
|   glEnable(GL_BLEND); | ||||
|   glClearColor(0, 0, 0, 0);  // window will be cleared to black (no blend) | ||||
|   DrawBackground(); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Main | ||||
|  | ||||
| static void Help(void) { | ||||
|   printf( | ||||
|       "Usage: vwebp in_file [options]\n\n" | ||||
|       "Decodes the WebP image file and visualize it using OpenGL\n" | ||||
|       "Options are:\n" | ||||
|       "  -version ..... print version number and exit\n" | ||||
|       "  -noicc ....... don't use the icc profile if present\n" | ||||
|       "  -nofancy ..... don't use the fancy YUV420 upscaler\n" | ||||
|       "  -nofilter .... disable in-loop filtering\n" | ||||
|       "  -dither <int>  dithering strength (0..100), default=50\n" | ||||
|       "  -noalphadither disable alpha plane dithering\n" | ||||
|       "  -usebgcolor .. display background color\n" | ||||
|       "  -mt .......... use multi-threading\n" | ||||
|       "  -info ........ print info\n" | ||||
|       "  -h ........... this help message\n" | ||||
|       "\n" | ||||
|       "Keyboard shortcuts:\n" | ||||
|       "  'c' ................ toggle use of color profile\n" | ||||
|       "  'b' ................ toggle background color display\n" | ||||
|       "  'i' ................ overlay file information\n" | ||||
|       "  'd' ................ disable blending & disposal (debug)\n" | ||||
|       "  'q' / 'Q' / ESC .... quit\n"); | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|   int c; | ||||
|   WebPDecoderConfig* const config = &kParams.config; | ||||
|   WebPIterator* const curr = &kParams.curr_frame; | ||||
|  | ||||
|   INIT_WARGV(argc, argv); | ||||
|  | ||||
|   if (!WebPInitDecoderConfig(config)) { | ||||
|     fprintf(stderr, "Library version mismatch!\n"); | ||||
|     FREE_WARGV_AND_RETURN(-1); | ||||
|   } | ||||
|   config->options.dithering_strength = 50; | ||||
|   config->options.alpha_dithering_strength = 100; | ||||
|   kParams.use_color_profile = 1; | ||||
|   // Background color hidden by default to see transparent areas. | ||||
|   kParams.draw_anim_background_color = 0; | ||||
|  | ||||
|   for (c = 1; c < argc; ++c) { | ||||
|     int parse_error = 0; | ||||
|     if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-noicc")) { | ||||
|       kParams.use_color_profile = 0; | ||||
|     } else if (!strcmp(argv[c], "-nofancy")) { | ||||
|       config->options.no_fancy_upsampling = 1; | ||||
|     } else if (!strcmp(argv[c], "-nofilter")) { | ||||
|       config->options.bypass_filtering = 1; | ||||
|     } else if (!strcmp(argv[c], "-noalphadither")) { | ||||
|       config->options.alpha_dithering_strength = 0; | ||||
|     } else if (!strcmp(argv[c], "-usebgcolor")) { | ||||
|       kParams.draw_anim_background_color = 1; | ||||
|     } else if (!strcmp(argv[c], "-dither") && c + 1 < argc) { | ||||
|       config->options.dithering_strength = | ||||
|           ExUtilGetInt(argv[++c], 0, &parse_error); | ||||
|     } else if (!strcmp(argv[c], "-info")) { | ||||
|       kParams.print_info = 1; | ||||
|     } else if (!strcmp(argv[c], "-version")) { | ||||
|       const int dec_version = WebPGetDecoderVersion(); | ||||
|       const int dmux_version = WebPGetDemuxVersion(); | ||||
|       printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", | ||||
|              (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, | ||||
|              dec_version & 0xff, (dmux_version >> 16) & 0xff, | ||||
|              (dmux_version >> 8) & 0xff, dmux_version & 0xff); | ||||
|       FREE_WARGV_AND_RETURN(0); | ||||
|     } else if (!strcmp(argv[c], "-mt")) { | ||||
|       config->options.use_threads = 1; | ||||
|     } else if (!strcmp(argv[c], "--")) { | ||||
|       if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c); | ||||
|       break; | ||||
|     } else if (argv[c][0] == '-') { | ||||
|       printf("Unknown option '%s'\n", argv[c]); | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } else { | ||||
|       kParams.file_name = (const char*)GET_WARGV(argv, c); | ||||
|     } | ||||
|  | ||||
|     if (parse_error) { | ||||
|       Help(); | ||||
|       FREE_WARGV_AND_RETURN(-1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (kParams.file_name == NULL) { | ||||
|     printf("missing input file!!\n"); | ||||
|     Help(); | ||||
|     FREE_WARGV_AND_RETURN(0); | ||||
|   } | ||||
|  | ||||
|   if (!ImgIoUtilReadFile(kParams.file_name, | ||||
|                          &kParams.data.bytes, &kParams.data.size)) { | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   if (!WebPGetInfo(kParams.data.bytes, kParams.data.size, NULL, NULL)) { | ||||
|     fprintf(stderr, "Input file doesn't appear to be WebP format.\n"); | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   kParams.dmux = WebPDemux(&kParams.data); | ||||
|   if (kParams.dmux == NULL) { | ||||
|     fprintf(stderr, "Could not create demuxing object!\n"); | ||||
|     goto Error; | ||||
|   } | ||||
|  | ||||
|   kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH); | ||||
|   kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT); | ||||
|   if (kParams.print_info) { | ||||
|     printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); | ||||
|   } | ||||
|  | ||||
|   ClearPreviousFrame(); | ||||
|  | ||||
|   memset(&kParams.iccp, 0, sizeof(kParams.iccp)); | ||||
|   kParams.has_color_profile = | ||||
|       !!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG); | ||||
|   if (kParams.has_color_profile) { | ||||
| #ifdef WEBP_HAVE_QCMS | ||||
|     if (!WebPDemuxGetChunk(kParams.dmux, "ICCP", 1, &kParams.iccp)) goto Error; | ||||
|     printf("VP8X: Found color profile\n"); | ||||
| #else | ||||
|     fprintf(stderr, "Warning: color profile present, but qcms is unavailable!\n" | ||||
|             "Build libqcms from Mozilla or Chromium and define WEBP_HAVE_QCMS " | ||||
|             "before building.\n"); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error; | ||||
|  | ||||
|   kParams.has_animation = (curr->num_frames > 1); | ||||
|   kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT); | ||||
|   kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR); | ||||
|   printf("VP8X: Found %d images in file (loop count = %d)\n", | ||||
|          curr->num_frames, kParams.loop_count); | ||||
|  | ||||
|   // Decode first frame | ||||
|   if (!Decode()) goto Error; | ||||
|  | ||||
|   // Position iterator to last frame. Next call to HandleDisplay will wrap over. | ||||
|   // We take this into account by bumping up loop_count. | ||||
|   WebPDemuxGetFrame(kParams.dmux, 0, curr); | ||||
|   if (kParams.loop_count) ++kParams.loop_count; | ||||
|  | ||||
| #if defined(__unix__) || defined(__CYGWIN__) | ||||
|   // Work around GLUT compositor bug. | ||||
|   // https://bugs.launchpad.net/ubuntu/+source/freeglut/+bug/369891 | ||||
|   setenv("XLIB_SKIP_ARGB_VISUALS", "1", 1); | ||||
| #endif | ||||
|  | ||||
|   // Start display (and timer) | ||||
|   glutInit(&argc, argv); | ||||
| #ifdef FREEGLUT | ||||
|   glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); | ||||
| #endif | ||||
|   StartDisplay(); | ||||
|  | ||||
|   if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0); | ||||
|   glutMainLoop(); | ||||
|  | ||||
|   // Should only be reached when using FREEGLUT: | ||||
|   ClearParams(); | ||||
|   FREE_WARGV_AND_RETURN(0); | ||||
|  | ||||
|  Error: | ||||
|   ClearParams(); | ||||
|   FREE_WARGV_AND_RETURN(-1); | ||||
| } | ||||
|  | ||||
| #else   // !WEBP_HAVE_GL | ||||
|  | ||||
| int main(int argc, const char *argv[]) { | ||||
|   fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]); | ||||
|   (void)argc; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
							
								
								
									
										1182
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/webpinfo.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1182
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/webpinfo.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1165
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/webpmux.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1165
									
								
								libsdl2_image/external/libwebp-1.0.2/examples/webpmux.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user