Snap for 10453563 from ef5735f51b1fd2a66aa1ad555dd5a8cbb904a088 to mainline-mediaprovider-release
Change-Id: I8d13a24ef10767cb7805ee8151463fb546802148
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..fa5a76c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,6 @@
+.gitattributes export-ignore
+.gitignore export-ignore
+.mailmap export-ignore
+*.bat text eol=crlf
+*.pdf -text -diff
+*.ppm -text -diff
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6d6f03c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,56 @@
+*.l[ao]
+*.[ao]
+*.pc
+.DS_Store
+.deps
+.idea
+.libs
+.vscode
+/aclocal.m4
+/ar-lib
+/autom4te.cache
+/compile
+/config.*
+/configure
+/depcomp
+/dist
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/mkinstalldirs
+/stamp-h1
+Makefile
+Makefile.in
+examples/anim_diff
+examples/anim_dump
+examples/[cdv]webp
+examples/gif2webp
+examples/img2webp
+examples/webpinfo
+examples/webpmux
+src/webp/config.h*
+src/webp/stamp-h1
+/output
+/doc/output
+*.idb
+*.pdb
+/iosbuild
+/xcframeworkbuild
+/WebP*.*framework
+CMakeCache.txt
+CMakeFiles/
+cmake_install.cmake
+.gradle
+/build
+extras/get_disto
+extras/vwebp_sdl
+extras/webp_quality
+tests/fuzzer/advanced_api_fuzzer
+tests/fuzzer/animation_api_fuzzer
+tests/fuzzer/animdecoder_fuzzer
+tests/fuzzer/animencoder_fuzzer
+tests/fuzzer/demux_api_fuzzer
+tests/fuzzer/enc_dec_fuzzer
+tests/fuzzer/mux_demux_api_fuzzer
+tests/fuzzer/simple_api_fuzzer
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..ddcf1a7
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,18 @@
+Johann Koenig <johann.koenig@duck.com>
+Johann Koenig <johann.koenig@duck.com> <johannkoenig@google.com>
+Mikołaj Zalewski <mikolajz@google.com>
+Pascal Massimino <pascal.massimino@gmail.com>
+Pascal Massimino <pascal.massimino@gmail.com> <skal@google.com>
+Vikas Arora <vikasa@google.com>
+<vikasa@google.com> <vikasa@gmail.com>
+<vikasa@google.com> <vikaas.arora@gmail.com>
+<slobodan.prijic@imgtec.com> <Slobodan.Prijic@imgtec.com>
+<vrabaud@google.com> <vincent.rabaud@gmail.com>
+Vincent Rabaud <vrabaud@google.com>
+Tamar Levy <tamar.levy@intel.com>
+<qrczak@google.com> <qrczak>
+Hui Su <huisu@google.com>
+James Zern <jzern@google.com>
+Roberto Alanis <alanisbaez@google.com>
+Brian Ledger <brianpl@google.com>
+Maryla Ustarroz-Calonge <maryla@google.com>
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..4658b84
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,441 @@
+# This Pylint rcfile contains a best-effort configuration to uphold the
+# best-practices and style described in the Google Python style guide:
+# https://google.github.io/styleguide/pyguide.html
+#
+# Its canonical open-source location is:
+# https://google.github.io/styleguide/pylintrc
+
+[MASTER]
+
+# Files or directories to be skipped. They should be base names, not paths.
+ignore=third_party
+
+# Files or directories matching the regex patterns are skipped. The regex
+# matches against base names, not paths.
+ignore-patterns=
+
+# Pickle collected data for later comparisons.
+persistent=no
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Use multiple processes to speed up Pylint.
+jobs=4
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=abstract-method,
+ apply-builtin,
+ arguments-differ,
+ attribute-defined-outside-init,
+ backtick,
+ bad-option-value,
+ basestring-builtin,
+ buffer-builtin,
+ c-extension-no-member,
+ consider-using-enumerate,
+ cmp-builtin,
+ cmp-method,
+ coerce-builtin,
+ coerce-method,
+ delslice-method,
+ div-method,
+ duplicate-code,
+ eq-without-hash,
+ execfile-builtin,
+ file-builtin,
+ filter-builtin-not-iterating,
+ fixme,
+ getslice-method,
+ global-statement,
+ hex-method,
+ idiv-method,
+ implicit-str-concat-in-sequence,
+ import-error,
+ import-self,
+ import-star-module-level,
+ inconsistent-return-statements,
+ input-builtin,
+ intern-builtin,
+ invalid-str-codec,
+ locally-disabled,
+ long-builtin,
+ long-suffix,
+ map-builtin-not-iterating,
+ misplaced-comparison-constant,
+ missing-function-docstring,
+ metaclass-assignment,
+ next-method-called,
+ next-method-defined,
+ no-absolute-import,
+ no-else-break,
+ no-else-continue,
+ no-else-raise,
+ no-else-return,
+ no-init, # added
+ no-member,
+ no-name-in-module,
+ no-self-use,
+ nonzero-method,
+ oct-method,
+ old-division,
+ old-ne-operator,
+ old-octal-literal,
+ old-raise-syntax,
+ parameter-unpacking,
+ print-statement,
+ raising-string,
+ range-builtin-not-iterating,
+ raw_input-builtin,
+ rdiv-method,
+ reduce-builtin,
+ relative-import,
+ reload-builtin,
+ round-builtin,
+ setslice-method,
+ signature-differs,
+ standarderror-builtin,
+ suppressed-message,
+ sys-max-int,
+ too-few-public-methods,
+ too-many-ancestors,
+ too-many-arguments,
+ too-many-boolean-expressions,
+ too-many-branches,
+ too-many-instance-attributes,
+ too-many-locals,
+ too-many-nested-blocks,
+ too-many-public-methods,
+ too-many-return-statements,
+ too-many-statements,
+ trailing-newlines,
+ unichr-builtin,
+ unicode-builtin,
+ unnecessary-pass,
+ unpacking-in-except,
+ useless-else-on-loop,
+ useless-object-inheritance,
+ useless-suppression,
+ using-cmp-argument,
+ wrong-import-order,
+ xrange-builtin,
+ zip-builtin-not-iterating,
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]". This option is deprecated
+# and it will be removed in Pylint 2.0.
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[BASIC]
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=main,_,PRESUBMIT
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
+
+# Regular expression matching correct function names
+function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
+
+# Regular expression matching correct variable names
+variable-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct constant names
+const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+
+# Regular expression matching correct attribute names
+attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
+
+# Regular expression matching correct argument names
+argument-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct class names
+class-rgx=^_?[A-Z][a-zA-Z0-9]*$
+
+# Regular expression matching correct module names
+module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
+
+# Regular expression matching correct method names
+method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=10
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
+# lines made too long by directives to pytype.
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=(?x)(
+ ^\s*(\#\ )?<?https?://\S+>?$|
+ ^\s*(from\s+\S+\s+)?import\s+.+$)
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=yes
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=
+
+# Maximum number of lines in a module
+max-module-lines=99999
+
+# String used as indentation unit. The internal Google style guide mandates 2
+# spaces. Google's externaly-published style guide says 4, consistent with
+# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
+# projects (like TensorFlow).
+indent-string=' '
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=TODO
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=yes
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging,absl.logging,tensorflow.io.logging
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[SPELLING]
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,
+ TERMIOS,
+ Bastion,
+ rexec,
+ sets
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant, absl
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls,
+ class_
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=StandardError,
+ Exception,
+ BaseException
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 0000000..0be981a
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = yapf
\ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..2f0c537
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,58 @@
+Contributors:
+- Aidan O'Loan (aidanol at gmail dot com)
+- Alan Browning (browning at google dot com)
+- Alexandru Ardelean (ardeleanalex at gmail dot com)
+- Brian Ledger (brianpl at google dot com)
+- Charles Munger (clm at google dot com)
+- Cheng Yi (cyi at google dot com)
+- Christian Duvivier (cduvivier at google dot com)
+- Christopher Degawa (ccom at randomderp dot com)
+- Clement Courbet (courbet at google dot com)
+- Djordje Pesut (djordje dot pesut at imgtec dot com)
+- Frank Barchard (fbarchard at google dot com)
+- Hui Su (huisu at google dot com)
+- H. Vetinari (h dot vetinari at gmx dot com)
+- Ilya Kurdyukov (jpegqs at gmail dot com)
+- Ingvar Stepanyan (rreverser at google dot com)
+- James Zern (jzern at google dot com)
+- Jan Engelhardt (jengelh at medozas dot de)
+- Jehan (jehan at girinstud dot io)
+- Jeremy Maitin-Shepard (jbms at google dot com)
+- Johann Koenig (johann dot koenig at duck dot com)
+- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
+- Jyrki Alakuijala (jyrki at google dot com)
+- Konstantin Ivlev (tomskside at gmail dot com)
+- Lode Vandevenne (lode at google dot com)
+- Lou Quillio (louquillio at google dot com)
+- Mans Rullgard (mans at mansr dot com)
+- Marcin Kowalczyk (qrczak at google dot com)
+- Martin Olsson (mnemo at minimum dot se)
+- Maryla Ustarroz-Calonge (maryla at google dot com)
+- Mikołaj Zalewski (mikolajz at google dot com)
+- Mislav Bradac (mislavm at google dot com)
+- Nico Weber (thakis at chromium dot org)
+- Noel Chromium (noel at chromium dot org)
+- Oliver Wolff (oliver dot wolff at qt dot io)
+- Owen Rodley (orodley at google dot com)
+- Parag Salasakar (img dot mips1 at gmail dot com)
+- Pascal Massimino (pascal dot massimino at gmail dot com)
+- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
+- Pierre Joye (pierre dot php at gmail dot com)
+- Roberto Alanis (alanisbaez at google dot com)
+- Sam Clegg (sbc at chromium dot org)
+- Scott Hancher (seh at google dot com)
+- Scott LaVarnway (slavarnway at google dot com)
+- Scott Talbot (s at chikachow dot org)
+- Slobodan Prijic (slobodan dot prijic at imgtec dot com)
+- Somnath Banerjee (somnath dot banerjee at gmail dot com)
+- Sriraman Tallam (tmsriram at google dot com)
+- Tamar Levy (tamar dot levy at intel dot com)
+- Timothy Gu (timothygu99 at gmail dot com)
+- Urvang Joshi (urvang at google dot com)
+- Vikas Arora (vikasa at google dot com)
+- Vincent Rabaud (vrabaud at google dot com)
+- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
+- Wan-Teh Chang (wtc at google dot com)
+- Yang Zhang (yang dot zhang at arm dot com)
+- Yannis Guyon (yguyon at google dot com)
+- Zhi An Ng (zhin at chromium dot org)
diff --git a/Android.bp b/Android.bp
index e81468f..ace6a9e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,7 +45,7 @@
cc_library_static {
name: "webp-headers",
host_supported: true,
- export_include_dirs: ["include"],
+ export_include_dirs: ["src"],
sdk_version: "9",
target: {
windows: {
@@ -60,6 +60,13 @@
name: "libwebp-encode",
host_supported: true,
srcs: [
+ "sharpyuv/sharpyuv.c",
+ "sharpyuv/sharpyuv_cpu.c",
+ "sharpyuv/sharpyuv_csp.c",
+ "sharpyuv/sharpyuv_dsp.c",
+ "sharpyuv/sharpyuv_gamma.c",
+ "sharpyuv/sharpyuv_neon.c",
+ "sharpyuv/sharpyuv_sse2.c",
"src/dsp/cost.c",
"src/dsp/cost_mips32.c",
"src/dsp/cost_mips_dsp_r2.c",
@@ -121,10 +128,10 @@
},
cflags: [
- "-O2",
"-DANDROID",
"-DWEBP_SWAP_16BIT_CSP",
"-DWEBP_USE_THREAD",
+ "-O2",
"-Wall",
"-Werror",
],
@@ -221,10 +228,10 @@
},
cflags: [
- "-O2",
"-DANDROID",
"-DWEBP_SWAP_16BIT_CSP",
"-DWEBP_USE_THREAD",
+ "-O2",
"-Wall",
"-Werror",
],
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..c7bcb0f
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,309 @@
+# Ignore this file during non-NDK builds.
+ifdef NDK_ROOT
+LOCAL_PATH := $(call my-dir)
+
+WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
+WEBP_CFLAGS += -fvisibility=hidden
+
+ifeq ($(APP_OPTIM),release)
+ WEBP_CFLAGS += -finline-functions -ffast-math \
+ -ffunction-sections -fdata-sections
+ ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),)
+ WEBP_CFLAGS += -frename-registers -s
+ endif
+endif
+
+# mips32 fails to build with clang from r14b
+# https://bugs.chromium.org/p/webp/issues/detail?id=343
+ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),clang)
+ ifeq ($(TARGET_ARCH),mips)
+ clang_version := $(shell $(TARGET_CC) --version)
+ ifneq ($(findstring clang version 3,$(clang_version)),)
+ WEBP_CFLAGS += -no-integrated-as
+ endif
+ endif
+endif
+
+ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),)
+ # Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal
+ # instructions to be generated for armv7a code. Instead target the neon code
+ # specifically.
+ NEON := c.neon
+ USE_CPUFEATURES := yes
+ WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H
+else
+ NEON := c
+endif
+
+sharpyuv_srcs := \
+ sharpyuv/sharpyuv.c \
+ sharpyuv/sharpyuv_cpu.c \
+ sharpyuv/sharpyuv_csp.c \
+ sharpyuv/sharpyuv_dsp.c \
+ sharpyuv/sharpyuv_gamma.c \
+ sharpyuv/sharpyuv_neon.$(NEON) \
+ sharpyuv/sharpyuv_sse2.c \
+
+dec_srcs := \
+ src/dec/alpha_dec.c \
+ src/dec/buffer_dec.c \
+ src/dec/frame_dec.c \
+ src/dec/idec_dec.c \
+ src/dec/io_dec.c \
+ src/dec/quant_dec.c \
+ src/dec/tree_dec.c \
+ src/dec/vp8_dec.c \
+ src/dec/vp8l_dec.c \
+ src/dec/webp_dec.c \
+
+demux_srcs := \
+ src/demux/anim_decode.c \
+ src/demux/demux.c \
+
+dsp_dec_srcs := \
+ src/dsp/alpha_processing.c \
+ src/dsp/alpha_processing_mips_dsp_r2.c \
+ src/dsp/alpha_processing_neon.$(NEON) \
+ src/dsp/alpha_processing_sse2.c \
+ src/dsp/alpha_processing_sse41.c \
+ src/dsp/cpu.c \
+ src/dsp/dec.c \
+ src/dsp/dec_clip_tables.c \
+ src/dsp/dec_mips32.c \
+ src/dsp/dec_mips_dsp_r2.c \
+ src/dsp/dec_msa.c \
+ src/dsp/dec_neon.$(NEON) \
+ src/dsp/dec_sse2.c \
+ src/dsp/dec_sse41.c \
+ src/dsp/filters.c \
+ src/dsp/filters_mips_dsp_r2.c \
+ src/dsp/filters_msa.c \
+ src/dsp/filters_neon.$(NEON) \
+ src/dsp/filters_sse2.c \
+ src/dsp/lossless.c \
+ src/dsp/lossless_mips_dsp_r2.c \
+ src/dsp/lossless_msa.c \
+ src/dsp/lossless_neon.$(NEON) \
+ src/dsp/lossless_sse2.c \
+ src/dsp/lossless_sse41.c \
+ src/dsp/rescaler.c \
+ src/dsp/rescaler_mips32.c \
+ src/dsp/rescaler_mips_dsp_r2.c \
+ src/dsp/rescaler_msa.c \
+ src/dsp/rescaler_neon.$(NEON) \
+ src/dsp/rescaler_sse2.c \
+ src/dsp/upsampling.c \
+ src/dsp/upsampling_mips_dsp_r2.c \
+ src/dsp/upsampling_msa.c \
+ src/dsp/upsampling_neon.$(NEON) \
+ src/dsp/upsampling_sse2.c \
+ src/dsp/upsampling_sse41.c \
+ src/dsp/yuv.c \
+ src/dsp/yuv_mips32.c \
+ src/dsp/yuv_mips_dsp_r2.c \
+ src/dsp/yuv_neon.$(NEON) \
+ src/dsp/yuv_sse2.c \
+ src/dsp/yuv_sse41.c \
+
+dsp_enc_srcs := \
+ src/dsp/cost.c \
+ src/dsp/cost_mips32.c \
+ src/dsp/cost_mips_dsp_r2.c \
+ src/dsp/cost_neon.$(NEON) \
+ src/dsp/cost_sse2.c \
+ src/dsp/enc.c \
+ src/dsp/enc_mips32.c \
+ src/dsp/enc_mips_dsp_r2.c \
+ src/dsp/enc_msa.c \
+ src/dsp/enc_neon.$(NEON) \
+ src/dsp/enc_sse2.c \
+ src/dsp/enc_sse41.c \
+ src/dsp/lossless_enc.c \
+ src/dsp/lossless_enc_mips32.c \
+ src/dsp/lossless_enc_mips_dsp_r2.c \
+ src/dsp/lossless_enc_msa.c \
+ src/dsp/lossless_enc_neon.$(NEON) \
+ src/dsp/lossless_enc_sse2.c \
+ src/dsp/lossless_enc_sse41.c \
+ src/dsp/ssim.c \
+ src/dsp/ssim_sse2.c \
+
+enc_srcs := \
+ src/enc/alpha_enc.c \
+ src/enc/analysis_enc.c \
+ src/enc/backward_references_cost_enc.c \
+ src/enc/backward_references_enc.c \
+ src/enc/config_enc.c \
+ src/enc/cost_enc.c \
+ src/enc/filter_enc.c \
+ src/enc/frame_enc.c \
+ src/enc/histogram_enc.c \
+ src/enc/iterator_enc.c \
+ src/enc/near_lossless_enc.c \
+ src/enc/picture_enc.c \
+ src/enc/picture_csp_enc.c \
+ src/enc/picture_psnr_enc.c \
+ src/enc/picture_rescale_enc.c \
+ src/enc/picture_tools_enc.c \
+ src/enc/predictor_enc.c \
+ src/enc/quant_enc.c \
+ src/enc/syntax_enc.c \
+ src/enc/token_enc.c \
+ src/enc/tree_enc.c \
+ src/enc/vp8l_enc.c \
+ src/enc/webp_enc.c \
+
+mux_srcs := \
+ src/mux/anim_encode.c \
+ src/mux/muxedit.c \
+ src/mux/muxinternal.c \
+ src/mux/muxread.c \
+
+utils_dec_srcs := \
+ src/utils/bit_reader_utils.c \
+ src/utils/color_cache_utils.c \
+ src/utils/filters_utils.c \
+ src/utils/huffman_utils.c \
+ src/utils/quant_levels_dec_utils.c \
+ src/utils/random_utils.c \
+ src/utils/rescaler_utils.c \
+ src/utils/thread_utils.c \
+ src/utils/utils.c \
+
+utils_enc_srcs := \
+ src/utils/bit_writer_utils.c \
+ src/utils/huffman_encode_utils.c \
+ src/utils/quant_levels_utils.c \
+
+################################################################################
+# libwebpdecoder
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(dec_srcs) \
+ $(dsp_dec_srcs) \
+ $(utils_dec_srcs) \
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
+
+# prefer arm over thumb mode for performance gains
+LOCAL_ARM_MODE := arm
+
+ifeq ($(USE_CPUFEATURES),yes)
+ LOCAL_STATIC_LIBRARIES := cpufeatures
+endif
+
+LOCAL_MODULE := webpdecoder_static
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/COPYING $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/PATENTS
+include $(BUILD_STATIC_LIBRARY)
+
+ifeq ($(ENABLE_SHARED),1)
+include $(CLEAR_VARS)
+
+LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
+
+LOCAL_MODULE := webpdecoder
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/COPYING $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/PATENTS
+include $(BUILD_SHARED_LIBRARY)
+endif # ENABLE_SHARED=1
+
+################################################################################
+# libwebp
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(sharpyuv_srcs) \
+ $(dsp_enc_srcs) \
+ $(enc_srcs) \
+ $(utils_enc_srcs) \
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)
+
+# prefer arm over thumb mode for performance gains
+LOCAL_ARM_MODE := arm
+
+LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
+
+LOCAL_MODULE := webp
+
+ifeq ($(ENABLE_SHARED),1)
+ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
+ LOCAL_LICENSE_CONDITIONS := notice
+ LOCAL_NOTICE_FILE := $(LOCAL_PATH)/COPYING $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/PATENTS
+ include $(BUILD_SHARED_LIBRARY)
+else
+ include $(BUILD_STATIC_LIBRARY)
+endif
+
+################################################################################
+# libwebpdemux
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(demux_srcs)
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
+
+# prefer arm over thumb mode for performance gains
+LOCAL_ARM_MODE := arm
+
+LOCAL_MODULE := webpdemux
+
+ifeq ($(ENABLE_SHARED),1)
+ LOCAL_SHARED_LIBRARIES := webp
+ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
+ LOCAL_LICENSE_CONDITIONS := notice
+ LOCAL_NOTICE_FILE := $(LOCAL_PATH)/COPYING $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/PATENTS
+ include $(BUILD_SHARED_LIBRARY)
+else
+ LOCAL_STATIC_LIBRARIES := webp
+ include $(BUILD_STATIC_LIBRARY)
+endif
+
+################################################################################
+# libwebpmux
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(mux_srcs)
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
+
+# prefer arm over thumb mode for performance gains
+LOCAL_ARM_MODE := arm
+
+LOCAL_MODULE := webpmux
+
+ifeq ($(ENABLE_SHARED),1)
+ LOCAL_SHARED_LIBRARIES := webp
+ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
+ LOCAL_LICENSE_CONDITIONS := notice
+ LOCAL_NOTICE_FILE := $(LOCAL_PATH)/COPYING $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/PATENTS
+ include $(BUILD_SHARED_LIBRARY)
+else
+ LOCAL_STATIC_LIBRARIES := webp
+ include $(BUILD_STATIC_LIBRARY)
+endif
+
+################################################################################
+
+WEBP_SRC_PATH := $(LOCAL_PATH)
+include $(WEBP_SRC_PATH)/imageio/Android.mk
+include $(WEBP_SRC_PATH)/examples/Android.mk
+
+ifeq ($(USE_CPUFEATURES),yes)
+ $(call import-module,android/cpufeatures)
+endif
+endif # NDK_ROOT
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..f378db5
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,779 @@
+# Copyright (c) 2020 Google LLC.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE 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.
+
+if(APPLE)
+ cmake_minimum_required(VERSION 3.17)
+else()
+ cmake_minimum_required(VERSION 3.7)
+endif()
+
+if(POLICY CMP0072)
+ cmake_policy(SET CMP0072 NEW)
+endif()
+
+project(WebP C)
+
+# Options for coder / decoder executables.
+if(BUILD_SHARED_LIBS)
+ set(WEBP_LINK_STATIC_DEFAULT OFF)
+else()
+ set(WEBP_LINK_STATIC_DEFAULT ON)
+endif()
+option(WEBP_LINK_STATIC
+ "Link using static libraries. If OFF, use dynamic libraries."
+ ${WEBP_LINK_STATIC_DEFAULT})
+if(NOT EMSCRIPTEN)
+ # Disable SIMD on Emscripten by default, as it's a new unstable Wasm feature.
+ # Users can still explicitly opt-in to make a SIMD-enabled build.
+ set(WEBP_ENABLE_SIMD_DEFAULT ON)
+endif()
+option(WEBP_ENABLE_SIMD "Enable any SIMD optimization."
+ ${WEBP_ENABLE_SIMD_DEFAULT})
+option(WEBP_BUILD_ANIM_UTILS "Build animation utilities." ON)
+option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." ON)
+option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." ON)
+option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
+option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON)
+option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON)
+option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON)
+option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON)
+option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
+option(WEBP_BUILD_EXTRAS "Build extras." ON)
+option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
+option(WEBP_USE_THREAD "Enable threading support" ON)
+option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
+option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
+ OFF)
+set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
+set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2)
+
+if(WEBP_LINK_STATIC)
+ if(WIN32)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ endif()
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+ # vwebp does not compile on Ubuntu with static libraries so disabling it for
+ # now.
+ set(WEBP_BUILD_VWEBP OFF)
+endif()
+
+# Option needed for handling Unicode file names on Windows.
+if(WIN32)
+ option(WEBP_UNICODE "Build Unicode executables." ON)
+endif()
+
+if(WEBP_BUILD_WEBP_JS)
+ set(WEBP_BUILD_ANIM_UTILS OFF)
+ set(WEBP_BUILD_CWEBP OFF)
+ set(WEBP_BUILD_DWEBP OFF)
+ set(WEBP_BUILD_GIF2WEBP OFF)
+ set(WEBP_BUILD_IMG2WEBP OFF)
+ set(WEBP_BUILD_VWEBP OFF)
+ set(WEBP_BUILD_WEBPINFO OFF)
+ set(WEBP_BUILD_WEBPMUX OFF)
+ set(WEBP_BUILD_EXTRAS OFF)
+ set(WEBP_USE_THREAD OFF)
+
+ if(WEBP_ENABLE_SIMD)
+ message("wasm2js does not support SIMD, disabling webp.js generation.")
+ endif()
+endif()
+
+set(SHARPYUV_DEP_LIBRARIES)
+set(SHARPYUV_DEP_INCLUDE_DIRS)
+set(WEBP_DEP_LIBRARIES)
+set(WEBP_DEP_INCLUDE_DIRS)
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release"
+ CACHE STRING "Build type: Release, Debug, MinSizeRel or RelWithDebInfo"
+ FORCE)
+endif()
+
+# Include dependencies.
+include(cmake/deps.cmake)
+include(GNUInstallDirs)
+
+if(BUILD_SHARED_LIBS AND NOT DEFINED CMAKE_INSTALL_RPATH)
+ # Set the rpath to match autoconf/libtool behavior. Note this must be set
+ # before target creation.
+ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+endif()
+
+# ##############################################################################
+# Options.
+if(WEBP_ENABLE_SWAP_16BIT_CSP)
+ add_definitions(-DWEBP_SWAP_16BIT_CSP=1)
+endif()
+
+if(NOT WEBP_BITTRACE STREQUAL "0")
+ add_definitions(-DBITTRACE=${WEBP_BITTRACE})
+endif()
+
+if(WEBP_UNICODE)
+ # Windows recommends setting both UNICODE and _UNICODE.
+ add_definitions(-DUNICODE -D_UNICODE)
+endif()
+
+if(MSVC AND BUILD_SHARED_LIBS)
+ add_definitions(-DWEBP_DLL)
+endif()
+
+# pkg-config variables used by *.pc.in.
+set(prefix ${CMAKE_INSTALL_PREFIX})
+set(exec_prefix "\${prefix}")
+if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
+ set(libdir "${CMAKE_INSTALL_LIBDIR}")
+else()
+ set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+endif()
+if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
+ set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
+else()
+ set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+endif()
+set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
+set(INSTALLED_LIBRARIES)
+
+if(MSVC)
+ # match the naming convention used by nmake
+ set(webp_libname_prefix "lib")
+ set(CMAKE_SHARED_LIBRARY_PREFIX "${webp_libname_prefix}")
+ set(CMAKE_IMPORT_LIBRARY_PREFIX "${webp_libname_prefix}")
+ set(CMAKE_STATIC_LIBRARY_PREFIX "${webp_libname_prefix}")
+endif()
+
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+
+# ##############################################################################
+# Android only.
+if(ANDROID)
+ include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
+ add_library(cpufeatures-webp STATIC
+ ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
+ list(APPEND INSTALLED_LIBRARIES cpufeatures-webp)
+ target_link_libraries(cpufeatures-webp dl)
+ set(SHARPYUV_DEP_LIBRARIES ${SHARPYUV_DEP_LIBRARIES} cpufeatures-webp)
+ set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures-webp)
+ set(cpufeatures_include_dir ${ANDROID_NDK}/sources/android/cpufeatures)
+ set(SHARPYUV_DEP_INCLUDE_DIRS ${SHARPYUV_DEP_INCLUDE_DIRS}
+ ${cpufeatures_include_dir})
+ set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${cpufeatures_include_dir})
+ add_definitions(-DHAVE_CPU_FEATURES_H=1)
+ set(HAVE_CPU_FEATURES_H 1)
+else()
+ set(HAVE_CPU_FEATURES_H 0)
+endif()
+
+function(configure_pkg_config FILE)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${FILE}" @ONLY)
+
+ if(HAVE_MATH_LIBRARY)
+ # MSVC doesn't have libm
+ file(READ ${CMAKE_CURRENT_BINARY_DIR}/${FILE} data)
+ string(REPLACE "-lm" "" data ${data})
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${FILE} ${data})
+ endif()
+
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endfunction()
+
+# ##############################################################################
+# WebP source files. Read the Makefile.am to get the source files.
+
+# We expect the Makefiles to define the sources as defined in the first regex.
+# E.g.: libimagedec_la_SOURCES = image_dec.c image_dec.h
+function(parse_Makefile_am FOLDER VAR SRC_REGEX)
+ file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
+ string(REGEX MATCHALL "${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*"
+ FILES_PER_LINE ${MAKEFILE_AM})
+ set(SRCS ${${VAR}})
+ foreach(FILES ${FILES_PER_LINE})
+ string(FIND ${FILES} "=" OFFSET)
+ math(EXPR OFFSET "${OFFSET} + 2")
+ string(SUBSTRING ${FILES} ${OFFSET} -1 FILES)
+ if(FILES)
+ string(REGEX MATCHALL "[0-9a-z\\._]+" FILES ${FILES})
+ foreach(FILE ${FILES})
+ list(APPEND SRCS ${FOLDER}/${FILE})
+ endforeach()
+ endif()
+ endforeach()
+ set(${VAR} ${SRCS} PARENT_SCOPE)
+endfunction()
+
+set(WEBP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
+parse_makefile_am(${WEBP_SRC_DIR}/dec "WEBP_DEC_SRCS" "")
+parse_makefile_am(${WEBP_SRC_DIR}/demux "WEBP_DEMUX_SRCS" "")
+parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_COMMON_SRCS" "COMMON")
+parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "ENC")
+parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "dsp_[^ ]*")
+parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_DEC_SRCS" "decode_[^ ]*")
+parse_makefile_am(${WEBP_SRC_DIR}/enc "WEBP_ENC_SRCS" "")
+parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_COMMON_SRCS" "COMMON")
+parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_ENC_SRCS" "ENC")
+parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_DEC_SRCS" "decode_[^ ]*")
+
+# Remove the files specific to SIMD we don't use.
+foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
+ list(REMOVE_ITEM WEBP_DSP_ENC_SRCS ${FILE})
+ list(REMOVE_ITEM WEBP_DSP_DEC_SRCS ${FILE})
+endforeach()
+
+# Generate the config.h file.
+configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h @ONLY)
+add_definitions(-DHAVE_CONFIG_H)
+
+# Set the version numbers.
+macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
+ file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} SOURCE_FILE)
+ string(REGEX MATCH
+ "${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+" TMP
+ ${SOURCE_FILE})
+ string(REGEX MATCH "[0-9:]+" TMP ${TMP})
+ string(REGEX REPLACE ":" " " LT_VERSION ${TMP})
+
+ # See the libtool docs for more information:
+ # https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+ #
+ # c=<current>, a=<age>, r=<revision>
+ #
+ # libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
+ # passed to libtool.
+ #
+ # We set FULL = [c-a].a.r and MAJOR = [c-a].
+ separate_arguments(LT_VERSION)
+ list(GET LT_VERSION 0 LT_CURRENT)
+ list(GET LT_VERSION 1 LT_REVISION)
+ list(GET LT_VERSION 2 LT_AGE)
+ math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}")
+
+ set_target_properties(
+ ${TARGET_NAME}
+ PROPERTIES VERSION ${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
+ SOVERSION ${LT_CURRENT_MINUS_AGE})
+ if(APPLE)
+ # For compatibility, set MACHO_COMPATIBILITY_VERSION and
+ # MACHO_CURRENT_VERSION to match libtool. These properties were introduced
+ # in 3.17:
+ # https://cmake.org/cmake/help/latest/prop_tgt/MACHO_COMPATIBILITY_VERSION.html
+ math(EXPR LIBWEBP_MACHO_COMPATIBILITY_VERSION "${LT_CURRENT} + 1")
+ set_target_properties(
+ ${TARGET_NAME}
+ PROPERTIES MACHO_COMPATIBILITY_VERSION
+ ${LIBWEBP_MACHO_COMPATIBILITY_VERSION}
+ MACHO_CURRENT_VERSION
+ ${LIBWEBP_MACHO_COMPATIBILITY_VERSION}.${LT_REVISION})
+ endif()
+endmacro()
+
+# ##############################################################################
+# Build the webpdecoder library.
+
+# Creates a source file with an unused stub function in $CMAKE_BINARY_DIR and
+# adds it to the specified target. Currently used only with Xcode.
+#
+# See also:
+# https://cmake.org/cmake/help/v3.18/command/add_library.html#object-libraries
+# "Some native build systems (such as Xcode) may not like targets that have only
+# object files, so consider adding at least one real source file to any target
+# that references $<TARGET_OBJECTS:objlib>."
+function(libwebp_add_stub_file TARGET)
+ set(stub_source_dir "${CMAKE_BINARY_DIR}")
+ set(stub_source_file "${stub_source_dir}/libwebp_${TARGET}_stub.c")
+ set(stub_source_code
+ "// Generated file. DO NOT EDIT!\n"
+ "// C source file created for target ${TARGET}.\n"
+ "void libwebp_${TARGET}_stub_function(void)\;\n"
+ "void libwebp_${TARGET}_stub_function(void) {}\n")
+ file(WRITE "${stub_source_file}" ${stub_source_code})
+
+ target_sources(${TARGET} PRIVATE ${stub_source_file})
+endfunction()
+
+parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS" "")
+add_library(sharpyuv ${WEBP_SHARPYUV_SRCS})
+target_link_libraries(sharpyuv ${SHARPYUV_DEP_LIBRARIES})
+set_version(sharpyuv/Makefile.am sharpyuv sharpyuv)
+target_include_directories(
+ sharpyuv PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+set_target_properties(
+ sharpyuv
+ PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h")
+configure_pkg_config("sharpyuv/libsharpyuv.pc")
+install(
+ TARGETS sharpyuv
+ EXPORT ${PROJECT_NAME}Targets
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp/sharpyuv
+ INCLUDES
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ ${CMAKE_INSTALL_INCLUDEDIR}/webp
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+if(MSVC)
+ # avoid security warnings for e.g., fopen() used in the examples.
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+else()
+ add_compile_options(-Wall)
+endif()
+include_directories(${WEBP_DEP_INCLUDE_DIRS})
+add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
+target_include_directories(webpdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
+target_include_directories(webpdspdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+add_library(webputilsdecode OBJECT ${WEBP_UTILS_COMMON_SRCS}
+ ${WEBP_UTILS_DEC_SRCS})
+target_include_directories(webputilsdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+add_library(
+ webpdecoder $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdspdecode>
+ $<TARGET_OBJECTS:webputilsdecode>)
+if(XCODE)
+ libwebp_add_stub_file(webpdecoder)
+endif()
+target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
+target_include_directories(
+ webpdecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
+ INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
+set_target_properties(
+ webpdecoder
+ PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
+
+configure_pkg_config("src/libwebpdecoder.pc")
+
+# Build the webp library.
+add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
+target_include_directories(
+ webpencode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+add_library(webpdsp OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS}
+ ${WEBP_DSP_ENC_SRCS})
+target_include_directories(webpdsp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+add_library(webputils OBJECT ${WEBP_UTILS_COMMON_SRCS} ${WEBP_UTILS_DEC_SRCS}
+ ${WEBP_UTILS_ENC_SRCS})
+target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
+ $<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
+target_link_libraries(webp sharpyuv)
+if(XCODE)
+ libwebp_add_stub_file(webp)
+endif()
+target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
+target_include_directories(
+ webp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ $<INSTALL_INTERFACE:include>)
+set_target_properties(
+ webp
+ PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
+
+# Make sure the OBJECT libraries are built with position independent code (it is
+# not ON by default).
+set_target_properties(webpdecode webpdspdecode webputilsdecode webpencode
+ webpdsp webputils PROPERTIES POSITION_INDEPENDENT_CODE ON)
+configure_pkg_config("src/libwebp.pc")
+
+# Build the webp demux library.
+add_library(webpdemux ${WEBP_DEMUX_SRCS})
+target_link_libraries(webpdemux webp)
+target_include_directories(
+ webpdemux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+ PUBLIC $<INSTALL_INTERFACE:include>)
+set_target_properties(
+ webpdemux
+ PROPERTIES
+ PUBLIC_HEADER
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
+
+configure_pkg_config("src/demux/libwebpdemux.pc")
+
+set_version(src/Makefile.am webp webp)
+set_version(src/Makefile.am webpdecoder webpdecoder)
+set_version(src/demux/Makefile.am webpdemux webpdemux)
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
+string(REGEX MATCH "AC_INIT\\([^\n]*\\[[0-9\\.]+\\]" TMP ${CONFIGURE_FILE})
+string(REGEX MATCH "[0-9\\.]+" PROJECT_VERSION ${TMP})
+
+# Define the libraries to install.
+list(APPEND INSTALLED_LIBRARIES webpdecoder webp webpdemux)
+
+# Deal with SIMD. Change the compile flags for SIMD files we use.
+list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH)
+math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE
+ "${WEBP_SIMD_FILES_TO_INCLUDE_LENGTH}-1")
+
+foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
+ list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE)
+ list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG)
+ set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS
+ ${SIMD_COMPILE_FLAG})
+endforeach()
+
+if(NOT WEBP_BUILD_LIBWEBPMUX)
+ set(WEBP_BUILD_GIF2WEBP OFF)
+ set(WEBP_BUILD_IMG2WEBP OFF)
+ set(WEBP_BUILD_WEBPMUX OFF)
+endif()
+
+if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
+ set(WEBP_BUILD_GIF2WEBP OFF)
+endif()
+
+if(WEBP_BUILD_ANIM_UTILS AND NOT GIF_FOUND)
+ set(WEBP_BUILD_ANIM_UTILS OFF)
+endif()
+
+# Build the executables if asked for.
+if(WEBP_BUILD_ANIM_UTILS
+ OR WEBP_BUILD_CWEBP
+ OR WEBP_BUILD_DWEBP
+ OR WEBP_BUILD_GIF2WEBP
+ OR WEBP_BUILD_IMG2WEBP
+ OR WEBP_BUILD_VWEBP
+ OR WEBP_BUILD_WEBPMUX
+ OR WEBP_BUILD_WEBPINFO)
+ # Example utility library.
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS"
+ "example_util_[^ ]*")
+ list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
+ add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS})
+ target_include_directories(
+ exampleutil PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
+
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS"
+ "imageio_util_[^ ]*")
+ add_library(imageioutil STATIC ${IMAGEIOUTILS_SRCS})
+ target_link_libraries(imageioutil webp)
+ target_link_libraries(exampleutil imageioutil)
+
+ # Image-decoding utility library.
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS"
+ "imagedec_[^ ]*")
+ add_library(imagedec STATIC ${IMAGEDEC_SRCS})
+ target_link_libraries(imagedec imageioutil webpdemux webp
+ ${WEBP_DEP_IMG_LIBRARIES})
+
+ # Image-encoding utility library.
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEENC_SRCS"
+ "imageenc_[^ ]*")
+ add_library(imageenc STATIC ${IMAGEENC_SRCS})
+ target_link_libraries(imageenc imageioutil webp)
+
+ set_property(
+ TARGET exampleutil imageioutil imagedec imageenc
+ PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_BINARY_DIR}/src)
+endif()
+
+if(WEBP_BUILD_DWEBP)
+ # dwebp
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "DWEBP_SRCS" "dwebp")
+ add_executable(dwebp ${DWEBP_SRCS})
+ target_link_libraries(dwebp exampleutil imagedec imageenc)
+ target_include_directories(dwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+ install(TARGETS dwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_CWEBP)
+ # cwebp
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" "cwebp")
+ add_executable(cwebp ${CWEBP_SRCS})
+ target_link_libraries(cwebp exampleutil imagedec webp)
+ target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR})
+ install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_LIBWEBPMUX)
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
+ add_library(libwebpmux ${WEBP_MUX_SRCS})
+ target_link_libraries(libwebpmux webp)
+ target_include_directories(libwebpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR})
+ set_version(src/mux/Makefile.am libwebpmux webpmux)
+ set_target_properties(
+ libwebpmux
+ PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
+${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
+ set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux)
+ list(APPEND INSTALLED_LIBRARIES libwebpmux)
+ configure_pkg_config("src/mux/libwebpmux.pc")
+endif()
+
+if(WEBP_BUILD_GIF2WEBP)
+ # gif2webp
+ include_directories(${WEBP_DEP_GIF_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "GIF2WEBP_SRCS"
+ "gif2webp")
+ add_executable(gif2webp ${GIF2WEBP_SRCS})
+ target_link_libraries(gif2webp exampleutil imageioutil webp libwebpmux
+ ${WEBP_DEP_GIF_LIBRARIES})
+ target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+ install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_IMG2WEBP)
+ # img2webp
+ include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "IMG2WEBP_SRCS"
+ "img2webp")
+ add_executable(img2webp ${IMG2WEBP_SRCS})
+ target_link_libraries(img2webp exampleutil imagedec imageioutil webp
+ libwebpmux)
+ target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+ install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_VWEBP)
+ # vwebp
+ find_package(GLUT)
+ if(GLUT_FOUND)
+ include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "VWEBP_SRCS" "vwebp")
+ add_executable(vwebp ${VWEBP_SRCS})
+ target_link_libraries(
+ vwebp
+ ${OPENGL_LIBRARIES}
+ exampleutil
+ GLUT::GLUT
+ imageioutil
+ webp
+ webpdemux)
+ target_include_directories(
+ vwebp PRIVATE ${GLUT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${OPENGL_INCLUDE_DIR})
+ install(TARGETS vwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+ check_c_compiler_flag("-Wno-deprecated-declarations" HAS_NO_DEPRECATED)
+ if(HAS_NO_DEPRECATED)
+ target_compile_options(vwebp PRIVATE "-Wno-deprecated-declarations")
+ endif()
+ endif()
+ endif()
+endif()
+
+if(WEBP_BUILD_WEBPINFO)
+ # webpinfo
+ include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPINFO_SRCS"
+ "webpinfo")
+ add_executable(webpinfo ${WEBPINFO_SRCS})
+ target_link_libraries(webpinfo exampleutil imageioutil)
+ target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+ install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_WEBPMUX)
+ # webpmux
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS"
+ "webpmux")
+ add_executable(webpmux ${WEBPMUX_SRCS})
+ target_link_libraries(webpmux exampleutil imageioutil libwebpmux webp)
+ target_include_directories(webpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+ install(TARGETS webpmux RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
+
+if(WEBP_BUILD_EXTRAS)
+ set(EXTRAS_MAKEFILE "${CMAKE_CURRENT_SOURCE_DIR}/extras")
+ parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_EXTRAS_SRCS" "libwebpextras_la")
+ parse_makefile_am(${EXTRAS_MAKEFILE} "GET_DISTO_SRCS" "get_disto")
+ parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality")
+ parse_makefile_am(${EXTRAS_MAKEFILE} "VWEBP_SDL_SRCS" "vwebp_sdl")
+
+ # libextras
+ add_library(extras STATIC ${WEBP_EXTRAS_SRCS})
+ target_include_directories(
+ extras PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+ # get_disto
+ add_executable(get_disto ${GET_DISTO_SRCS})
+ target_link_libraries(get_disto imagedec)
+ target_include_directories(get_disto PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/src)
+
+ # webp_quality
+ add_executable(webp_quality ${WEBP_QUALITY_SRCS})
+ target_link_libraries(webp_quality exampleutil imagedec extras)
+ target_include_directories(webp_quality PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR})
+
+ # vwebp_sdl
+ find_package(SDL)
+ if(WEBP_BUILD_VWEBP AND SDL_FOUND)
+ add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
+ target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
+ target_include_directories(
+ vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL_INCLUDE_DIR})
+ set(WEBP_HAVE_SDL 1)
+ target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
+ endif()
+endif()
+
+if(WEBP_BUILD_WEBP_JS)
+ # wasm2js does not support SIMD.
+ if(NOT WEBP_ENABLE_SIMD)
+ # JavaScript version
+ add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
+ target_link_libraries(webp_js webpdecoder SDL)
+ target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+ set(WEBP_HAVE_SDL 1)
+ set_target_properties(
+ webp_js
+ PROPERTIES LINK_FLAGS "-sWASM=0 \
+ -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
+ -sEXPORTED_RUNTIME_METHODS=cwrap")
+ set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
+ target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
+ endif()
+
+ # WASM version
+ add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
+ target_link_libraries(webp_wasm webpdecoder SDL)
+ target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+ set_target_properties(
+ webp_wasm
+ PROPERTIES LINK_FLAGS "-sWASM=1 \
+ -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
+ -sEXPORTED_RUNTIME_METHODS=cwrap")
+ target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
+
+ target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
+endif()
+
+if(WEBP_BUILD_ANIM_UTILS)
+ # anim_diff
+ include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DIFF_SRCS"
+ "anim_diff")
+ add_executable(anim_diff ${ANIM_DIFF_SRCS})
+ target_link_libraries(
+ anim_diff
+ exampleutil
+ imagedec
+ imageenc
+ imageioutil
+ webp
+ webpdemux
+ ${WEBP_DEP_GIF_LIBRARIES})
+ target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+
+ # anim_dump
+ include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
+ parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DUMP_SRCS"
+ "anim_dump")
+ add_executable(anim_dump ${ANIM_DUMP_SRCS})
+ target_link_libraries(
+ anim_dump
+ exampleutil
+ imagedec
+ imageenc
+ imageioutil
+ webp
+ webpdemux
+ ${WEBP_DEP_GIF_LIBRARIES})
+ target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+endif()
+
+# Install the different headers and libraries.
+install(
+ TARGETS ${INSTALLED_LIBRARIES}
+ EXPORT ${PROJECT_NAME}Targets
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp
+ INCLUDES
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+set(ConfigPackageLocation ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/)
+install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::
+ DESTINATION ${ConfigPackageLocation})
+
+# Create the CMake version file.
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
+ VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion)
+
+# Create the Config file.
+include(CMakePackageConfigHelpers)
+# Fix libwebpmux reference. The target name libwebpmux is used for compatibility
+# purposes, but the library mentioned in WebPConfig.cmake should be the
+# unprefixed version. Note string(...) can be replaced with list(TRANSFORM ...)
+# if cmake_minimum_required is >= 3.12.
+string(REGEX REPLACE "libwebpmux" "webpmux" INSTALLED_LIBRARIES
+ "${INSTALLED_LIBRARIES}")
+
+if(MSVC)
+ # For compatibility with nmake, MSVC builds use a custom prefix (lib) that
+ # needs to be included in the library name.
+ string(REGEX REPLACE "[A-Za-z0-9_]+" "${CMAKE_STATIC_LIBRARY_PREFIX}\\0"
+ INSTALLED_LIBRARIES "${INSTALLED_LIBRARIES}")
+endif()
+
+configure_package_config_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake
+ INSTALL_DESTINATION ${ConfigPackageLocation})
+
+# Install the generated CMake files.
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake"
+ DESTINATION ${ConfigPackageLocation})
+
+# Install the man pages.
+set(MAN_PAGES
+ cwebp.1
+ dwebp.1
+ gif2webp.1
+ img2webp.1
+ vwebp.1
+ webpmux.1
+ webpinfo.1)
+set(EXEC_BUILDS
+ "CWEBP"
+ "DWEBP"
+ "GIF2WEBP"
+ "IMG2WEBP"
+ "VWEBP"
+ "WEBPMUX"
+ "WEBPINFO")
+list(LENGTH MAN_PAGES MAN_PAGES_LENGTH)
+math(EXPR MAN_PAGES_RANGE "${MAN_PAGES_LENGTH} - 1")
+
+foreach(I_MAN RANGE ${MAN_PAGES_RANGE})
+ list(GET EXEC_BUILDS ${I_MAN} EXEC_BUILD)
+ if(WEBP_BUILD_${EXEC_BUILD})
+ list(GET MAN_PAGES ${I_MAN} MAN_PAGE)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man/${MAN_PAGE}
+ DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc)
+ endif()
+endforeach()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..7a73a30
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,29 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use a [Gerrit](https://www.gerritcodereview.com) instance hosted at
+https://chromium-review.googlesource.com for this purpose. See the
+[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
+for additional details.
+
+## Community Guidelines
+
+This project follows
+[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..00ef617
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,4547 @@
+0ba77244 update NEWS
+e763eb1e bump version to 1.3.0
+2a8686fc update AUTHORS
+106a57c1 Merge "*/Android.mk: add a check for NDK_ROOT" into main
+c5e841c4 Merge "extras: WebpToSDL -> WebPToSDL" into main
+dbc30715 Merge "xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION" into main
+6fc1a9f9 */Android.mk: add a check for NDK_ROOT
+d3e151fc doc/api.md,webp_js/README.md: Webp -> WebP
+ed92a626 extras: WebpToSDL -> WebPToSDL
+6eb0189b xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION
+1d58575b CMake: align .pc variables with autoconf
+e5fe2cfc webp-lossless-bitstream-spec,cosmetics: reflow paragraphs
+0ceeeab9 webp-lossless-bitstream-spec: add amendment note
+607611cd Merge "webp-container-spec: normalize section title case" into main
+f853685e lossless: SUBTRACT_GREEN -> SUBTRACT_GREEN_TRANSFORM
+786497e4 webp-lossless-bitstream-spec: fix inv color txfm description
+c6ac672d webp-lossless-bitstream-spec: fix num_code_lengths check
+b5700efb webp-lossless-bitstream-spec,cosmetics: grammar/capitalization
+d8ed8c11 webp-container-spec: normalize section title case
+52ec0b8f Merge changes Ie975dbb5,Ifc8c93af,I6ca7c5d6,I2e8d66f5,I152477b8 into main
+5097ef62 webp-container-spec,cosmetics: grammar/capitalization
+e3ba2b1f webp-lossless-bitstream-spec,cosmetics: reflow abstract
+1e8e3ded webp-lossless-bitstream-spec: reword abstract re alpha
+017cb6fa webp-container-spec,cosmetics: normalize range syntax
+f6a4684b webp-lossless-bitstream-spec,cosmetics: normalize range syntax
+54ebd5a3 webp-lossless-bitstream-spec: limit dist map lut to 69 cols
+44741f9c webp-lossless-bitstream-spec: fix dist mapping example
+fad0ece7 pnmdec.c: use snprintf instead of sprintf
+3f73e8f7 sharpyuv: add SharpYuvGetVersion()
+ce2f2d66 SharpYuvConvert: fix a race on SharpYuvGetCPUInfo
+a458e308 sharpyuv_dsp.h: restore sharpyuv_cpu.h include
+9ba800a7 Merge changes Id72fbf3b,Ic59d23a2 into main
+979c0ebb sharpyuv: add SharpYuvGetCPUInfo
+8bab09a4 Merge "*.pc.in: rename lib_prefix to webp_libname_prefix" into main
+769387c5 cpu.c,cosmetics: fix a typo
+a02978c2 sharpyuv/Makefile.am+cmake: add missing -lm
+28aedcb9 *.pc.in: rename lib_prefix to webp_libname_prefix
+c42e6d5a configure.ac: export an empty lib_prefix variable
+dfc843aa Merge "*.pc.in: add lib prefix to lib names w/MSVC" into main
+2498209b *.pc.in: add lib prefix to lib names w/MSVC
+ac252b61 Merge "analysis_enc.c: fix a dead store warning" into main
+56944762 analysis_enc.c: fix a dead store warning
+d34f9b99 Merge "webp-lossless-bitstream-spec: convert BNF to ABNF" into main
+dc05b4db Merge changes I96bc063c,I45880467,If9e18e5a,I6ee938e4,I0a410b28, ... into main
+83270c7f webp-container-spec: add prose for rendering process
+73b19b64 webp-container-spec: note reserved fields MUST be ignored
+57101d3f webp-lossless-bitstream-spec: improve 'small' color table stmt
+dfd32e45 webp-container-spec: remove redundant sentence
+8a6185dd doc/webp-*: fix some punctuation, grammar
+72776530 webp-lossless-bitstream-spec: convert BNF to ABNF
+d992bb08 cmake: rename cpufeatures target to cpufeatures-webp
+3ed2b275 webp-container-spec: clarify background color note
+951c292d webp-container-spec: come too late -> out of order
+902dd787 webp-container-spec: prefer hex literals
+a8f6b5ee webp-container-spec: change SHOULD to MUST w/ANIM chunk
+1dc59435 webp-container-spec: add unknown fields MUST be ignored
+280a810f webp-container-spec: make padding byte=0 a MUST
+41f0bf68 webp-container-spec: update note on trailing data
+6bdd36db webp-container-spec: clarify Chunk Size is in bytes
+87e36c48 Merge "webp_js/README.md,cosmetics: reflow some lines" into main
+5b01f321 Merge "Update Windows makefile to build libsharpyuv library." into main
+19b1a71c webp_js/README.md,cosmetics: reflow some lines
+780db756 Update Windows makefile to build libsharpyuv library.
+e407d4b3 CMakeLists.txt: replace GLUT_glut_LIBRARY w/GLUT::GLUT
+abf73d62 Merge "WebPConfig.cmake.in: add find_dependency(Threads)" into main
+25807fb4 Merge "cmake: restore compatibility with cmake < 3.12" into main
+5dbc4bfa WebPConfig.cmake.in: add find_dependency(Threads)
+b2a175dd Merge "Update wasm instructions." into main
+cb90f76b Update wasm instructions.
+02d15258 cmake: restore compatibility with cmake < 3.12
+5ba046e2 CMake: add_definitions -> add_compile_options
+e68765af dsp,neon: use vaddv in a few more places
+e8f83de2 Set libsharpyuv include dir to 'webp' subdirectory.
+15a91ab1 cmake,cosmetics: apply cmake-format
+0dd49d1a CMakeLists.txt: set @ONLY in configure_file() calls
+62b1bfe8 Merge changes I2877e7bb,I777cad70,I15af7d1a,I686e6740,If10538a9, ... into main
+95c8fe5f Merge changes Iecea3603,I9dc228ab into main
+e7c805cf picture_csp_enc.c: remove SafeInitSharpYuv
+6af8845a sharpyuv: prefer webp/types.h
+639619ce cmake: fix dll exports
+782ed48c sharpyuv,SharpYuvInit: add mutex protection when available
+cad0d5ad sharyuv_{neon,sse2}.c: merge WEBP_USE_* sections
+ef70ee06 add a few missing <stddef.h> includes for NULL
+f0f9eda4 sharpyuv.h: remove <inttypes.h>
+9b902cba Merge "picture_csp_enc.c,CheckNonOpaque: rm unneeded local" into main
+9c1d457c cmake/cpu.cmake: remove unused variable
+9ac25bcb CMakeLists.txt,win32: match naming convention used by nmake
+76c353ba picture_csp_enc.c,CheckNonOpaque: rm unneeded local
+5000de54 Merge "cwebp: fix WebPPictureHasTransparency call" into main
+e1729309 Merge "WebPPictureHasTransparency: add missing pointer check" into main
+00ff988a vp8l_enc,AddSingleSubGreen: clear int sanitizer warnings
+e2fecc22 dsp/lossless_enc.c: clear int sanitizer warnings
+129cf9e9 dsp/lossless.c: clear int sanitizer warnings
+ad7d1753 dsp/lossless_enc.c: clear int sanitizer warnings
+5037220e VP8LSubtractGreenFromBlueAndRed_C: clear int sanitizer warnings
+2ee786c7 upsampling_sse2.c: clear int sanitizer warnings
+4cc157d4 ParseOptionalChunks: clear int sanitizer warning
+892cf033 BuildHuffmanTable: clear int sanitizer warning
+3a9a4d45 VP8GetSigned: clear int sanitizer warnings
+704a3d0a dsp/lossless.c: quiet int sanitizer warnings
+1a6c109c WebPPictureHasTransparency: add missing pointer check
+c626e7d5 cwebp: fix WebPPictureHasTransparency call
+866e349c Merge tag 'v1.2.4'
+c170df38 Merge "Create libsharpyuv.a in makefile.unix." into main
+9d7ff74a Create libsharpyuv.a in makefile.unix.
+0d1f1254 update ChangeLog (tag: v1.2.4, origin/1.2.4)
+fcbc2d78 Merge "doc/*.txt: restrict code to 69 columns" into main
+4ad0e189 Merge "webp-container-spec.txt: normalize fourcc spelling" into main
+980d2488 update NEWS
+9fde8127 bump version to 1.2.4
+7a0a9935 doc/*.txt: restrict code to 69 columns
+c040a615 webp-container-spec.txt: normalize fourcc spelling
+aff1c546 dsp,x86: normalize types w/_mm_cvtsi128_si32 calls
+ab540ae0 dsp,x86: normalize types w/_mm_cvtsi32_si128 calls
+8980362e dsp,x86: normalize types w/_mm_set* calls (2)
+e626925c lossless: fix crunch mode w/WEBP_REDUCE_SIZE
+83539239 dsp,x86: normalize types w/_mm_set* calls
+8a4576ce webp-container-spec.txt: replace & with &
+db870881 Merge "webp-container-spec.txt: make reserved 0 values a MUST" into main
+01d7d378 webp-lossless-bitstream-spec: number all sections
+337cf69f webp-lossless-bitstream-spec: mv Nomenclature after Intro
+79be856e Merge changes I7111d1f7,I872cd62c into main
+5b87983a webp-container-spec.txt: make reserved 0 values a MUST
+bd939123 Merge changes I7a25b1a6,I51b2c2a0,I87d0cbcf,I6ec60af6,I0a3fe9dc into main
+04764b56 libwebp.pc: add libsharpyuv to requires
+7deee810 libsharpyuv: add pkg-config file
+1a64a7e6 webp-container-spec.txt: clarify some SHOULDs
+bec2c88a webp-container-spec.txt: move ChunkHeader to terminology
+c9359332 webp-container-spec.txt: clarify 'VP8 '/'XMP ' fourccs
+70fe3063 webp-container-spec.txt: rightsize table entries
+ddbf3f3f webp-container-spec.txt: update 'key words' text
+c151e95b utils.h,WEBP_ALIGN: make bitmask unsigned
+748e92bb add WebPInt32ToMem
+3fe15b67 Merge "Build libsharpyuv as a full installable library." into main
+4f402f34 add WebPMemToInt32
+a3b68c19 Build libsharpyuv as a full installable library.
+b4994eaa CMake: set rpath for shared objects
+94cd7117 Merge "CMake: fix dylib versioning" into main
+e91451b6 Fix the lossless specs a bit more.
+231bdfb7 CMake: fix dylib versioning
+bfad7ab5 CMakeLists.txt: correct libwebpmux name in WebPConfig.cmake
+c2e3fd30 Revert "cmake: fix webpmux lib name for cmake linking"
+7366f7f3 Merge "lossless: fix crunch mode w/WEBP_REDUCE_SIZE" into main
+84163d9d lossless: fix crunch mode w/WEBP_REDUCE_SIZE
+d01c1eb3 webp-lossless-bitstream-spec,cosmetics: normalize capitalization
+8813ca8e Merge tag 'v1.2.3'
+3c4a0fbf update ChangeLog (tag: v1.2.3)
+56a480e8 dsp/cpu.h: add missing extern "C"
+62b45bdd update ChangeLog (tag: v1.2.3-rc1)
+8764ec7a Merge changes Idb037953,Id582e395 into 1.2.3
+bcb872c3 vwebp: fix file name display in windows unicode build
+67c44ac5 webpmux: fix -frame option in windows unicode build
+8278825a makefile.unix: add sharpyuv objects to clean target
+14a49e01 update NEWS
+34b1dc33 bump version to 1.2.3
+0b397fda update AUTHORS
+c16488ac update .mailmap
+5a2d929c Merge "unicode.h: set console mode before using wprintf" into main
+169f867f unicode.h: set console mode before using wprintf
+a94b855c Merge "libsharpyuv: add version defines" into main
+f83bdb52 libsharpyuv: add version defines
+bef0d797 unicode_gif.h: fix -Wdeclaration-after-statement
+404c1622 Rename Huffman coding to prefix coding in the bitstream spec
+8895f8a3 Merge "run_static_analysis.sh: fix scan-build archive path" into main
+92a673d2 Merge "Add -fvisibility=hidden flag in CMakeLists." into main
+67c1d722 Merge "add WEBP_MSAN" into main
+1124ff66 Add -fvisibility=hidden flag in CMakeLists.
+e15b3560 add WEBP_MSAN
+ec9e782a sharpyuv: remove minimum image size from sharpyuv library
+7bd07f3b run_static_analysis.sh: fix scan-build archive path
+5ecee06f Merge "sharpyuv: increase precision of gamma<->linear conversion" into main
+f81dd7d6 Merge changes I3d17d529,I53026880,I1bd61639,I6bd4b25d,Icfec8fba into main
+2d607ee6 sharpyuv: increase precision of gamma<->linear conversion
+266cbbc5 sharpyuv: add 32bit version of SharpYuvFilterRow.
+9fc12274 CMake: add src to webpinfo includes
+7d18f40a CMake: add WEBP_BUILD_WEBPINFO to list of checks for exampleutil
+11309aa5 CMake: add WEBP_BUILD_WEBPMUX to list of checks for exampleutil
+4bc762f7 CMake: link imageioutil to exampleutil after defined
+0d1b9bc4 WEBP_DEP_LIBRARIES: use Threads::Threads
+20ef48f0 Merge "sharpyuv: add support for 10/12/16 bit rgb and 10/12 bit yuv." into main
+93c54371 sharpyuv: add support for 10/12/16 bit rgb and 10/12 bit yuv.
+53cf2b49 normalize WebPValidatePicture declaration w/definition
+d3006f4b sharpyuv: slightly improve precision
+ea967098 Merge changes Ia01bd397,Ibf3771af into main
+11bc8410 Merge changes I2d317c4b,I9e77f6db into main
+30453ea4 Add an internal WebPValidatePicture.
+6c43219a Some renamings for consistency.
+4f59fa73 update .mailmap
+e74f8a62 webp-lossless-bitstream-spec,cosmetics: normalize range syntax
+5a709ec0 webp-lossless-bitstream-spec,cosmetics: fix code typo
+a2093acc webp-lossless-bitstream-spec: add amendment note
+86c66930 webp-lossless-bitstream-spec: fix BNF
+232f22da webp-lossless-bitstream-spec: fix 'simple code' snippet
+44dd765d webp-lossless-bitstream-spec: fix ColorTransform impl
+7a7e33e9 webp-lossless-bitstream-spec: fix TR-pixel right border note
+86f94ee0 Update lossless spec with Huffman codes.
+a3927cc8 sharpyuv.c,cosmetics: fix indent
+6c45cef7 Make sure the stride has a minimum value in the importer.
+0c8b0e67 sharpyuv: cleanup/cosmetic changes
+dc3841e0 {histogram,predictor}_enc: quiet int -> float warnings
+a19a25bb Replace doubles by floats in lossless misc cost estimations.
+42888f6c Add an option to enable static builds.
+7efcf3cc Merge "Fix typo in color constants: Marix -> Matrix" into main
+8f4b5c62 Fix typo in color constants: Marix -> Matrix
+90084d84 Merge "demux,IsValidExtendedFormat: remove unused variable" into main
+ed643f61 Merge changes I452d2485,Ic6d75475 into main
+8fa053d1 Rename SharpYUV to SharpYuv for consistency.
+99a87562 SharpYuvComputeConversionMatrix: quiet int->float warnings
+deb426be Makefile.vc: add sharpyuv_csp.obj to SHARPYUV_OBJS
+779597d4 demux,IsValidExtendedFormat: remove unused variable
+40e8aa57 Merge "libsharpyuv: add colorspace utilities" into main
+01a05de1 libsharpyuv: add colorspace utilities
+2de4b05a Merge changes Id9890a60,I376d81e6,I1c958838 into main
+b8bca81f Merge "configure.ac: use LT_INIT if available" into main
+e8e77b9c Merge changes I479bc487,I39864691,I5d486c2c,I186d13be into main
+7e7d5d50 Merge ".gitignore: add Android Studio & VS code dirs" into main
+10c50848 normalize label indent
+89f774e6 mux{edit,internal}: fix leaks on error
+2d3293ad ExUtilInitCommandLineArguments: fix leak on error
+ec34fd70 anim_util: fix leaks on error
+e4717287 gif2webp: fix segfault on OOM
+e3cfafaf GetBackwardReferences: fail on alloc error
+a828a59b BackwardReferencesHashChainDistanceOnly: fix segfault on OOM
+fe153fae VP8LEncodeStream: fix segfault on OOM
+919acc0e .gitignore: add Android Studio & VS code dirs
+efa0731b configure.ac: use LT_INIT if available
+0957fd69 tiffdec: add grayscale support
+e685feef Merge "Make libsharpyuv self-contained by removing dependency on cpu.c" into main
+841960b6 Make libsharpyuv self-contained by removing dependency on cpu.c
+617cf036 image_dec: add WebPGetEnabledInputFileFormats()
+7a68afaa Let SharpArgbToYuv caller pass in an RGB>YUV conversion matrix.
+34bb332c man/cwebp.1: add note about crop/resize order
+f0e9351c webp-lossless-bitstream-spec,cosmetics: fix some typos
+5ccbd6ed vp8l_dec.c,cosmetics: fix a few typos
+c3d0c2d7 fix ios build scripts after sharpyuv dep added
+d0d2292e Merge "Make libwebp depend on libsharpyuv." into main
+03d12190 alpha_processing_neon.c: fix 0x01... typo
+d55d447c Make libwebp depend on libsharpyuv.
+e4cbcdd2 Fix lossless encoding for MIPS.
+924e7ca6 alpha_processing_neon.c: fix Dispatch/ExtractAlpha_NEON
+0fa0ea54 Makefile.vc: use /MANIFEST:EMBED
+29cc95ce Basic version of libsharpyuv in libwebp, in C.
+a30f2190 examples/webpmux.c: fix a couple of typos
+66b3ce23 Fix bad overflow check in ReadTIFF()
+54e61a38 Markdownify libwebp docs and reorganize them.
+b4533deb CMakeLists.txt,cosmetics: break long line
+b9d2f9cd quant_enc.c: use WEBP_RESTRICT qualifier
+ec178f2c Add progress hook granularity in lossless
+26139c73 Rename MAX_COST to MAX_BIT_COST in histogram_enc.c
+13b82816 cmake: fix webpmux lib name for cmake linking
+88b6a396 webp-container-spec.txt,cosmetics: normalize formatting
+6f496540 Merge tag 'v1.2.2'
+4074acf8 dsp.h: bump msvc arm64 version requirement to 16.6
+b0a86089 update ChangeLog (tag: v1.2.2)
+6db8248c libwebp: Fix VP8EncTokenLoop() progress
+827a307f BMP enc: fix the transparency case
+db25f1b4 libwebp: Fix VP8EncTokenLoop() progress
+286e7fce libwebp: do not destroy jpeg codec twice on error
+6e8a4126 libwebp: do not destroy jpeg codec twice on error
+faf21968 Merge "BMP enc: fix the transparency case" into main
+480cd51d BMP enc: fix the transparency case
+9195ea05 update ChangeLog (tag: v1.2.2-rc2)
+4acae017 update NEWS
+883f0633 man/img2webp.1: update date
+567e1f44 Reword img2webp synopsis command line
+1b0c15db man/img2webp.1: update date
+17bade38 Merge "Reword img2webp synopsis command line" into main
+a80954a1 Reword img2webp synopsis command line
+f084244d anim_decode: fix alpha blending with big-endian
+b217b4ff webpinfo: fix fourcc comparison w/big-endian
+ec497b75 Merge "anim_decode: fix alpha blending with big-endian" into main
+e4886716 anim_decode: fix alpha blending with big-endian
+e3cb052c webpinfo: fix fourcc comparison w/big-endian
+a510fedb patch-check: detect duplicated files
+f035d2e4 update ChangeLog (tag: v1.2.2-rc1)
+7031946a update NEWS
+973390b6 bump version to 1.2.2
+abd6664f update AUTHORS
+5b7e7930 Merge "add missing USE_{MSA,NEON} checks in headers" into main
+02ca04c3 add missing USE_{MSA,NEON} checks in headers
+e94716e2 xcframeworkbuild.sh: place headers in a subdir
+c846efd8 patch-check: commit subject length check
+b6f756e8 update http links
+8f5cb4c1 update rfc links
+8ea81561 change VP8LPredictorFunc signature to avoid reading 'left'
+6b1d18c3 webpmux: fix the -bgcolor description
+3368d876 Merge "webpmux: add "-set bgcolor A,R,G,B"" into main
+f213abf6 webpinfo: print the number of warnings
+50c97c30 webpmux: add "-set bgcolor A,R,G,B"
+2c206aaf Remove CMakeLists.txt check in compile.sh
+96e3dfef Merge "infra/common.sh: add shard_should_run()" into main
+0e0f74b7 infra/common.sh: add shard_should_run()
+35b7436a Jenkins scripts port: update shell function comments
+21d24b4c webp-container-spec.txt: remove 'experimental' markers
+cdcf8902 Merge "Port Jenkins script: compile" into main
+dc683cde Jenkins scripts port: static analysis
+0858494e Port Jenkins script: compile
+c2cf6a93 Jenkins scripts port: android compilation
+df0e808f presubmit: Add pylint-2.7 and .pylintrc
+676c57db patch-check: shfmt
+7bb7f747 patch-check: Add shellcheck
+abcd1797 Reformat docstrings and imports
+edaf0895 Port Jenkins scripts: compile js
+b9622063 Set CheckPatchFormatted flags to fail on diffs
+e23cd548 dsp.h: enable NEON w/VS2019+ ARM64 targets
+3875c7de CMakeLists.txt: set minimum version to 3.7
+1a8f0d45 Have a hard-coded value for memset in TrellisQuantizeBlock.
+93480160 Speed up TrellisQuantizeBlock
+45eaacc9 Convert deprecated uint32 to uint32_t.
+42592af8 webp,cmake: Remove unnecessary include dirs
+e298e05f Add patch-check steps in PRESUBMIT.py
+29148919 Merge tag 'v1.2.1'
+9ce5843d update ChangeLog (tag: v1.2.1)
+d9191588 fuzzer/*: normalize src/ includes
+c5bc3624 fuzzer/*: normalize src/ includes
+53b6f762 fix indent
+d2caaba4 fix indent
+731246ba update ChangeLog (tag: v1.2.1-rc2)
+d250f01d dsp/*: use WEBP_HAVE_* to determine Init availability
+1fe31625 dsp/*: use WEBP_HAVE_* to determine Init availability
+3a4d3ecd update NEWS
+b2bc8093 bump version to 1.2.1
+e542fc7a update AUTHORS
+e0241154 Merge "libwebp/CMake: Add <BUILD_INTERFACE> to webp incl" into main
+edea6444 libwebp/CMake: Add <BUILD_INTERFACE> to webp incl
+ece18e55 dsp.h: respect --disable-sse2/sse4.1/neon
+a89a3230 wicdec: support alpha from WebP WIC decoder
+26f4aa01 Merge "alpha_processing: fix visual studio warnings" into main
+8f594663 alpha_processing: fix visual studio warnings
+46d844e6 Merge "cpu.cmake: fix compiler flag detection w/3.17.0+" into main
+298d26ea Merge changes I593adf92,If20675e7,Ifac68eac into main
+a1e5dae0 alpha_processing*: use WEBP_RESTRICT qualifier
+327ef24f cpu.cmake: fix compiler flag detection w/3.17.0+
+f70819de configure: enable libwebpmux by default
+dc7e2b42 configure: add informational notices when disabling binaries
+9df23ddd configure: move lib flag checks before binaries
+a2e18f10 Merge "WebPConfig.config.in: correct WEBP_INCLUDE_DIRS" into main
+e1a8d4f3 Merge "bit_reader_inl_utils: uniformly apply WEBP_RESTRICT" into main
+4de35f43 rescaler.c: fix alignment
+0f13eec7 bit_reader_inl_utils: uniformly apply WEBP_RESTRICT
+277d3074 Fix size_t overflow in WebPRescalerInit
+97adbba5 WebPConfig.config.in: correct WEBP_INCLUDE_DIRS
+b60d4603 advanced_api_fuzzer: add extreme config value coverage
+72fe52f6 anim_encode.c,cosmetics: normalize indent
+116d235c anim_encode: Fix encoded_frames_[] overflow
+6f445b3e CMake: set CMP0072 to NEW
+b1cf887f define WEBP_RESTRICT for MSVC
+3e265136 Add WEBP_RESTRICT & use it in VP8BitReader
+f6d29247 vp8l_dec::ProcessRows: fix int overflow in multiply
+de3b4ba8 CMake: add WEBP_BUILD_LIBWEBPMUX
+7f09d3d1 CMakeLists.txt: rm libwebpmux dep from anim_{diff,dump}
+4edea4a6 Init{RGB,YUV}Rescaler: fix a few more int overflows
+c9e26bdb rescaler_utils: set max valid scaled w/h to INT_MAX/2
+28d488e6 utils.h: add SizeOverflow()
+695bdaa2 Export/EmitRescaledRowsRGBA: fix pointer offset int overflow
+685d073e Init{RGB,YUV}Rescaler: fix int overflows in multiplication
+d38bd0dd WebPFlipBuffer: fix integer overflow
+109ff0f1 utils: allow MALLOC_LIMIT to indicate a max
+a2fce867 WebPRescalerImportRowExpand_C: promote some vals before multiply
+776983d4 AllocateBuffer: fix int multiplication overflow check
+315abbd6 Merge "Revert "Do not use a palette for one color images.""
+eae815d0 Merge changes Ica3bbf75,I82f82954
+afbca5a1 Require Emscripten 2.0.18
+3320416b CMakeLists,emscripten: use EXPORTED_RUNTIME_METHODS
+29145ed6 Update README instructions for using Emscripten
+1f579139 cosmetics: remove use of 'sanity' / 'master'
+29b6129c WebPAnimEncoderNewInternal: remove some unnecessary inits
+b60869a1 Revert "Do not use a palette for one color images."
+6fb4cddc demux: move padded size calc post unpadded validation
+05b72d42 vp8l_enc.c: normalize index types
+b6513fba Do not use a palette for one color images.
+98bbe35b Fix multi-threading with palettes.
+b1674240 Add modified Zeng's method to palette sorting.
+88c90c45 add CONTRIBUTING.md
+6a9916d7 WebPRescalerInit: add missing int64_t promotion
+b6cf52d5 WebPIoInitFromOptions: treat use_scaling as a bool
+3b12b7f4 WebPIoInitFromOptions: treat use_cropping as a bool
+595fa13f add WebPCheckCropDimensions()
+8fdaecb0 Disable cross-color when palette is used.
+8933bac2 WebPIoInitFromOptions: respect incoming bypass_filtering val
+7d416ff0 webpdec,cosmetics: match error text to function call
+ec6cfeb5 Fix typo on WebPPictureAlloc() in README
+7e58a1a2 *.cmake: add license header
+5651a6b2 cmake: fix .so versioning
+25ae67b3 xcframeworkbuild.sh: add arm64 simulator target
+5d4ee4c3 cosmetics: remove use of the term 'dummy'
+01b38ee1 faster CollectColorXXXTransforms_SSE41
+652aa344 Merge "Use BitCtz for FastSLog2Slow_C"
+0320e1e3 add the missing default BitsCtz() code
+8886f620 Use BitCtz for FastSLog2Slow_C
+fae41617 faster CombinedShannonEntropy_SSE2
+5bd2704e Introduce the BitCtz() function.
+fee64287 Merge "wicdec,icc: treat unsupported op as non-fatal"
+33ddb894 lossless_sse{2,41}: remove some unneeded includes
+b27ea852 wicdec,icc: treat unsupported op as non-fatal
+b78494a9 Merge "Fix undefined signed shift."
+e79974cd Fix undefined signed shift.
+a8853394 SSE4.1 versions of BGRA to RGB/BGR color-space conversions
+a09a6472 SSE4.1 version of TransformColorInverse
+401da22b Merge "pngdec: check version before using png_get_chunk_malloc_max"
+26907822 pngdec: check version before using png_get_chunk_malloc_max
+06c1e72e Code cleanup
+8f0d41aa Merge changes Id135bbf4,I99e59797
+373eb170 gif2webp: don't store loop-count if there's only 1 frame
+759b9d5a cmake: add WEBP_USE_THREAD option
+926ce921 cmake: don't install binaries from extras/
+9c367bc6 WebPAnimDecoderNewInternal: validate bitstream before alloc
+47f64f6e filters_sse2: import Chromium change
+cc3577e9 fuzzer/*: use src/ based include paths
+004d77ff Merge tag 'v1.2.0'
+fedac6cc update ChangeLog (tag: v1.2.0-rc3, tag: v1.2.0)
+170a8712 Fix check_c_source_compiles with pthread.
+ceddb5fc Fix check_c_source_compiles with pthread.
+85995719 disable CombinedShannonEntropy_SSE2 on x86
+289757fe TiffDec: enforce stricter mem/dimension limit on tiles
+8af7436f Merge "{ios,xcframework}build.sh: make min version(s) more visible" into 1.2.0
+e56c3c5b pngdec: raise memory limit if needed
+8696147d pngdec: raise memory limit if needed
+13b8e9fe {ios,xcframework}build.sh: make min version(s) more visible
+a9225410 animdecoder_fuzzer: fix memory leak
+d6c2285d update gradle to 6.1.1
+8df77fb1 animdecoder_fuzzer: fix memory leak
+52ce6333 update NEWS
+28c49820 bump version to 1.2.0
+7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0
+826aafa5 update AUTHORS
+63258823 animdecoder_fuzzer: validate canvas size
+9eb26381 CMake: remove duplicate "include(GNUInstallDirs)"
+2e7bed79 WebPPicture: clarify the ownership of user-owned data.
+cccf5e33 webpmux: add an '-set loop <value>' option
+c9a3f6a1 Merge changes Ie29f9867,I289c54c4
+319f56f1 iosbuild.sh: sync some aspects of xcframeworkbuild.sh
+e8e8db98 add xcframeworkbuild.sh
+ae545534 dsp.h: allow config.h to override MSVC SIMD autodetection
+fef789f3 Merge "cmake: fix per-file assembly flags"
+fc14fc03 Have C encoding predictors use decoding predictors.
+7656f0b3 README,cosmetics: fix a couple typos
+d2e245ea cmake: disable webp.js if WEBP_ENABLE_SIMD=1
+96099a79 cmake: fix per-file assembly flags
+5abb5582 Merge "cmake: fix compilation w/Xcode generator"
+8484a120 cmake: fix compilation w/Xcode generator
+d7bf01c9 Merge changes Ifcae0f38,Iee2d7401
+36c81ff6 WASM-SIMD: port 2 patches from rreverser@'s tree
+988b02ab Merge "Couple of fixes to allow SIMD on Emscripten"
+26faf770 wicdec: fail with animated images
+ab2d08a8 [cd]webp: document lack of animated webp support
+52273943 Couple of fixes to allow SIMD on Emscripten
+8870ba7f Fix skia bug #10952
+4b3c6953 Detect if StoreFrame read more than anmf_payload_size bytes
+17fd4ba8 webp/decode.h,cosmetics: normalize 'flip' comment
+411d3677 remove some unreachable break statements
+3700ffd7 WebPPictureHasTransparency: remove unreachable return
+83604bf3 {animencoder,enc_dec}_fuzzer: convert some abort()s to returns
+eb44119c Merge changes I8ae09473,I678c8b1e
+9f6055fc fuzz_utils.h: rename max() to Max()
+695788e7 fuzz_utils.h: make functions WEBP_INLINE
+906c1fcd make ImgIoUtilReadFile use WebPMalloc instead of malloc
+8cb7e536 rename demux_api_fuzzer.c -> mux_demux_api_fuzzer.c
+443db47d add animdecoder_fuzzer.cc
+36a6eea3 Merge "import fuzzers from oss-fuzz/chromium"
+ec5f12c1 Makefile.vc: remove deprecated /Gm option
+64425a08 picture_tools_enc: fix windows build warning
+bd94090a import fuzzers from oss-fuzz/chromium
+cf847cba use WEBP_DSP_INIT_FUNC for Init{GammaTables*,GetCoeffs}
+55a080e5 Add WebPReplaceTransparentPixels() in dsp
+84739717 GetBackgroundColorGIF: promote to uint32_t before << 24
+def64e92 cwebp: Fix -print_psnr for near_lossless
+cf2f88b3 Add palette and spatial for q >= 75 and -m 5
+f0110bae Add no-color cache configuration to the cruncher
+749a8b99 Better estimate of the cache cost.
+4f9f00cc Use spatial predictors on top of palette no matter what.
+7658c686 Add spatial prediction on top of palette in cruncher.
+133ff0e3 webp_js: force WASM=0 option explicitly
+e3c259a2 Fix integer overflow in EmitFancyRGB.
+b3ff0bde man/{gif2,img2}webp,webpmux: normalize some wording
+f9b30586 fix ABI breakage introduced by 6a0ff358
+1d58dcfc README.webp_js: update note about emscripten version
+44070266 README.webp_js: s/fastcomp/upstream/
+2565fa8f README.webp_js: update cmake command
+47309ef5 webp: WEBP_OFFSET_PTR()
+687ab00e DC{4,8,16}_NEON: replace vmovl w/vaddl
+1b92fe75 DC16_NEON,aarch64: use vaddlv
+53f3d8cf dec_neon,DC8_NEON: use vaddlv instead of movl+vaddv
+27d08240 Fix integer overflow in WebPAnimDecoderGetNext()
+69776e38 Merge "remove call to MBAnalyzeBestIntra4Mode for method >= 5"
+a99078c1 remove call to MBAnalyzeBestIntra4Mode for method >= 5
+22e404cc CMakeLists.txt: fix set(CACHE) argument order
+71690b52 fix MSVC warning
+6a0ff358 Enc: add a qmin / qmax range for quality factor
+0fa56f30 Merge tag 'v1.1.0'
+6cf504d0 PNM decoding: handle max_value != 255
+d7844e97 update ChangeLog (tag: v1.1.0-rc2, tag: v1.1.0)
+7f006436 Makefile.vc: fix webp_quality.exe link
+cf047e83 Makefile.vc: fix webp_quality.exe link
+c074c653 update NEWS
+30f09551 bump version to 1.1.0
+a76694a1 update AUTHORS
+6e3ef7b3 extras: fix WEBP_SWAP_16BIT_CSP check
+47178dbd extras: add WebPUnmultiplyARGB() convenience function
+22cbae33 idec_dec: fix 0 offset of NULL pointer
+290dd0b4 muxread: fix 0 offset of NULL pointer
+0df474ac Merge "lossless_(enc_|)sse2: avoid offsetting a NULL pointer"
+c6b75a19 lossless_(enc_|)sse2: avoid offsetting a NULL pointer
+295e5e38 fix UBSAN warning
+e2575e05 DC8_NEON,aarch64: use vaddv
+b0e09e34 dec_neon: Fix build failure under some toolchains
+cf0e903c dsp/lossless: Fix non gcc ARM builds
+bb7bc40b Remove ubsan errors.
+78881b76 CMake: fix GLUT library link
+9f750f7a cmake: fix BUILD_SHARED_LIBS build on mac
+17850e74 libwebp: Remove char-subscripts warning in pnmdec.c
+2fa2552d Merge "Expose WebPMalloc() in addition to WebPFree()"
+a4df4aae Expose WebPMalloc() in addition to WebPFree()
+853ea3d8 imageio/tiff: Return error before allocating bad tile size
+af650c0b Fix a Wxor-used-as-pow false positive
+601ef17c libwebp.py: update to swig 3.0.12
+0e48d889 bugfix: last alpha rows were incorrectly decoded
+24d2ccb4 webp: Fix imageio ReadPNM() TUPLTYPE
+fab8f9cf cosmetics: normalize '*' association
+94138e0e update .gitignore
+0fe1a89d update ChangeLog (tag: v1.0.3-rc1, tag: v1.0.3)
+2ad0916d update NEWS
+1287362b bump version to 1.0.3
+7b968cc2 update AUTHORS
+9d6988f4 Fix the oscillating prediction problem at low quality
+312f74d0 makefile.unix: allow *_LIBS to be overridden w/EXTRA_LIBS
+92dbf237 filters_sse2,cosmetics: shorten some long lines
+a277d197 filters_sse2.c: quiet integer sanitizer warnings
+804540f1 Fix cpufeatures in CMake.
+bf00c15b Add CMake option for bittrace.
+a788b498 filters_sse2.c: quiet integer sanitizer warnings
+e6a92c5e filters.c: quiet integer sanitizer warnings
+ec1cc40a lossless.c: remove U32 -> S8 conversion warnings
+1106478f remove conversion U32 -> S8 warnings
+812a6b49 lossless_enc: fix some conversion warning
+4627c1c9 lossless_enc,TransformColorBlue: quiet uint32_t conv warning
+c84673a6 lossless_enc_sse{2,41}: quiet signed conv warnings
+776a7757 dec_sse2: quiet signed conv warnings
+bd39c063 Merge "thread_utils: release mutex before signaling"
+0550576f Merge "(alpha_processing,enc}_sse2: quiet signed conv warnings"
+6682f2c4 thread_utils: release mutex before signaling
+e78dea75 (alpha_processing,enc}_sse2: quiet signed conv warnings
+9acf18ba iosbuild.sh: add WebP{Demux,Mux}.framework
+b9be7e65 vwebp: remove the -fit option (and make it default)
+1394a2bb Merge "README.webp_js: update Emscripten.cmake note"
+dd3e7f8a README.webp_js: update Emscripten.cmake note
+32cf8801 predictor_enc,GetBestGreenRedToBlue: quiet implicit conv warnings
+e1c8acb5 Merge "vwebp: add a -fit option"
+cbd23dd5 vwebp: add a -fit option
+2e672351 bit_writer_utils,Flush: quiet implicit conversion warnings
+1326988d swig: update libwebp_python_wrap.c
+0e7f8548 update generated swig files
+17ed1438 Merge "PutLE{16,24}: quiet implicit conversion warnings"
+24686538 PutLE{16,24}: quiet implicit conversion warnings
+153bb3a0 fix some clang-7 warnings:
+ab2dc893 Rescaler: fix rounding error
+aa65f89a HistogramCombineStochastic: fix free of uninit value
+af0bac64 Merge "encode.h: mention 'exact' default in WebPEncodeLossless*"
+6d2e11ec encode.h: mention 'exact' default in WebPEncodeLossless*
+8c3f04fe AndroidCPUInfo: reorder terms in conditional
+fcfd9c71 BitTrace: if BITTRACE is > 0, record and print syntax bits used
+067031ea Speedups for unused Huffman groups.
+01ac46ba libwebp: Display "libjpeg error:" in imageio/jpegdec
+d9a662e1 WebPRescalerGetScaledDimensions: round scaled dimension up
+62eb3f08 libwebp: Fix missing '{' in README
+e05f785a Merge "unicode,INIT_WARGV: add missing cast"
+63c9a69f tag the VP8LHashPix() function for potential uint roll-over
+2b7214ab unicode,INIT_WARGV: add missing cast
+bf424b46 tag the GetPixPairHash64() function for potential uint roll-over
+7d05d6ca Have the color cache computation be u32-bit only.
+6bcf8769 Remove BINARYEN_METHOD in wasm settings.
+2b98df90 update ChangeLog (tag: v1.0.2-rc1, tag: v1.0.2)
+61e372b7 update NEWS
+7ae658a0 bump version to 1.0.2
+51c4907d update AUTHORS
+666bd6c6 man/cwebp.1: refine near-lossless text
+561cdce5 Clarify the doc about GetFeatures.
+aec2cf02 near_lossless: fix fuzzing-detected integer overflow
+928a75de webp: Fix VP8LBitWriterClone() bug
+5173d4ee neon IsFlat
+5b081219 IsFlat: inline when possible
+381b7b54 IsFlat: use int for thresh
+6ed15ea1 fix unprobable leak in webp_sdl.c
+22bbb24e Merge "IsFlat: return int"
+8b3fb238 Merge tag 'v1.0.1'
+f435de95 IsFlat: return int
+41521aed utils.h: only define WEBP_NEED_LOG_TABLE_8BIT when needed
+9f4d4a3f neon: GetResidualCost
+0fd7514b neon: SetResidualCoeffs
+f95a996c Simpler histogram clustering.
+e85d3313 update ChangeLog (tag: v1.0.1-rc2, tag: v1.0.1)
+fa8210e4 Fix pair update in stochastic entropy merging.
+fd198f73 add codereview.settings
+825389ac README.mux: add a reference to the AnimDecoder API
+3be698c3 CMake: fix webp_js compilation
+485ff86f Fix pair update in stochastic entropy merging.
+4cd0582d CMake: fix webp_js compilation
+4cbb4caf update NEWS
+f5a5918d bump version to 1.0.1
+d61385db Speed-up: Make sure we only initialize histograms when needed.
+6752904b Speed-up: Make sure we only initialize histograms when needed.
+0c570316 update AUTHORS
+301a2dda img2webp: add help note about arguments from a file
+f0abab92 Speedups for empty histograms.
+f2dfd925 Split HistogramAdd to only have the high level logic in C.
+06b7bc7d Fix compilation on windows and clang-cl+ninja.
+b6284d82 img2webp: add help note about arguments from a file
+decf6f6b Speedups for empty histograms.
+dea3e899 Split HistogramAdd to only have the high level logic in C.
+632798ae Merge "Fix compilation on windows and clang-cl+ninja."
+dc1a9518 Merge "libwebp: Unicode command tools on Windows"
+9cf9841b libwebp: Unicode command tools on Windows
+98179495 remove some minor TODOs
+a376e7b9 Fix compilation on windows and clang-cl+ninja.
+cbf82cc0 Remove AVX2 files.
+5030e902 Merge "TIFF decoder: remove unused KINV definition"
+ac543311 Remove a few more useless #defines
+123d3306 TIFF decoder: remove unused KINV definition
+ef1094b0 Merge "- install pkg-config files during the CMake build"
+b911fbc9 libwebp: Remove duplicate GIFDisplayError in anim_util
+eee00b66 - install pkg-config files during the CMake build
+ac3ec8c9 Merge "Clean-up the common sources in dsp."
+3e13da7b Clean-up the common sources in dsp.
+5c395f1d libwebp: cmake-format all
+e7a69729 libwebp: Add extras targets in CMakeLists.txt
+e52485d6 libwebp: Rename macros in webpmux.c
+92dc0f09 clean-up MakeInputImageCopy()
+39952de2 VP8IteratorImport: add missing 'const'
+382af7a2 clean-up WebPBlendAlpha
+14d020f6 libwebp: Use ExUtilGet*() in anim_diff
+0d92ff25 libwebp: remove useless variable in gif2webp
+556cb1b4 Merge "CMake: Set WEBP_BUILD_GIF2WEBP to off"
+da26ee49 CMake: Set WEBP_BUILD_GIF2WEBP to off
+b2a867c0 cwebp: Don't premultiply during -resize if -exact
+637141bc pngdec: fix build w/libpng < 1.4.x
+bc5092b1 pngdec: set memory functions
+50d8345a Fix CMake math library.
+6aa3e8aa Fix math library on Visual Studio.
+d71df4e2 Fix math library finding in CMake.
+de08d727 cosmetics: normalize include guard comment
+009562b4 vwebp: Fix bug when Dispose then NoBlend frames
+423f2579 Fix up CMake to create targets.
+907208f9 Wait for all threads to be done in DecodeRemaining.
+4649b3c4 vwebp: Add background color display option
+78ad57a3 Fix bad glClearColor parameters
+da96d8d9 Allow for a non-initialized alpha decompressor in DoRemap.
+2563db47 fix rescaling rounding inaccuracy
+211f37ee fix endian problems in pattern copy
+5f0f5c07 Make sure partition #0 is read before VP8 data in IDecode.
+de98732b fix GetColorf() bug
+4338cd36 misc fixes in libwebpmux
+e00af13e fix signatures after a9ceda7ff1
+a9ceda7f Speed-up chunk list operations.
+2281bbf6 Merge "Better handling of bogus Huffman codes."
+39cb9aad Better handling of bogus Huffman codes.
+89cc9d37 Merge "fix read-overflow while parsing VP8X chunk"
+95fd6507 fix read-overflow while parsing VP8X chunk
+9e729fe1 Fix VP8IoTeardownHook being called twice on worker sync failure
+29fb8562 Merge "muxread,anmf: fail on multiple image chunks"
+eb82ce76 muxread,anmf: fail on multiple image chunks
+1344a2e9 fix alpha-filtering crash when image width is larger than radius
+be738c6d muxread,ChunkVerifyAndAssign: validate chunk_size
+2c70ad76 muxread,CreateInternal: fix riff size checks
+569001f1 Fix for thread race heap-use-after-free
+c56a02d9 Android.mk: use LOCAL_EXPORT_C_INCLUDES w/public libs
+15795596 CMakeLists.txt,cosmetics: normalize if() formatting
+1a44c233 Merge "cmake: add support for webpmux"
+e9569ad7 Merge "configure,*am,cosmetics: s/WANT_/BUILD_/"
+35c7de6f cmake: add support for webpmux
+0f25e61c WebpToSDL(): fix the return value in case of error
+5d8985de configure,*am,cosmetics: s/WANT_/BUILD_/
+895fd28f Merge "man/Makefile.am: add img2webp.1"
+5cf3e2af man/Makefile.am: add img2webp.1
+2a9de5b9 Add build rules for anim_diff & anim_dump utils.
+71ed73cf fix invalid check for buffer size
+af0e4fbb gif2webp: fix transcode of loop count=65535
+dce5d764 Limit memory allocation when reading invalid Huffman codes.
+f9df0081 Merge "cmake: quiet glut deprecation warnings on OS X"
+dc39b16f webpmux.1: correct grammar
+c7aa1264 cwebp.c: fix a missing \n
+53aa51e9 Merge tag 'v1.0.0'
+698b8844 update ChangeLog (tag: v1.0.0)
+8d510751 webp-container-spec: correct frame duration=0 note
+e6b2164e vwebp: Copy Chrome's behavior w/frame duration == 0
+094b3b28 cmake: quiet glut deprecation warnings on OS X
+71c39a06 webp-container-spec: correct frame duration=0 note
+fd3d5756 vwebp: Copy Chrome's behavior w/frame duration == 0
+b0c966fb Build vwebp from CMake.
+d20b7707 update ChangeLog (tag: v1.0.0-rc3)
+0d5fad46 add WEBP_DSP_INIT / WEBP_DSP_INIT_FUNC
+d77bf512 add WEBP_DSP_INIT / WEBP_DSP_INIT_FUNC
+c1cb86af fix 16b overflow in SSE2
+e577feb7 makefile.unix: add DEBUG flag for compiling w/ debug-symbol
+99be34b3 cwebp,get_disto: fix bpp output
+e122e511 cwebp,get_disto: fix bpp output
+f5565ca8 cmake: Make sure we use near-lossless by default.
+d898dc14 fix bug in WebPImport565: alpha value was not set
+1c8f358d Fix CMake with WASM.
+a0215fb7 webp_js: fix webp_js demo html
+882784b0 update ChangeLog (tag: v1.0.0-rc2)
+2f930e08 Revert "Use proper targets for CMake."
+8165e8fb Use proper targets for CMake.
+3f157dd5 Remove some very hard TODOs.
+abb47760 Merge "Use proper targets for CMake."
+cd758a17 {de,}mux/Makefile.am: add missing headers
+e155dda0 Use proper targets for CMake.
+b892b8ba makefile.unix,dist: use ascii for text output
+64a57d05 add -version option to anim_dump,anim_diff and img2webp
+994be82d Merge "Remove some very hard TODOs."
+4033e1d7 Remove some very hard TODOs.
+fc1b8e3a webp_js: fix webp_js demo html
+15aa48d9 update ChangeLog (tag: v1.0.0-rc1)
+e607dabc update AUTHORS
+38410c08 [CFI] Remove function pointer casts
+978eec25 [CFI] Remove function pointer casts
+c57b2736 bump version to 1.0.0
+cba28853 update NEWS
+c909d531 Merge "remove some deprecation warning on MacOSX"
+217443c7 remove some deprecation warning on MacOSX
+b672bdfa configure: quiet glut deprecation warnings on OS X
+daa9fcaf configure: use sdl-config if available
+dd174cae Merge "imagedec: support metadata reading for WebP image decoding"
+641cedcc imagedec: support metadata reading for WebP image decoding
+065b2ce1 anim_diff: add a couple missing newlines in Help()
+c4cc1147 Merge "gif2webp: force low duration frames to 100ms"
+09333097 gif2webp: force low duration frames to 100ms
+e03f0ec3 sharp_yuv: use 14b fixed-point precision for gamma
+b2db361c image_enc,WebPWritePNG: move locals after setjmp
+74e82ec6 Merge "WebPPictureDistortion: fix big-endian results order"
+645d04ca Merge "cwebp,get_disto: report bpp"
+120f58c3 Merge "lossless*sse2: improve non-const 16-bit vector creation"
+a7fe9412 WebPPictureDistortion: fix big-endian results order
+e26fe066 cwebp,get_disto: report bpp
+9df64e28 Merge changes Id5b4a1a4,Ia20ce844
+8043504f lossless*sse2: improve non-const 16-bit vector creation
+1e3dfc48 Import: extract condition from loop
+3b07d327 Import,RGBA: fix for BigEndian import
+551948e4 Remove unused argument in VP8LBitsEntropy.
+3005237a ReadWebP: fix for big-endian
+499c395a Merge "anim_diff: expose the -max_diff option"
+f69dcd69 Merge "remove WEBP_EXPERIMENTAL_FEATURES"
+07d884d5 anim_diff: expose the -max_diff option
+f4dd9256 remove WEBP_EXPERIMENTAL_FEATURES
+94a8377b extract the command-line parsing helpers to example_util
+fc09e6e2 PNM decoder: prevent unsupported depth=2 PAM case.
+6de58603 MIPS64: Fix defined-but-not-used errors with WEBP_REDUCE_CSP
+cbde5728 gif2webp: add support for reading from stdin
+cf1c5054 Add an SSE4 version of some lossless color transforms.
+45a8b5eb Fix lint error with man page.
+cff38e8f Merge "PNG decoder: handle gAMA chunk"
+59cb1a48 Merge "enable dc error-diffusion always"
+78318b30 PNG decoder: handle gAMA chunk
+664c21dd Merge "remove some TODOs"
+815652de enable dc error-diffusion always
+aec45cec remove some TODOs
+5715dfce fix block-count[] increment in case of large image
+c2d04f3e enable DC error-diffusion always for multi-pass
+96bf07c5 use DC error diffusion for U/V at low-quality
+1c59020b fix missing sse41 targets in makefile.unix
+7a8e814b cosmetics: s/color_space/colorspace/
+05f6fe24 upsampling: rm asserts w/REDUCE_CSP+OMIT_C_CODE
+b4cf5597 Merge "Upsampling SSE2/SSE4 speedup."
+ccbeb32c Makefile.vc: add missing sse41 files
+55403a9a Upsampling SSE2/SSE4 speedup.
+807b53c4 Implement the upsampling/yuv functions in SSE41
+84101a81 Fix wasm WebP compilation
+8bebd2a3 fix warning on MSVC
+a7f93fe3 webpmux: allow reading argument from a file
+b69f18a7 gif2webp.1: fix -loop_compatibility layout
+72d530c0 Merge "fix lossless decoding w/WEBP_REDUCE_SIZE"
+296c7dc4 fix lossless decoding w/WEBP_REDUCE_SIZE
+0d5d029c Merge "ImgIoUtilReadFile: fix file leak upon error"
+ae568ce7 ImgIoUtilReadFile: fix file leak upon error
+796b5a8a Merge tag 'v0.6.1'
+6b7a95fd update ChangeLog (tag: v0.6.1)
+f66955de WEBP_REDUCE_CSP: restrict colorspace support
+1af0df76 Merge "WEBP_REDUCE_CSP: restrict colorspace support"
+6de20df0 WEBP_REDUCE_CSP: restrict colorspace support
+a289d8e7 update ChangeLog (tag: v0.6.1-rc2)
+c10a493c vwebp: disable double buffering on windows & mac
+0d4466c2 webp_to_sdl.c: fix file mode
+1b27bf8b WEBP_REDUCE_SIZE: disable all rescaler code
+126be109 webpinfo: add -version option
+0df22b9e WEBP_REDUCE_SIZE: disable all rescaler code
+9add62b5 bump version to 0.6.1
+d3e26144 update NEWS
+2edda639 README: add webpinfo section
+9ca568ef Merge "right-size some tables"
+31f1995c Merge "SSE2 implementation of HasAlphaXXX"
+a80c46bd SSE2 implementation of HasAlphaXXX
+083507f2 right-size some tables
+2e5785b2 anim_utils.c: remove warning when !defined(WEBP_HAVE_GIF)
+b299c47e add WEBP_REDUCE_SIZE
+f593d71a enc: disable pic->stats/extra_info w/WEBP_DISABLE_STATS
+541179a9 Merge "predictor_enc: fix build w/--disable-near-lossless"
+5755a7ec predictor_enc: fix build w/--disable-near-lossless
+eab5bab7 add WEBP_DISABLE_STATS
+8052c585 remove some petty TODOs from vwebp.
+c245343d move LOAD8x4 and STORE8x2 closer to their use location
+b9e734fd dec,cosmetics: normalize function naming style
+c188d546 dec: harmonize function suffixes
+28c5ac81 dec_sse41: harmonize function suffixes
+e65b72a3 Merge "introduce WebPHasAlpha8b and WebPHasAlpha32b"
+b94cee98 dec_sse2: remove HE8uv_SSE2
+44a0ee3f introduce WebPHasAlpha8b and WebPHasAlpha32b
+aebf59ac Merge "WebPPictureAllocARGB: align argb allocation"
+c184665e WebPPictureAllocARGB: align argb allocation
+3daf7509 WebPParseHeaders: remove obsolete animation TODO
+80285d97 cmake: avoid security warnings under msvc
+650eac55 cmake: don't set -Wall with MSVC
+c462cd00 Remove useless code.
+01a98217 Merge "remove WebPWorkerImpl declaration from the header"
+3c49fc47 Merge "thread_utils: fix potentially bad call to Execute"
+fde2782e thread_utils: fix potentially bad call to Execute
+2a270c1d remove WebPWorkerImpl declaration from the header
+f1f437cc remove mention of 'lossy-only parameters' from the doc
+3879074d Merge "WebPMemToUint32: remove ptr cast to int"
+04b029d2 WebPMemToUint32: remove ptr cast to int
+b7971d0e dsp: avoid defining _C functions w/NEON builds
+6ba98764 webpdec: correct alloc size check w/use_argb
+5cfb3b0f normalize include guards
+f433205e Merge changes Ia17c7dfc,I75423abb,Ia2f716b4,I161caa14,I4210081a, ...
+8d033b14 {dec,enc}_neon: harmonize function suffixes x2
+0295e981 upsampling_neon: harmonize function suffixes
+d572c4e5 yuv_neon: harmonize function suffixes
+ab9c2500 rescaler_neon: harmonize function suffixes
+93e0ce27 lossless_neon: harmonize function suffixes
+22fbc50e lossless_enc_neon: harmonize function suffixes
+447875b4 filters_neon,cosmetics: fix indent
+e51bdd43 remove unused VP8TokenToStats() function
+785da7ea enc_neon: harmonize function suffixes
+bc1a251f dec_neon: harmonize function suffixes
+61e535f1 dsp/lossless: workaround gcc-4.8 bug on arm
+68b2eab7 cwebp: fix alpha reporting w/lossless & metadata
+30042faa WebPDemuxGetI: add doc details around WebPFormatFeature
+0a17f471 Merge "WIP: list includes as descendants of the project dir"
+a4399721 WIP: list includes as descendants of the project dir
+08275708 Merge "Make sure we reach the full range for alpha blending."
+d361a6a7 yuv_sse2: harmonize function suffixes
+6921aa6f upsampling_sse2: harmonize function suffixes
+08c67d3e ssim_sse2: harmonize function suffixes
+582a1b57 rescaler_sse2: harmonize function suffixes
+2c1b18ba lossless_sse2: harmonize function suffixes
+0ac46e81 lossless_enc_sse2: harmonize function suffixes
+bc634d57 enc_sse2: harmonize function suffixes
+bcb7347c dec_sse2: harmonize function suffixes
+e14ad93c Make sure we reach the full range for alpha blending.
+7038ca8d demux,StoreFrame: restore hdr size check to min req
+fb3daad6 cpu: fix ssse3 check
+be590e06 Merge "Fix CMake redefinition for HAVE_CPU_FEATURES_H"
+35f736e1 Fix CMake redefinition for HAVE_CPU_FEATURES_H
+a5216efc Fix integer overflow warning.
+a9c8916b decode.h,WebPIDecGetRGB: clarify output ptr validity
+3c74c645 gif2webp: handle 1-frame case properly + fix anim_diff
+c7f295d3 Merge "gif2webp: introduce -loop_compatibility option"
+b4e04677 gif2webp: introduce -loop_compatibility option
+f78da3de add LOCAL_CLANG_PREREQ and avoid WORK_AROUND_GCC w/3.8+
+01c426f1 define WEBP_USE_INTRINSICS w/gcc-4.9+
+8635973d use sdl-config (if available) to determine the link flags
+e9459382 use CPPFLAGS before CFLAGS
+4a9d788e Merge "Android.mk,mips: fix clang build with r15"
+4fbdc9fb Android.mk,mips: fix clang build with r15
+a80fcc4a ifdef code not used by Chrome/Android.
+3993af12 Fix signed integer overflows.
+f66f94ef anim_dump: small tool to dump frames from animated WebP
+6eba857b Merge "rationalize the Makefile.am"
+c5e34fba function definition cleanup
+3822762a rationalize the Makefile.am
+501ef6e4 configure style fix: animdiff -> anim_diff
+f8bdc268 Merge "protect against NULL dump_folder[] value in ReadAnimatedImage()"
+23bfc652 protect against NULL dump_folder[] value in ReadAnimatedImage()
+8dc3d71b cosmetics,ReadAnimatedWebP: correct function comment
+5bd40066 Merge changes I66a64a0a,I4d2e520f
+7945575c cosmetics,webpinfo: remove an else after a return
+8729fa11 cosmetics,cwebp: remove an else after a return
+f324b7f9 cosmetics: normalize fn proto & decl param names
+869eb369 CMake cleanups.
+289e62a3 Remove declaration of unimplemented VP8ApplyNearLosslessPredict
+20a94186 pnmdec,PAM: validate depth before calculating bytes_per_px
+34130afe anim_encode: fix integer overflow
+42c79aa6 Merge "Encoder: harmonize function suffixes"
+b09307dc Encoder: harmonize function suffixes
+bed0456d Merge "SSIM: harmonize the function suffix"
+54f6a3cf lossless_sse2.c: fix some missed suffix changes
+088f1dcc SSIM: harmonize the function suffix
+86fc4dd9 webpdec: use ImgIoUtilCheckSizeArgumentsOverflow
+08ea9ecd imageio: add ability restrict max image size
+6f9daa4a jpegdec,ReadError: fix leaks on error
+a0f72a4f VP8LTransformColorFunc: drop an non-respected 'const' from the signature.
+8c934902 Merge "Lossess dec: harmonize the function suffixes"
+622242aa Lossess dec: harmonize the function suffixes
+1411f027 Lossless Enc: harmonize the function suffixes
+24ad2e3c add const to two variables
+46efe062 Merge "Allow the lossless cruncher to work for alpha."
+8c3f9a47 Speed-up LZ77.
+1aef4c71 Allow the lossless cruncher to work for alpha.
+b8821dbd Improve the box LZ77 speed.
+7beed280 add missing ()s to macro parameters
+6473d20b Merge "fix Android standalone toolchain build"
+dcefed95 Merge "build.gradle: fix arm64 build"
+0c83a8bc Merge "yuv: harmonize suffix naming"
+c6d1db4b fix Android standalone toolchain build
+663a6d9d unify the ALTERNATE_CODE flag usage
+73ea9f27 yuv: harmonize suffix naming
+c71b68ac build.gradle: fix arm64 build
+c4568b47 Rescaler: harmonize the suffix naming
+6cb13b05 Merge "alpha_processing: harmonize the naming suffixes to be _C()"
+83a3e69a Merge "simplify WEBP_EXTERN macro"
+7295fde2 Merge "filters: harmonize the suffixes naming to _SSE2(), _C(), etc."
+8e42ba4c simplify WEBP_EXTERN macro
+331ab34b cost*.c: harmonize the suffix namings
+b161f670 filters: harmonize the suffixes naming to _SSE2(), _C(), etc.
+dec5e4d3 alpha_processing: harmonize the naming suffixes to be _C()
+6878d427 fix memory leak in SDL_Init()
+461ae555 Merge "configure: fix warnings in sdl check"
+62486a22 configure: test for -Wundef
+92982609 dsp.h: fix -Wundef w/__mips_dsp_rev
+0265cede configure: fix warnings in sdl check
+88c73d8a backward_references_enc.h: fix WINDOW_SIZE_BITS check
+4ea49f6b rescaler_sse2.c: fix WEBP_RESCALER_FIX -> _RFIX typo
+1b526638 Clean-up some CMake
+87f57a4b Merge "cmake: fix gif lib detection when cross compiling"
+b34a9db1 cosmetics,dec_sse2: remove some redundant comments
+471c5755 cmake: fix gif lib detection when cross compiling
+c793417a cmake: disable gif2webp if gif lib isn't found
+dcbc1c88 cmake: split gif detection from IMG deps
+66ad84f0 Merge "muxread: remove unreachable code"
+50ec3ab7 muxread: remove unreachable code
+7d67a164 Lossy encoding: smoothen transparent areas to improve compression
+e50650c7 Merge "fix signature for DISABLE_TOKEN_BUFFER compilation"
+671d2567 fix signature for DISABLE_TOKEN_BUFFER compilation
+d6755580 cpu.cmake: use unique flag to test simd disable flags
+28914528 Merge "Remove the argb* files."
+8acb4942 Remove the argb* files.
+3b62347b README: correct cmake invocation note
+7ca0df13 Have the SSE2 version of PackARGB use common code.
+7b250459 Merge "Re-use the transformed image when trying several LZ77 in lossless."
+e132072f Re-use the transformed image when trying several LZ77 in lossless.
+5d7a50ef Get code to compile in C++.
+7b012987 configure: test for -Wparentheses-equality
+f0569adb Fix man pages for multi-threading.
+f1d5a397 multithread cruncher: only copy stats when picture->stats != NULL
+f8c2ac15 Multi-thread the lossless cruncher.
+a88c6522 Merge "Integrate a new LZ77 looking for matches in the neighborhood of a pixel only."
+8f6df1d0 Unroll Predictors 10, 11 and 12.
+355c3d1b Integrate a new LZ77 looking for matches in the neighborhood of a pixel only.
+a1779a01 Refactor LZ77 handling in preparation for a new method.
+67de68b5 Android.mk/build.gradle: fix mips build with clang from r14b
+f209a548 Use the plane code and not the distance when computing statistics.
+b903b80c Split cost-based backward references in its own file.
+498cad34 Cosmetic changes in backward reference.
+e4eb4587 lossless, VP8LTransformColor_C: make sure no overflow happens with colors.
+af6deaff webpinfo: handle alpha flag mismatch
+7caef29b Fix typo that creeped in.
+39e19f92 Merge "near lossless: fix unsigned int overflow warnings."
+9bbc0891 near lossless: fix unsigned int overflow warnings.
+e1118d62 Merge "cosmetics,FindClosestDiscretized: use uint in mask creation"
+186bc9b7 Merge "webpinfo: tolerate ALPH+VP8L"
+b5887297 cosmetics,FindClosestDiscretized: use uint in mask creation
+f1784aee near_lossless,FindClosestDiscretized: use unsigned ops
+0d20abb3 webpinfo: tolerate ALPH+VP8L
+972104b3 webpmux: tolerate false positive Alpha flag
+dd7e83cc tiffdec,ReadTIFF: ensure data_size is < tsize_t max
+d988eb7b tiffdec,MyRead: quiet -Wshorten-64-to-32 warning
+dabda707 webpinfo: add support to parse Alpha bitstream
+4c117643 webpinfo: correct background color output, BGRA->ARGB
+defc98d7 Doc: clarify the role of quality in WebPConfig.
+d78ff780 Merge "Fix code to compile with C++."
+c8f14093 Fix code to compile with C++.
+497dc6a7 pnmdec: sanitize invalid header output
+d78e5867 Merge "configure: test for -Wconstant-conversion"
+481e91eb Merge "pnmdec,PAM: set bytes_per_px based on depth when missing"
+93b12753 configure: test for -Wconstant-conversion
+645f0c53 pnmdec,PAM: set bytes_per_px based on depth when missing
+e9154605 Merge "vwebp: activate GLUT double-buffering"
+818d795b vwebp: activate GLUT double-buffering
+d63e6f4b Add a man page for webpinfo
+4d708435 Merge "NEON: implement ConvertRGB24ToY/BGR24/ARGB/RGBA32ToUV/ARGBToUV"
+faf42213 NEON: implement ConvertRGB24ToY/BGR24/ARGB/RGBA32ToUV/ARGBToUV
+b4d576fa Install man pages with CMake.
+cbc1b921 webpinfo: add features to parse bitstream header
+e644c556 Fix bad bit writer initialization.
+b62cdad2 Merge "Implement a cruncher for lossless at method 6."
+da3e4dfb use the exact constant for the gamma transfer function
+a9c701e0 Merge "tiffdec: fix EXTRASAMPLES check"
+adab8ce0 Implement a cruncher for lossless at method 6.
+1b92b237 Merge "Fix VP8ApplyNearLossless to respect const and stride."
+1923ff02 tiffdec: fix EXTRASAMPLES check
+97cce5ba tiffdec: only request EXTRASAMPLES w/> 3 samples/px
+0dcd85b6 Fix VP8ApplyNearLossless to respect const and stride.
+f7682189 yuv: rationalize the C/SSE2 function naming
+52245424 NEON implementation of some Sharp-YUV420 functions
+690efd82 Avoid several backward reference copies.
+4bb1f607 src/dec/vp8_dec.h, cosmetics: fix comments
+285748be cmake: build/install webpinfo
+78fd199c backward_references_enc.c: clear -Wshadow warnings
+ae836410 WebPLog2FloorC: clear -Wshadow warning
+d0b7404e Merge "WASM support"
+134e314f WASM support
+c08adb6f Merge "VP8LEnc: remove use of BitsLog2Ceiling()"
+28c37ebd VP8LEnc: remove use of BitsLog2Ceiling()
+2cb58ab2 webpinfo: output format as a human readable string
+bb175a93 Merge "rename some symbols clashing with MSVC headers"
+39eda658 Remove a duplicated pixel hash implementation.
+36b8274d rename some symbols clashing with MSVC headers
+274daf54 Add webpinfo tool.
+ec5036e4 add explicit reference to /usr/local/{lib,inc}
+18f0dfac Merge "fix TIFF encoder regarding rgbA/RGBA"
+4e2b0b50 Merge "webpdec.h: fix a doc typo"
+e2eeabff Merge "Install binaries, libraries and headers in CMake."
+836607e6 webpdec.h: fix a doc typo
+9273e441 fix TIFF encoder regarding rgbA/RGBA
+17e3c11f Add limited PAM decoding support
+5f624871 Install binaries, libraries and headers in CMake.
+976adac1 Merge "lossless incremental decoding: fix missing eos_ test"
+f8fad4fa lossless incremental decoding: fix missing eos_ test
+27415d41 Merge "vwebp_sdl: fix the makefile.unix"
+49566182 Merge "ImgIoUtilWriteFile(): use ImgIoUtilSetBinaryMode"
+6f75a51b Analyze the transform entropy on the whole image.
+a5e4e3af Use palette only if we can in entropy analysis.
+75a9c3c4 Improve compression by better entropy analysis.
+39cf6f4f vwebp_sdl: fix the makefile.unix
+699b0416 ImgIoUtilWriteFile(): use ImgIoUtilSetBinaryMode
+7d985bd1 Fix small entropy analysis bug.
+6e7caf06 Optimize the color cache size.
+833c9219 More efficient stochastic histogram merge.
+5183326b Refactor the greedy histogram merge.
+99f6f462 Merge "histogram_enc.c,MyRand: s/ul/u/ for unsigned constants"
+80a22186 ssim.c: remove dead include
+a128dfff histogram_enc.c,MyRand: s/ul/u/ for unsigned constants
+693bf74e move the SSIM calculation code in ssim.c / ssim_sse2.c
+10d791ca Merge "Fix the random generator in HistogramCombineStochastic."
+fa63a966 Fix the random generator in HistogramCombineStochastic.
+16be192f VP8LSetBitPos: remove the eos_ setting
+027151ca don't erase the surface before blitting.
+4105d565 disable WEBP_USE_XXX optimisations when EMSCRIPTEN is defined
+9ee32a75 Merge "WebP-JS: emscripten-based Javascript decoder"
+ca9f7b7d WebP-JS: emscripten-based Javascript decoder
+868aa690 Perform greedy histogram merge in a unified way.
+5b393f2d Merge "fix path typo for vwebp_sdl in Makefile.vc"
+e0012bea CMake: only use libwebpdecoder for building dwebp
+84c2a7b0 fix path typo for vwebp_sdl in Makefile.vc
+1b0e4abf Merge "Add a flag to disable SIMD optimizations."
+32263250 Add a flag to disable SIMD optimizations.
+b494fdec optimize the ARGB->ARGB Import to use memcpy
+f1536039 Merge "ReadWebP: decode directly into a pre-allocated buffer"
+e69ed291 ReadWebP: decode directly into a pre-allocated buffer
+57d8de8a Merge "vwebp_sdl: simple viewer based on SDL"
+5cfd4ebc LZ77 interval speedups. Faster, smaller, simpler.
+1e7ad88b PNM header decoder: add some basic numerical validation
+17c7890c Merge "Add a decoder only library for WebP in CMake."
+be733786 Merge "Add clang build fix for MSA"
+03cda0e4 Add a decoder only library for WebP in CMake.
+aa893914 Add clang build fix for MSA
+31a92e97 Merge "imageio: add limited PNM support for reading"
+dcf9d82a imageio: add limited PNM support for reading
+6524fcd6 vwebp_sdl: simple viewer based on SDL
+6cf24a24 get_disto: fix reference file read
+43d472aa Merge tag 'v0.6.0'
+50d1a848 update ChangeLog (tag: v0.6.0, origin/0.6.0)
+20a7fea0 extras/Makefile.am: fix libwebpextras.la reference
+415f3ffe update ChangeLog (tag: v0.6.0-rc3)
+3c6d1224 update NEWS
+ee4a4141 update AUTHORS
+32ed856f Fix "all|no frames are keyframes" settings.
+1c3190b6 Merge "Fix "all|no frames are keyframes" settings."
+f4dc56fd disable GradientUnfilter_NEON
+4f3e3bbd disable GradientUnfilter_NEON
+2dc0bdca Fix "all|no frames are keyframes" settings.
+0d8e0588 img2webp: treat -loop as a no-op w/single images
+b0450139 ReadImage(): restore size reporting
+0ad3b4ef update ChangeLog (tag: v0.6.0-rc2)
+6451709e img2webp,get_disto: fix image decode w/WIC builds
+92504d21 get_disto: make ReadPicture() return a bool
+c3e4b3a9 update NEWS
+3363eb6d man/img2webp.1: fix formatting warning
+4d1312f2 update NEWS
+36c42ea4 bump version to 0.6.0
+bb498a51 update AUTHORS
+84cef16f Makefile.vc: fix CFG=debug-dynamic build
+919f9e2f Merge "add .rc files for windows dll versioning"
+f1ae8af4 Merge ".gitignore: add img2webp"
+4689ce16 cwebp: add a -sharp_yuv option for 'sharp' RGB->YUV conversion
+79bf46f1 rename the pretentious SmartYUV into SharpYUV
+eb1dc89a silently expose use_delta_palette in the WebPConfig API
+c85b0dde .gitignore: add img2webp
+43d3f01a add .rc files for windows dll versioning
+668e1dd4 src/{dec,enc,utils}: give filenames a unique suffix
+0e6b7f33 Merge "iosbuild.sh: only add required headers to framework"
+29ed6f9a iosbuild.sh: only add required headers to framework
+71c53f1a NEON: speed-up strong filtering
+73f567ea Merge "get_disto: remove redundant reader check"
+9e14276f Merge "makefiles: prune get_disto & webp_quality deps"
+99965bac Merge "Makefile.vc: add get_disto.exe, webp_quality.exe"
+d4912238 get_disto: remove redundant reader check
+ea482409 makefiles: prune get_disto & webp_quality deps
+2ede5a19 Makefile.vc: add get_disto.exe, webp_quality.exe
+a345068a ARM: speed up bitreader by avoiding tables
+1dc82a6b Merge "introduce a generic GetCoeffs() function pointer"
+8074b89e introduce a generic GetCoeffs() function pointer
+749a45a5 Merge "NEON: implement alpha-filters (horizontal/vertical/gradient)"
+74c053b5 Merge "NEON: fix overflow in SSE NxN calculation"
+0a3aeff7 Merge "dsp: WebPExtractGreen function for alpha decompression"
+1de931c6 NEON: implement alpha-filters (horizontal/vertical/gradient)
+9b3aca40 NEON: fix overflow in SSE NxN calculation
+1c07a3c6 dsp: WebPExtractGreen function for alpha decompression
+9ed5e3e5 use pointers for WebPRescaler's in WebPDecParams
+db013a8d Merge "ARM: don't use USE_GENERIC_TREE"
+fcd4784d use a 8b table for C-version for clz()
+fbb5c473 ARM: don't use USE_GENERIC_TREE
+8fda5612 Merge "add a kSlowSSSE3 feature for CPUInfo"
+86bbd245 add a kSlowSSSE3 feature for CPUInfo
+7c2779e9 Get code to fully compile in C++.
+250c3586 Merge "When compiling as C++, avoid narrowing warnings."
+c0648ac2 When compiling as C++, avoid narrowing warnings.
+0d55f60c 40% faster ApplyAlphaMultiply_SSE2
+49d0280d NEON: implement several alpha-processing functions
+48b1e85f SSE2: 15% faster alpha-processing functions
+e3b8abbc fix warning from static analysis.
+28fe054e SSE2: 30% faster ApplyAlphaMultiply()
+f44acd25 Merge "Properly compute the optimal color cache size."
+527844fe Properly compute the optimal color cache size.
+be0ef639 fix a comment typo
+8874b162 Fix a non-deterministic color cache size computation.
+d712e20d Do not allow a color cache size bigger than the number of colors.
+ecff04f6 re-introduce some comments in Huffman Cost.
+259e9828 replace 'ptr + y * stride' by 'ptr += stride'
+00b08c88 Merge "NEON: 5% faster conversion to RGB565 and RGBA4444"
+0e7f4447 Merge "NEON: faster fancy upsampling"
+b016cb91 NEON: faster fancy upsampling
+1cb63801 Call the C function to finish off lossless SSE loops only when necessary.
+875fafc1 Implement BundleColorMap in SSE2.
+3674d49e Merge "remove Clang warnings with unused arch arguments."
+f04eb376 Merge tag 'v0.5.2'
+341d711c NEON: 5% faster conversion to RGB565 and RGBA4444
+abb54827 remove Clang warnings with unused arch arguments.
+ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2)
+aa7744ca anim_util: quiet implicit conv warnings in 32-bit
+d9120271 jpegdec: correct ContextFill signature
+24eb3940 Remove some errors when compiling the code as C++.
+a4a8e5f3 vwebp: clear canvas during resize w/o animation
+67c25ad5 vwebp: clear canvas during resize w/o animation
+a4bbe4b3 fix indentation
+31ca2a80 tiffdec: restore libtiff 3.9.x compatibility
+b2f77b57 update NEWS
+5ab6d9de AnimEncoder: avoid freeing uninitialized memory pointer.
+f29bf582 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless.
+3ebe1c00 AnimEncoder: avoid freeing uninitialized memory pointer.
+df780e0e fix a potential overflow with MALLOC_LIMIT
+58fc5078 Merge "PredictorSub: implement fully-SSE2 version"
+9cc42167 PredictorSub: implement fully-SSE2 version
+0aa1f35c remove dependency of imageio/ to stopwatch.h
+cb9ec84b Merge "remove the dependency to stop_watch.[ch] in imageio"
+dc0c01fb Merge "anim_util: quiet implicit conv warnings in 32-bit"
+827d3c50 Merge "fix a potential overflow with MALLOC_LIMIT"
+1e2e25b0 anim_util: quiet implicit conv warnings in 32-bit
+218460cd bump version to 0.5.2
+de7d654d update AUTHORS & .mailmap
+273367c1 Merge "dsp/lossless.c,cosmetics: fix indent"
+76bbcf2e fix a potential overflow with MALLOC_LIMIT
+8ac1abfe Merge "jpegdec: correct ContextFill signature"
+cb215aed remove the dependency to stop_watch.[ch] in imageio
+2423017a dsp/lossless.c,cosmetics: fix indent
+74a12b10 iosbuild.sh: add WebPDecoder.framework + encoder
+a9cc7621 Merge "iosbuild.sh: add WebPDecoder.framework + encoder"
+fbba5bc2 optimize predictor #1 in plain-C For some reason, gcc has hard time inlining this one...
+9ae0b3f6 Merge "SSE2: slightly (~2%) faster Predictor #1"
+c1f97bd7 SSE2: slightly (~2%) faster Predictor #1
+ea664b89 SSE2: 10% faster Predictor #11
+be7dcc08 AnimEncoder: Correctly skip a frame when sub-rectangle is empty.
+40885830 Fix assertions in WebPRescalerExportRow()
+1d5046d1 iosbuild.sh: add WebPDecoder.framework + encoder
+cec72014 jpegdec: correct ContextFill signature
+8f38c72e fix a typo in WebPPictureYUVAToARGB's doc
+33ca93f9 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_
+76e19073 doc: use two's complement explicitly for uint8->int8 conversion
+f91ba963 Anim_encoder: correctly handle enc->prev_candidate_undecided_
+25d74e65 WebPPictureDistortion(): free() -> WebPSafeFree()
+03f1c008 mux/Makefile.am: add missing -lm
+58410cd6 fix bug in RefineUsingDistortion()
+e168af8c fix filtering auto-adjustment
+ed9dec41 fix doc and code snippet for WebPINewDecoder() doc
+3c49178f prevent 32b overflow for very large canvas_width / height
+9595f290 fix anim_util.c compilation when HAVE_GIF is not defined.
+7ec9552c Make gif transparent color to be transparent black
+b3fb8bb6 slightly faster Predictor #11 in NEON
+9871335f Add a CMake option for WEBP_SWAP_16BIT_CSP.
+0ae32226 Fix missing cpu-features for Android.
+ab4c8056 cpu.cmake: improve webp_check_compiler_flag output
+eec5fa3a Provide support for CMake on Android studio 2.2.
+004d5690 Split the main CMake file.
+4fe5d588 Android.mk: use -fvisibility=hidden
+bd63a31a vwebp: ensure setenv() is available in stdlib.h
+363a5681 vwebp: handle window resizing properly
+a0d2753f lower WEBP_MAX_ALLOCABLE_MEMORY default
+31fe11a5 fix infinite loop in case of PARTITION0 overflow
+532215dd Change the rule of picking UV mode in MBAnalyzeBestUVMode()
+9c75dbd3 cwebp.1: improve some grammar
+af2e05cb vwebp: Clear previous frame when a key triggers a redraw
+26ffa296 Add descriptions of default configuration in help info.
+7416280d Fix an unsigned integer overflow error in enc/cost.h
+13cf1d2e Do token recording and counting in a single loop
+eb9a4b97 Reset segment id if we decide not to update segment map
+42ebe3b7 configure: fix NEON flag detection under gcc 6
+76ebbfff NEON: implement predictor #13
+95b12a08 Merge "Revert Average3 and Average4"
+54ab2e75 Revert Average3 and Average4
+fe12330c 3-5% faster Predictor #5, #6, #7 and #10 for NEON
+fbfb3bef ~2% faster predictor #10 for NEON
+d4b7d801 lossless_sse2: use the local functions
+a5e3b225 Lossless decoder SSE2 improvements.
+58a1f124 ~2% faster predictor #12 in NEON.
+906c3b63 Merge "Implement lossless transforms in NEON."
+d23abe4e Implement lossless transforms in NEON.
+2e6cb6f3 Give more flexibility to the predictor generating macro.
+28e0bb70 Merge "Fix race condition in multi-threading initialization."
+64704530 Fix race condition in multi-threading initialization.
+bded7848 img2webp: fix default -lossless value and use pic.argb=1
+0e61a513 Merge "img2webp: convert a sequence of images to an animated webp"
+1cc79e92 AnimEncoder: Correctly skip a frame when sub-rectangle is empty.
+03f40955 img2webp: convert a sequence of images to an animated webp
+ea72cd60 add missing 'extern' keyword for predictor dcl
+67879e6d SSE implementation of decoding predictors.
+34aee990 Merge "vwebp: make 'd' key toggle the debugging of fragments"
+a41296ae Fix potentially uninitialized value.
+c85adb33 vwebp: make 'd' key toggle the debugging of fragments
+4239a148 Make the lossless predictors work on a batch of pixels.
+bc18ebad fix extra 'const's in signatures
+71e2f5ca Remove memcpy in lossless decoding.
+7474d46e Do not use a register array in SSE.
+67748b41 Improve latency of FTransform2.
+16951b19 Merge "Provide an SSE implementation of ConvertBGRAToRGB"
+6540cd0e Provide an SSE implementation of ConvertBGRAToRGB
+de568abf Android.mk: use -fvisibility=hidden
+3c2a61b0 remove some unneeded casts
+9ac063c3 add dsp functions for SmartYUV
+22efabdd Merge "smart_yuv: switch to planar instead of packed r/g/b processing"
+1d6e7bf3 smart_yuv: switch to planar instead of packed r/g/b processing
+0a3838ca fix bug in RefineUsingDistortion()
+c0699515 webpmux -duration: set default 'end' value equal to 'start'
+83cbfa09 Import: use relative pointer offsets
+a1ade40e PreprocessARGB: use relative pointer offsets
+fd4d090f ConvertWRGBToYUV: use relative pointer offsets
+9daad459 ImportYUVAFromRGBA: use relative pointer offsets
+f90c60d1 Merge "add a "-duration duration,start,end" option to webpmux"
+3f182d36 add a "-duration duration,start,end" option to webpmux
+342e15f0 Import: use relative pointer offsets
+1147ab4e PreprocessARGB: use relative pointer offsets
+e4cd4daf fix filtering auto-adjustment
+e7152856 fix doc and code snippet for WebPINewDecoder() doc
+de9fa507 ConvertWRGBToYUV: use relative pointer offsets
+deb1b831 ImportYUVAFromRGBA: use relative pointer offsets
+c284780f imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow
+e375080d gifdec,Remap: avoid out of bounds colormap read
+c222a053 additional fix for stride type as size_t
+bb233617 fix potential overflow when width * height * 4 >= (1<<32)
+883d41fb gif2webp: fix crash with NULL extension data
+cac9a36a gifdec,Remap: avoid out of bounds colormap read
+4595e01f Revert "gifdec,Remap: avoid out of bounds colormap read"
+fb52d443 gifdec: make some constants unsigned
+f048d38d gifdec,Remap: avoid out of bounds colormap read
+31b1e343 fix SSIM metric ... by ignoring too-dark area
+2f51b614 introduce WebPPlaneDistortion to compute plane distortion
+0104d730 configure: fix NEON flag detection under gcc 6
+265abbe9 Merge "additional fix for stride type as size_t"
+f7601aa6 Merge "Introduce a generic WebPGetImageReader(type) function"
+ce873320 Introduce a generic WebPGetImageReader(type) function
+2a2773ea imageio/*dec,Read*: add input parameter checks
+9f5c8eca additional fix for stride type as size_t
+4eb5df28 remove unused stride fields from VP8Iterator
+11bc423a MIN_LENGTH cleanups.
+273d035a Merge "fix a typo in WebPPictureYUVAToARGB's doc"
+4db82a17 Merge "fix potential overflow when width * height * 4 >= (1<<32)"
+e2affacc fix potential overflow when width * height * 4 >= (1<<32)
+dc789ada fix a typo in WebPPictureYUVAToARGB's doc
+539f5a68 Fix non-included header in config.c.
+aaf2a6a6 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_
+20ef9915 Merge "imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow"
+bc86b7a8 imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow
+806f6279 gif2webp: fix crash with NULL extension data
+68ae5b67 Add libwebp/src/mux/animi.h
+28ce3043 Remove some errors when compiling the code as C++.
+b34abcb8 Favor keeping the areas locally similar in spatial prediction mode selection
+ba843a92 fix some SSIM calculations
+51b71fd2 Merge "vwebp: ensure setenv() is available in stdlib.h"
+fb01743a get_disto: fix the r/g/b order for luma calculation
+bfab8947 vwebp: ensure setenv() is available in stdlib.h
+9310d192 vwebp: handle window resizing properly
+f79450ca Speedup ApplyMap.
+cfdda7c6 Merge "prevent 32b overflow for very large canvas_width / height"
+e36396ba Merge "get_disto: new option to compute SSIM map and convert to gray"
+18a9a0ab Add an API to import a color-mapped image.
+30d43706 Speed-up Combined entropy for palettized histograms.
+36aa087b get_disto: new option to compute SSIM map and convert to gray
+86a84b35 2x faster SSE2 implementation of SSIMGet
+b8384b53 lower WEBP_MAX_ALLOCABLE_MEMORY default
+1c364400 prevent 32b overflow for very large canvas_width / height
+eee0cce1 Merge "Small LZ77 speedups."
+5f1caf29 Small LZ77 speedups.
+1effde7b fix anim_util.c compilation when HAVE_GIF is not defined.
+a2fe9bf4 Speedup TrellisQuantizeBlock().
+573cce27 smartYUV improvements
+21e7537a fix infinite loop in case of PARTITION0 overflow
+053a1565 Merge "Change the rule of picking UV mode in MBAnalyzeBestUVMode()"
+1377ac2e Change the rule of picking UV mode in MBAnalyzeBestUVMode()
+7c1fb7d0 fix uint32_t initialization (0. -> 0)
+bfff0bf3 speed-up SSIM calculation
+64577de8 De-VP8L-ize GetEntropUnrefinedHelper.
+a7be7328 Merge "refactor the PSNR / SSIM calculation code"
+50c3d7da refactor the PSNR / SSIM calculation code
+d6228aed indentation fix after I7055d3ee3bd7ed5e78e94ae82cb858fa7db3ddc0
+dd538b19 Remove unused declaration.
+6cc48b17 Move some lossless logic out of dsp.
+78363e9e Merge "Remove a redundant call to InitLeft() in VP8IteratorReset()"
+ffd01929 Refactor VP8IteratorNext().
+c4f6d9c9 Remove a redundant call to InitLeft() in VP8IteratorReset()
+c27d8210 Merge "smartYUV: simplify main loop"
+07795296 smartYUV: simplify main loop
+c9b45863 Split off common lossless dsp inline functions.
+490ae5b1 smartYUV: improve initial state for faster convergence
+894232be smartYUV: fix and simplify the over-zealous stop criterion
+8de08483 Remove unused code in webpi.h
+41cab7fe imageio/Android.mk: correct imagedec dependencies
+82c91c70 Merge "libimageenc.a: extract image-saving code from dwebp"
+af1ad3e2 libimageenc.a: extract image-saving code from dwebp
+dd7309e3 Merge "doc: use two's complement explicitly for uint8->int8 conversion"
+6105777e Merge "add gif2webp to CMake"
+13ae011e doc: use two's complement explicitly for uint8->int8 conversion
+4bda0cfb add gif2webp to CMake
+6029c7fe Merge "remove mention of fragment, frgm, FRGM, etc."
+545c147f remove mention of fragment, frgm, FRGM, etc.
+5b46f7fc cwebp.1: improve some grammar
+9e478f80 dec/vp8l.c: add assertions in EmitRescaledRowsRGBA/YUVA
+43bd8958 Make gif transparent color to be transparent black
+0887fc2d Merge "get_disto: add a '-o file' option to save a diff map"
+0de48e18 get_disto: add a '-o file' option to save a diff map
+0a57ad0d cosmetics: WebPSafeAlloc -> WebPSafeMalloc
+0a4699bc Merge "WebPPictureDistortion(): free() -> WebPSafeFree()"
+29fedbf5 Anim_encoder: correctly handle enc->prev_candidate_undecided_
+32dead4e WebPPictureDistortion(): free() -> WebPSafeFree()
+85cd5d06 Smarter LZ77 for uniform regions.
+6585075f Change PixelsAreSimilar() to handle black pixels correctly.
+c0a27fd2 vwebp: Clear previous frame when a key triggers a redraw
+57a5e3b6 webp_quality should return '0' in case of success.
+7f1b897b Faster stochastic histogram merging.
+48c810b8 Merge "remove WEBP_FORCE_ALIGNED and use memcpy() instead."
+3884972e remove WEBP_FORCE_ALIGNED and use memcpy() instead.
+485cac1a switch libimagedec.a and libimageio_util.a to avoid undefined symbol
+005e15b1 Merge "{extras,mux}/Makefile.am: add missing -lm"
+6ab496ed fix some 'unsigned integer overflow' warnings in ubsan
+8a4ebc6a Revert "fix 'unsigned integer overflow' warnings in ubsan"
+9d4f209f Merge changes I25711dd5,I43188fab
+e44f5248 fix 'unsigned integer overflow' warnings in ubsan
+27b5d991 Fix assertions in WebPRescalerExportRow()
+74f6f9e7 Add descriptions of default configuration in help info.
+aaf2530c {extras,mux}/Makefile.am: add missing -lm
+1269dc7c Refactor VP8LColorCacheContains()
+40872fb2 dec_neon,NeedsHev: micro optimization
+7b54e26b Add a CMake option for WEBP_SWAP_16BIT_CSP.
+d2223d8d Fix missing cpu-features for Android.
+bf16a4b4 Merge "cpu.cmake: improve webp_check_compiler_flag output"
+ee1057e3 cpu.cmake: improve webp_check_compiler_flag output
+b551e587 cosmetics: add {}s on continued control statements
+d2e4484e dsp/Makefile.am: put msa source in correct lib
+c7f66c82 Merge "utils/thread.c,cosmetics: join a few lines"
+98d8f295 Merge "examples/Makefile.am,cosmetics: sort binary targets"
+39f4ffbc utils/thread.c,cosmetics: join a few lines
+a86ce2b1 Merge "extras/Makefile.am: don't install libwebpextras"
+6fa9fe24 extras/Makefile.am: don't install libwebpextras
+0b2c58a9 Fix an unsigned integer overflow error in enc/cost.h
+d7ce4a2e examples/Makefile.am,cosmetics: sort binary targets
+386e4ba2 Reset segment id if we decide not to update segment map
+7b87e848 Merge "Add MSA optimized YUV to RGB upsampling functions"
+d3ddacb6 Add MSA optimized YUV to RGB upsampling functions
+eb98d8d8 webp_quality: detect lossless format and features
+ebee57f4 move imageio/example_util.[hc] (back to) examples/
+99542bbf webpdec: s/ExUtil//
+da573cf4 imageio_util: s/ExUtil/ImgIoUtil/
+bdda5bd4 split example_util.h
+15ed462b .gitignore: add extras/{get_disto,webp_quality}
+7be57489 Merge "VP8EstimateQuality(): roughty estimate webp bitstream quality factor"
+57020525 Makefile.vc: add missing imageio target
+e8ab6a82 VP8EstimateQuality(): roughty estimate webp bitstream quality factor
+fee7b3d6 Merge "'extras/get_disto' example: compute PSNR between two files"
+1e7d4401 'extras/get_disto' example: compute PSNR between two files
+4cecab63 pngdec.c,jpegdec.[hc]: remove unnecessary includes
+259f0434 makefile.unix: normalize image decode lib name
+ed34c39b fix: examples/libexample_dec.a => imageio/libexample_dec.a
+33d8d0d4 Merge "move examples/{example_util,image_dec} to imageio/"
+c960b82e Merge "extras.h: correct include guard"
+fe3cd28a Merge ".gitignore: add .gradle, /build"
+45fbeba5 Merge "Do token recording and counting in a single loop"
+4f33c820 .gitignore: add .gradle, /build
+c379b55a move examples/{example_util,image_dec} to imageio/
+5108d9aa extras.h: correct include guard
+ad497fbc move src/extras to the top-level
+0c0fb832 Do token recording and counting in a single loop
+9ac74f92 Add MSA optimized rescaling functions
+cb19dbc1 Add MSA optimized color transform functions
+3f4042b5 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless.
+5e2eb89e cosmetics,dsp/*msa.c: associate '*' with the type
+5b60db5c FastMBAnalyze() for quick i16/i4 decision
+567e6977 Add MSA optimized CollectHistogram function
+c54ab8dd Add MSA optimized quantization functions
+ec6f68c5 Merge "Remove QuantizeBlockWHT() in enc.c"
+2a5c417c Apply the RLE heuristic to LZ77.
+91b59e88 Remove QuantizeBlockWHT() in enc.c
+fe572737 Add MSA optimized SSE functions
+6b53ca87 cosmetics,(dec|enc)_sse2.c: fix indent
+b15d00d9 Merge "Add MSA optimized encoder IntraChromaPreds function"
+afe3cec8 Add MSA optimized encoder IntraChromaPreds function
+fc8cad9f reduce the number of malloc/free cycles in huffman.c
+7b4b05e0 Add MSA optimized encoder Intra16Preds function
+c18787a0 Add MSA optimized encoder Intra4Preds function
+479d1908 webpmux: Also print compression info per frame.
+a80e8cfd Provide support for CMake on Android studio 2.2.
+6c628410 Split the main CMake file.
+bbb6ecd9 Merge "Add MSA optimized distortion functions"
+7915396f Add MSA optimized distortion functions
+652e944f Merge "build.gradle: remove tab"
+c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr
+48bf5ed1 build.gradle: remove tab
+bfef6c9f Merge tag 'v0.5.1'
+3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1)
+deb54d91 Clarify the expected 'config' lifespan in WebPIDecode()
+435308e0 Add MSA optimized encoder transform functions
+dce64bfa Add MSA optimized alpha filter functions
+429120d0 Add MSA optimized color transform functions
+c7e2d245 update ChangeLog (tag: v0.5.1-rc5)
+55b2fede normalize the macros' "do {...} while (0)" constructs
+701c772e Add MSA optimized colorspace conversion functions
+c7eb06f7 Fix corner case in CostManagerInit.
+f918cb10 fix rescaling bug: alpha plane wasn't filled with 0xff
+ab7937a5 gif2webp: normalize the number of .'s in the help message
+3cdec847 vwebp: normalize the number of .'s in the help message
+bdf6241e cwebp: normalize the number of .'s in the help message
+06a38c7b fix rescaling bug: alpha plane wasn't filled with 0xff
+319e37be Improve lossless compression.
+6a197937 Add MSA optimized intra pred chroma functions
+447adbce 'our bug tracker' -> 'the bug tracker'
+97b9e644 normalize the number of .'s in the help message
+293d786f Added MSA optimized intra prediction 16x16 functions
+0afa0ce2 Added MSA optimized intra prediction 4x4 functions
+a6621bac Added MSA optimized simple edge filtering functions
+bb50bf42 pngdec,ReadFunc: throw an error on invalid read
+38063af1 decode.h,WebPGetInfo: normalize function comment
+1ebf193c Added MSA optimized chroma edge filtering functions
+9ad2352d Merge "Added MSA optimized edge filtering functions"
+60751096 Added MSA optimized edge filtering functions
+9e8e1b7b Inline GetResidual for speed.
+7d58d1b7 Speed-up uniform-region processing.
+8ec7032b simplify HistogramCombineEntropyBin()
+23e29cb1 Merge "Fix a boundary case in BackwardReferencesHashChainDistanceOnly." into 0.5.1
+472a049b remove bin_map[] allocation altogether
+0bb23b2c free -> WebPSafeFree()
+a977b4b5 Merge "rewrite the bin_map clustering to use less memory"
+3591ba66 rewrite the bin_map clustering to use less memory
+e6ac450c utils.[hc]: s/MAX_COLOR_COUNT/MAX_PALETTE_SIZE/
+e7b91772 Merge "DecodeImageData(): change the incorrect assert" into 0.5.1
+2abfa54f DecodeImageData(): change the incorrect assert
+5a48fcd8 Merge "configure: test for -Wfloat-conversion"
+0174d18d Fix a boundary case in BackwardReferencesHashChainDistanceOnly.
+6a9c262a Merge "Added MSA optimized transform functions"
+cfbcc5ec Make sure to consider small distances in LZ77.
+5e60c42a Added MSA optimized transform functions
+3dc28d76 configure: test for -Wfloat-conversion
+f2a0946a add some asserts to delimit the perimeter of CostManager's operation
+9a583c66 fix invalid-write bug for alpha-decoding
+f66512db make gradlew executable
+6fda58f1 backward_references: quiet double->int warning
+a48cc9d2 Merge "Fix a compression regression for images with long uniform regions." into 0.5.1
+cc2720c1 Merge "Revert an LZ77 boundary constant." into 0.5.1
+059aab4f Fix a compression regression for images with long uniform regions.
+b0c7e49e Check more backward matches with higher quality.
+a3611513 Revert an LZ77 boundary constant.
+8190374c README: fix typo
+7551db44 update NEWS
+0fb2269c bump version to 0.5.1
+f4537610 update AUTHORS & .mailmap
+3259571e Refactor GetColorPalette method.
+1df5e260 avoid using tmp histogram in PreparePair()
+7685123a fix comment typos
+a246b921 Speedup backward references.
+76d73f18 Merge "CostManager: introduce a free-list of ~10 intervals"
+eab39d81 CostManager: introduce a free-list of ~10 intervals
+4c59aac0 Merge "mips msa webp configuration"
+043c33f1 Merge "Improve speed and compression in backward reference for lossless."
+71be9b8c Merge "clarify variable names in HistogramRemap()"
+0ba7fd70 Improve speed and compression in backward reference for lossless.
+0481d42a CostManager: cache one interval and re-use it when possible
+41b7e6b5 Merge "histogram: fix bin calculation"
+96c3d624 histogram: fix bin calculation
+fe9e31ef clarify variable names in HistogramRemap()
+ce3c8247 disable near-lossless quantization if palette is used
+e11da081 mips msa webp configuration
+5f8f998d mux: Presence of unknown chunks should trigger VP8X chunk output.
+cadec0b1 Merge "Sync mips32 and dsp_r2 YUV->RGB code with C verison"
+d9637758 Compute the hash chain once and for all for lossless compression.
+50a48665 Sync mips32 and dsp_r2 YUV->RGB code with C verison
+eee788e2 Merge "introduce a common signature for all image reader function"
+d77b877c introduce a common signature for all image reader function
+ca8d9519 remove some obsolete TODOs
+ae2a7222 collect all decoding utilities from examples/ in libexampledec.a
+0b8ae852 Merge "Move DitherCombine8x8 to dsp/dec.c"
+77cad885 Merge "ReadWebP: avoid conversion to ARGB if final format is YUVA"
+ab8d6698 ReadWebP: avoid conversion to ARGB if final format is YUVA
+f8b7ce9e Merge "test pointer to NULL explicitly"
+5df6f214 test pointer to NULL explicitly
+77f21c9c Move DitherCombine8x8 to dsp/dec.c
+c9e6d865 Add gradle support
+c65f41e8 Revert "Add gradle support"
+bf731ede Add gradle support
+08333b85 WebPAnimEncoder: Detect when canvas is modified, restore only when needed.
+0209d7e6 Merge "speed-up MapToPalette() with binary search"
+fdd29a3d speed-up MapToPalette() with binary search
+cf4a651b Revert "Refactor GetColorPalette method."
+0a27aca3 Merge changes Idfa8ce83,I19adc9c4
+f25c4406 WebPAnimEncoder: Restore original canvas between multiple encodes.
+169004b1 Refactor GetColorPalette method.
+576362ab VP8LDoFillBitWindow: support big-endian in fast path
+ac49e4e4 bit_reader.c: s/VP8L_USE_UNALIGNED_LOAD/VP8L_USE_FAST_LOAD/
+d39ceb58 VP8LDoFillBitWindow: remove stale TODO
+2ec2de14 Merge "Speed-up BackwardReferencesHashChainDistanceOnly."
+3e023c17 Speed-up BackwardReferencesHashChainDistanceOnly.
+f2e1efbe Improve near lossless compression when a prediction filter is used.
+e15afbce dsp.h: fix ubsan macro name
+e53c9ccb dsp.h: add WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
+af81fdb7 utils.h: quiet -fsanitize=undefined warnings
+ea0be354 dsp.h: remove utils.h include
+cd276aec utils/*.c: ../utils/utils.h -> ./utils.h
+c8927131 utils/Makefile.am: add some missing headers
+ea24e026 Merge "dsp.h: add WEBP_UBSAN_IGNORE_UNDEF"
+369e264e dsp.h: add WEBP_UBSAN_IGNORE_UNDEF
+0d020a78 Merge "add runtime NEON detection"
+5ee2136a Merge "add VP8LAddPixels() to lossless.h"
+47435a61 add VP8LAddPixels() to lossless.h
+8fa6ac68 remove two ubsan warnings
+74fb56fb add runtime NEON detection
+4154a839 MIPS update to new Unfilter API
+c80b9fc8 Merge "cherry-pick decoder fix for 64-bit android devices"
+6235147e cherry-pick decoder fix for 64-bit android devices
+d41b8c43 configure: test for -Wformat-* w/-Wformat present
+5f95589f Fix WEBP_ALIGN in case the argument is a pointer to a type larger than a byte.
+2309fd5c replace num_parts_ by num_parts_minus_one_ (unsigned)
+9629f4bc SimplifySegments: quiet -Warray-bounds warning
+de47492e Merge "update the Unfilter API in dsp to process one row independently"
+2102ccd0 update the Unfilter API in dsp to process one row independently
+e3912d56 WebPAnimEncoder: Restore canvas before evaluating blending possibility.
+6e12e1e3 WebPAnimEncoder: Fix for single-frame optimization.
+602f344a Merge changes I1d03acac,Ifcb64219
+95ecccf6 only apply color-mapping for alpha on the cropped area
+47dd0708 anim_diff: Add an experimental option for max inter-frame diff.
+aa809cfe only allocate alpha_plane_ up to crop_bottom row
+31f2b8d8 WebPAnimEncoder: FlattenSimilarPixels(): look for similar
+774dfbdc perform alpha filtering within the decoding loop
+a4cae68d lossless decoding: only process decoded row up to last_row
+238cdcdb Only call WebPDequantizeLevels() on cropped area
+cf6c713a alpha: preparatory cleanup
+b95ac0a2 Merge "VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions"
+89231394 VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions
+5828e199 use_8b_decode -> use_8b_decode_
+8dca0247 fix bug in alpha.c that was triggering a memory error in incremental mode
+9a950c53 WebPAnimEncoder: Disable filtering when blending is used with lossy encoding.
+eb423903 WebPAnimEncoder: choose max diff for framerect based on quality.
+ff0a94be WebPAnimEncoder lossy: ignore small pixel differences for frame rectangles.
+f8040084 gif2webp: Remove the 'prev_to_prev_canvas' buffer.
+6d8c07d3 Merge "WebPDequantizeLevels(): use stride in CountLevels()"
+d96fe5e0 WebPDequantizeLevels(): use stride in CountLevels()
+ec1b2407 WebPPictureImport*: check output pointer
+c0768769 Merge "Revert "Re-enable encoding of alpha plane with color cache for next release.""
+41f14bcb WebPPictureImport*: check src pointer
+64eed387 Pass stride parameter to WebPDequantizeLevels()
+97934e24 Revert "Re-enable encoding of alpha plane with color cache for next release."
+e88c4ca0 fix -m 2 mode-cost evaluation (causing partition0 overflow)
+4562e83d Merge "add extra meaning to WebPDecBuffer::is_external_memory"
+abdb109f add extra meaning to WebPDecBuffer::is_external_memory
+875aec70 enc_neon,cosmetics: break long comment
+71e856cf GetMBSSIM,cosmetics: fix alignment
+a90edffb fix missing 'extern' for SSIM function in dsp/
+423ecaf4 move some SSIM-accumulation function for dsp/
+f08e6624 Merge "Fix FindClosestDiscretized in near lossless:"
+0d40cc5e enc_neon,Disto4x4: remove an unnecessary transpose
+e8feb20e Fix FindClosestDiscretized in near lossless:
+82006430 anim_util: quiet static analysis warning
+a6f23c49 Merge "AnimEncoder: Support progress hook and user data."
+a5193774 Merge "Near lossless feature: fix some comments."
+da98d31c AnimEncoder: Support progress hook and user data.
+33357131 Near lossless feature: fix some comments.
+0beed01a cosmetics: fix indent after 2f5e898
+6753f35c Merge "FTransformWHT optimization."
+6583bb1a Improve SSE4.1 implementation of TTransform.
+7561d0c3 FTransformWHT optimization.
+7ccdb734 fix indentation after patch #328220
+6ec0d2a9 clarify the logic of the error path when decoding fails.
+8aa352b2 Merge "Remove an unnecessary transposition in TTransform."
+db860884 Merge "remove useless #include"
+9960c316 Remove an unnecessary transposition in TTransform.
+6e36b511 Small speedup in FTransform.
+9dbd4aad Merge "fix C and SIMD flags completion."
+e60853ea Add missing common_sse2.h file to makefile.unix
+696eb2b0 fix C and SIMD flags completion.
+2b4fe33e Merge "fix multiple allocation for transform buffer"
+2f5e8986 fix multiple allocation for transform buffer
+bf2b4f11 Regroup common SSE code + optimization.
+4ed650a1 force "-pass 6" if -psnr or -size is used but -pass isn't.
+3ef1ce98 yuv_sse2: fix -Wconstant-conversion warning
+a7a03e9f Merge changes I4852d18f,I51ccb85d
+5e122bd6 gif2webp: set enc_options.verbose = 0 w/-quiet
+ab3c2583 anim_encode,DefaultEncoderOptions: init verbose
+8f0dee77 Merge "configure: fix builtin detection w/-Werror"
+4a7b85a9 cmake: fix builtin detection w/-Werror
+b74657fb configure: fix builtin detection w/-Werror
+3661b980 Add a CMakeLists.txt
+75f4af4d remove useless #include
+6c1d7631 avoid Yoda style for comparison
+8ce975ac SSE optimization for vector mismatch.
+7db53831 Merge tag 'v0.5.0'
+37f04949 update ChangeLog (tag: v0.5.0-rc1, tag: v0.5.0, origin/0.5.0)
+7e7b6ccc faster rgb565/rgb4444/argb output
+4c7f565f update NEWS
+1f62b6b2 update AUTHORS
+e224fdc8 update mailmap
+71100500 bump version to 0.5.0
+230a685e README: update help text, repo link
+d48e427b Merge "demux: accept raw bitstreams"
+99a01f4f Merge "Unify some entropy functions."
+4b025f10 Merge "configure: disable asserts by default"
+92cbddf8 Merge "fix PrintBlockInfo()"
+ca509a33 Unify some entropy functions.
+367bf903 fix PrintBlockInfo()
+b0547ff0 move back common constants for lossless_enc*.c into the .h
+fb4c7832 lossless: simpler alpha cleanup preprocessing
+ba7f4b68 Merge "anim_diff: add brief description of options"
+47ddd5a4 Move some codec logic out of ./dsp .
+b4106c44 anim_diff: add brief description of options
+357f455d yuv_sse2: fix 32-bit visual studio build
+b9d80fa4 configure: disable asserts by default
+7badd3da cosmetic fix: sizeof(type) -> sizeof(*var)
+80ce27d3 Speed up 24-bit packing / unpacking in YUV / RGB conversions.
+68eebcb0 remove a TODO about rotation
+2dee2966 remove few obsolete TODO about aligned loads in SSE2
+e0c0bb34 remove TODO about unused ref_lf_delta[]
+9cf1cc2b remove few TODO: * 256 -> RD_DISTO_MULT * don't use TDisto for UV mode picking
+79189645 Merge changes from topic 'demux-fragment-cleanup'
+47399f92 demux: remove GetFragment()
+d3cfb79a demux: remove dead fragment related TODO
+ab714b8a demux, Frame: remove is_fragment_ field
+b105921c yuv_sse2, cosmetics: fix indent
+466c92e8 demux,WebPIterator: remove fragment_num/num_fragments
+11714ff1 demux: remove WebPDemuxSelectFragment
+c0f7cc47 fix for bug #280: UMR in next->bits
+578beeb8 Merge "enc/Makefile.am: add missing headers"
+1a819f00 makefile.unix: make visibility=hidden the default
+d4f9c2ef enc/Makefile.am: add missing headers
+846caff4 configure: check for -fvisibility=hidden
+3f3ea2c5 demux: accept raw bitstreams
+d6dad5d0 man cwebp: add precision about exactness of the 'lossless' mode
+46bb1e34 Merge "gifdec: remove utils.h include"
+2b882e94 Merge "Makefile.vc: define WEBP_HAVE_GIF for gifdec.c"
+892b9238 Merge "man/*, AUTHORS: clarify origin of the tool"
+e5687a18 Merge "fix optimized build with -mcmodel=medium"
+e56e6859 Makefile.vc: define WEBP_HAVE_GIF for gifdec.c
+4077d944 gifdec: remove utils.h include
+b5e30dac man/*, AUTHORS: clarify origin of the tool
+b275e598 fix optimized build with -mcmodel=medium
+64da45a9 cosmetics, cwebp: fix indent
+038a060d Merge "add disto-based refinement for UV mode (if method = 1 or 2)"
+2835089d Provide an SSE2 implementation of CombinedShannonEntropy.
+e6c93519 add disto-based refinement for UV mode (if method = 1 or 2)
+04507dc9 Merge "fix undefined behaviour during shift, using a cast"
+793c5261 Merge "wicdec: add support for reading from stdin"
+d3d16397 Optimize the heap usage in HistogramCombineGreedy.
+202a710b fix undefined behaviour during shift, using a cast
+14d27a46 improve method #2 by merging DistoRefine() and SimpleQuantize()
+cb1ce996 Merge "10% faster table-less SSE2/NEON version of YUV->RGB conversion"
+ac761a37 10% faster table-less SSE2/NEON version of YUV->RGB conversion
+79fcf29a wicdec: add support for reading from stdin
+015f173f Merge "cwebp: add support for stdin input"
+a9947c32 cwebp: add support for stdin input
+7eb01ff3 Merge "Improved alpha cleanup for the webp encoder when prediction transform is used."
+fb8c9106 Merge "introduce WebPMemToUint32 and WebPUint32ToMem for memory access"
+bd91af20 Merge "bit_reader: remove aarch64 BITS TODO"
+6c702b81 Speed up hash chain initialization using memset.
+4c60f63c make ReadPNG and ReadJPEG take a filename instead of a FILE
+464ed10f bit_reader: remove aarch64 BITS TODO
+d478e589 Merge "configure: update issue tracker"
+69381113 Improved alpha cleanup for the webp encoder when prediction transform is used.
+2c08aac8 introduce WebPMemToUint32 and WebPUint32ToMem for memory access
+010ca3d1 Fix FindMatchLength with non-aligned buffers.
+a90e1e3f README: add prerequisites for an autoconf build
+458f0866 configure: update issue tracker
+33914595 vwebp: work around the transparent background with GLUT bug
+e4a7eed4 cosmetics: fix indent
+08375129 Merge "Make a separate case for low_effort in CopyImageWithPrediction"
+aa2eb2d4 Merge "cosmetics: fix indent"
+b7551e90 cosmetics: fix indent
+5bda52d4 Make a separate case for low_effort in CopyImageWithPrediction
+66fa598a Merge "configure: fix intrinsics build w/older gcc"
+5ae220be backward_references.c: Fixed compiler warning
+1556da09 Merge "configure: restore 2 warnings"
+71a17e58 configure: restore 2 warnings
+9eeabc07 configure: fix intrinsics build w/older gcc
+363babe2 Merge "fix some warning about unaligned 32b reads"
+a1411782 Optimization in hash chain comparison for 64 bit Arrays were compared 32 bits at a time, it is now done 64 bits at a time. Overall encoding speed-up is only of 0.2% on @skal's small PNG corpus. It is of 3% on my initial 1.3 Mp desktop screenshot image.
+829bd141 Combine Huffman cost and bit entropy into one loop
+a7a954c8 Merge "lossless: make prediction in encoder work per scanline"
+61b605b4 Merge "fix of undefined multiply (int32 overflow)"
+239421c5 lossless: make prediction in encoder work per scanline
+f5ca40e0 fix of undefined multiply (int32 overflow)
+5cd2ef4c Merge changes from topic 'win-threading-compat'
+76ce9187 Makefile.vc: enable WEBP_USE_THREAD for windows phone
+d2afe974 thread: use CreateThread for windows phone
+0fd0e12b thread: use WaitForSingleObjectEx if available
+63fadc9f thread: use InitializeCriticalSectionEx if available
+110ad583 thread: use native windows cond var if available
+912c9fdf dec/webp: use GetLE(24|32) from utils
+f1694481 utils/GetLE32: correct uint32 promotion
+158763de Merge "always call WebPInitSamplers(), don't try to be smart"
+3770f3bb Merge "cleanup the YFIX/TFIX difference by removing some code and #define"
+a40f60a9 Merge "3% speed improvement for lossless webp encoder for low effort mode:"
+ed1c2bc6 always call WebPInitSamplers(), don't try to be smart
+b8c44f1a 3% speed improvement for lossless webp encoder for low effort mode:
+997e1038 cleanup the YFIX/TFIX difference by removing some code and #define
+d73d1c8b Merge "Make discarding invisible RGB values (cleanup alpha) the default."
+1f9be97c Make discarding invisible RGB values (cleanup alpha) the default.
+f240117b Make dwebp listen more to the -quiet flag
+b37b0179 fix for issue #275: don't compare to out-of-bound pointers
+21735e06 speed-up trivial one-symbol decoding case for lossless
+397863bd Refactor CopyPlane() and CopyPixels() methods: put them in utils.
+6ecd72f8 Re-enable encoding of alpha plane with color cache for next release.
+1f7148a4 Merge "remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures"
+6ae395fa Merge "use ExReadFile() for ReadYUV()"
+8076a00e gitignore list: add anim_diff.
+1c1702d8 use ExReadFile() for ReadYUV()
+775d3a37 remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures
+c13245c7 AnimEncoder: Add a GetError() method.
+688b265d AnimDecoder API: Add a GetDemuxer() method.
+1aa4e3d6 WebPAnimDecoder: add an option to enable multi-threaded decoding.
+3584abca AnimDecoder: option to decode to common color modes.
+afd5a62c Merge "mux.h does NOT need to include encode.h"
+8550d443 Merge "migrate anim_diff tool from C++ to C89"
+96201e50 migrate anim_diff tool from C++ to C89
+945cfa3b mux.h does NOT need to include encode.h
+8da07e8d Merge "~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV"
+bfd3fc02 ~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV
+02432427 man/cwebp.1, cosmetics: escape '-'s
+96f5b423 man/cwebp: group lossy-only options
+52fdbdfe extract some RGB24 to Luma conversion function from enc/ to dsp/
+ab8c2300 add missing \n
+8304179a sync NEWS with 0.4.4
+5bd04a08 sync versions with 0.4.4
+8f1fcc15 Merge "Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c"
+25bf2ce5 fix some warning about unaligned 32b reads
+922268fd s/TIFF/WebP
+fa8927ef Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c
+9b373598 Merge "for ReadXXXX() image-readers, use the value of pic->use_argb"
+f7c507a5 Merge "remove unnecessary #include "yuv.h""
+7861578b for ReadXXXX() image-readers, use the value of pic->use_argb
+14e4043b remove unnecessary #include "yuv.h"
+469ba2cd vwebp: fix incorrect clipping w/NO_BLEND
+4b9186b2 update issue tracker url
+d64d376c change WEBP_ALIGN_CST value to 31
+f717b828 vp8l.c, cosmetics: fix indent after 95509f9
+927ccdc4 Merge "fix alignment of allocated memory in AllocateTransformBuffer"
+fea94b2b fix alignment of allocated memory in AllocateTransformBuffer
+5aa8d61f Merge "MIPS: rescaler code synced with C implementation"
+e7fb267d MIPS: rescaler code synced with C implementation
+93c86ed5 Merge "format_constants.h: MKFOURCC, correct cast"
+5d791d26 format_constants.h: MKFOURCC, correct cast
+65726cd3 dsp/lossless: Average2, make a constant unsigned
+d26d9def Use __has_builtin to check clang support
+12ec204e moved ALIGN_CST into util/utils.h and renamed WEBP_ALIGN_xxx
+a2640838 Merge "rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand"
+3fb600d5 Merge "wicdec: fix alpha detection w/64bpp BGRA/RGBA"
+67c547fd rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand
+99e3f812 Merge "large re-organization of the delta-palettization code"
+95509f99 large re-organization of the delta-palettization code
+74fb458b fix for weird msvc warning message
+ae49ad86 Merge "SSE2 implementation of ImportRowShrink"
+932fd4df SSE2 implementation of ImportRowShrink
+badfcbaa wicdec: fix alpha detection w/64bpp BGRA/RGBA
+35cafa6c Merge "iosbuild: fix linking with Xcode 7 / iOS SDK 9"
+b0c9d8af label rename: NO_CHANGE -> NoChange
+b4e731cd neon-implementation for rescaler code
+db1321a6 iosbuild: fix linking with Xcode 7 / iOS SDK 9
+6dfa5e3e rescaler: better handling of the fxy_scale=0 special case.
+55c05293 Revert "rescaler: better handling of the fxy_scale=0 special case."
+9f226bf8 rescaler: better handling of the fxy_scale=0 special case.
+f7b8f907 delta_palettization.*: add copyright
+c1e1b710 Changed delta palette to compress better
+0dd28267 Merge "Add delta_palettization feature to WebP"
+48f66b66 Add delta_palettization feature to WebP
+27933e2a anim_encoder: drop a frame if it has same pixels as the prev frame.
+df9f6ec8 Merge "webpmux/DisplayInfo: send non-error output to stdout"
+8af4993b Merge "rescaler_mips_dsp_r2: cosmetics, fix indent"
+2b9d2495 Merge "rescaler: cosmetics, join two lines"
+cc020a8c webpmux/DisplayInfo: send non-error output to stdout
+a288e746 configure: add -Wshorten-64-to-32
+c4c3cf2d pngdec: fix type conversion warnings
+bef8e97d webpmux: fix type conversion warning
+5a84460d rescaler_mips_dsp_r2: cosmetics, fix indent
+acde0aae rescaler: cosmetics, join two lines
+306ce4fd rescaler: move the 1x1 or 2x1 handling one level up
+cced974b remove _mm_set_epi64x(), which is too specific
+56668c9f fix warnings about uint64_t -> uint32_t conversion
+76a7dc39 rescaler: add some SSE2 code
+1df1d0ee rescaler: harmonize function protos
+9ba1894b rescaler: simplify ImportRow logic
+5ff0079e fix rescaler vertical interpolation
+cd82440e VP8LAllocateHistogramSet: align histogram[] entries
+a406b1dd Merge "fix memory over-allocation in lossless rescaler init"
+0fde33e3 add missing const in VP8InitFrame signature
+ac7d5e8d fix memory over-allocation in lossless rescaler init
+017f8ccc Loosen the buffer size checks for Y/U/V/A too.
+15ca5014 loosen the padding check on buffer size
+d623a870 dec_neon: add whitespace around stringizing operator
+29377d55 dsp/mips: cosmetics: add whitespace around XSTR macro
+eebaf97f dsp/mips: add whitespace around stringizing operator
+d39dc8f3 Create a WebPAnimDecoder API.
+03fb7522 gif2webp: print output file size
+14efabbf Android: limit use of cpufeatures
+7b83adbe preparatory cosmetics for Rescaler code fix and clean-up
+77fb41c2 dec/vp8l/DecodeAlphaData: remove redundant cast
+90fcfcd9 Insert less hash chain entries from the beginnings of long copies.
+bd55604d SSE2: add yuv444 converters, re-using yuv_sse2.c
+41a5d99d add a -quiet option to 'dwebp'
+80ab3edb Merge "README: update dwebp help output after 1e595fe"
+32b71b2e README: update dwebp help output after 1e595fe
+3ec11827 use the DispatchAlpha() call from dsp
+c5f00621 incorporate bzero() into WebPRescalerInit() instead of call site
+3ebcdd41 remove duplicate "#include <stdlib.h>"
+1e595fe1 dwebp: add -resize as a synonym for -scale
+24a96932 dec: allow 0 as a scaling dimension
+b9187242 utils/rescaler: add WebPRescalerGetScaledDimensions
+923e8eda Merge "update NEWS"
+020fd099 Merge "WebPPictureDistortion: support ARGB format for 'pic' when computing distortion."
+6a5292f6 update NEWS
+56a2e9f5 WebPPictureDistortion: support ARGB format for 'pic' when computing distortion.
+0ae582e4 configure: test and add -Wunreachable-code
+c2f9dc06 bit_writer: convert VP8L macro values to immediates
+b969f888 Reduce magic in palette reordering
+acb297e9 anim_diff: add a -raw_comparison flag
+155c1b22 Merge changes I76f4d6fe,I45434639
+717e4d5a mips32/mipsDSPr2: function ImportRow rebased
+7df93893 fix rescaling bug (uninitialized read, see bug #254).
+5cdcd561 lossless_enc_neon: add VP8LTransformColor
+a53c3369 lossless_neon: add VP8LTransformColorInverse
+99131e7f Merge changes I9fb25a89,Ibc648e9e
+c4556766 simplify the main loop for downscaling
+2a010f99 lossless_neon: remove predictors 5-13
+ca221bbc ll_enc_neon: enable VP8LSubtractGreenFromBlueAndRed
+585d93db Container spec: clarify ordering of ALPH chunk.
+01d61fd9 lossless: ~20 % speedup
+f722c8f0 lossless: Speed up ComputeCacheEntropy by 40 %
+1ceecdc8 add a VP8LColorCacheSet() method for color cache
+17eb6099 lossless: Allow copying from prev row in rle-mode.
+f3a7a5bf lossless: bit writer optimization
+d97b9ff7 Merge changes from topic 'lossless-enc-improvements'
+0250dfcc msvc: fix pointer type warning in BitsLog2Floor
+52931fd5 lossless: combine the Huffman code with extra bits
+c4855ca2 lossless: Inlining add literal
+8e9c94de lossless: simplify HashChainFindCopy heuristics
+888429f4 lossless: 0.5 % compression density improvement
+7b23b198 lossless: Add zeroes into the predicted histograms.
+85b44d8a lossless: encoding, don't compute unnecessary histo
+d92453f3 lossless: Remove about 25 % of the speed degradation
+2cce0317 Faster alpha coding for webp
+5e75642e lossless: rle mode not to accept lengths smaller than 4.
+84326e4a lossless: Less code for the entropy selection
+16ab951a lossless: 0.37 % compression density improvement
+822f113e add WebPFree() to the API
+0ae2c2e4 SSE2/SSE41: optimize SSE_16xN loops
+39216e59 cosmetics: fix indent after 32462a07
+559e54ca Merge "SSE2: slightly faster FTransformWHT"
+8ef9a63b SSE2: slightly faster FTransformWHT
+f27f7735 lossless_neon: enable VP8LAddGreenToBlueAndRed
+36e9c4bc SSE2: minor cosmetrics on in-loop filter code
+4741fac4 dsp/lossless_*sse2: remove some unnecessary inlines
+1819965e fix warning ("left shift of negative value") using a cast
+70170014 SSE2: speed-up some lossless-encoding functions
+abcb0128 Merge "SSE2: slightly faster (~5%) AddGreenToBlueAndRed()"
+2df5bd30 Merge "Speedup to HuffmanCostCombinedCount"
+9e356d6b SSE2: slightly faster (~5%) AddGreenToBlueAndRed()
+fc6c75a2 SSE2: 53% faster TransformColor[Inverse]
+49073da6 SSE2: 46% speed-up of TransformColor[Inverse]
+32462a07 Speedup to HuffmanCostCombinedCount
+f3d687e3 SSE4.1 implementation of some lossless encoding functions
+bfc300c7 SSE4.1 implementation of some alpha-processing functions
+7f9c98f2 Merge "sse2 in-loop: simplify SignedShift8b() a bit"
+ef314a5d dec_sse2/GetNotHEV: micro optimization
+a729cff9 sse2 in-loop: simplify SignedShift8b() a bit
+422ec9fb simplify Load8x4() a bit
+8df238ec Merge "remove some duplicate FlipSign()"
+751506c4 remove some duplicate FlipSign()
+65ef5afc Merge "lossless: 0.13% compression density gain"
+2beef2f2 lossless: 0.13% compression density gain
+3033f24c lossless: 0.06 % compression density improvement
+64960da9 dec_neon: add VE8uv / VE16
+14dbd87b dec_neon: add HE8uv / HE16
+ac768011 introduce FTransform2 to perform two transforms at a time.
+aa6065ae dec_neon: use vld1_dup(mem) rather than vdup(mem[0])
+8b63ac78 Merge "dec_neon: add TM16"
+f51be09e Merge "dec_neon/TrueMotion: simply left border load"
+dc48196b dec_neon: add TM16
+ea95b305 dec_neon/TrueMotion: simply left border load
+f262d612 speed-up SetResidualSSE2
+bf46d0ac fix mips2 build target
+929a0fdc enc_sse2/TTransform: simplify abs calculation
+17dbd058 enc_sse2/CollectHistogram: simplify abs calculation
+a6c15936 dec_neon: add DC16 intra predictors
+03b4f50d Makefile.vc: add anim_diff build support.
+1b989874 Merge changes I9cd84125,Iee7e387f,I7548be72
+acd7b5af Introduce a test tool anim_diff.
+f274a96c dsp/enc_sse2: add luma4 intra predictors
+040b11bd dsp/enc_sse2: add chroma intra predictors
+aee021bb dsp/enc_sse2: add luma16 intra predictors
+9e00a499 makefile.unix: remove superclean target
+cefc9c09 makefile.unix: clean up after extras target
+4c9af023 dec_neon: add DC8uvNoTopLeft
+dd55b873 Merge "doc/webp-container-spec: update repo browser link"
+f0486968 doc/webp-container-spec: update repo browser link
+9287761d Merge "GetResidualCostSSE2: simplify abs calculation"
+0e009366 dsp/cpu.c(x86): check maximum supported cpuid feature
+b243a4bc GetResidualCostSSE2: simplify abs calculation
+6d4602b8 Merge "fix typo: constitutes -> constitute"
+5fe1fe37 fix typo: constitutes -> constitute
+b83bd7c4 Merge "populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions"
+b0114a32 Merge "histogram.h: cosmetics: remove unnecessary includes"
+feab45ef gifdec: Move inclusion of webp/config.h to header.
+dbba67d1 histogram.h: cosmetics: remove unnecessary includes
+e978fec6 Merge "VP8LBitReader: fix remaining ubsan error with large shifts"
+d6fe5884 Merge "ReconstructRow: move some one-time inits out of the main loop"
+a21d647c ReconstructRow: move some one-time inits out of the main loop
+7a01c3c3 VP8LBitReader: fix remaining ubsan error with large shifts
+7fa67c9b change GetPixPairHash64() return type to uint32_t
+ec1fb9f8 Merge "dsp/enc.c: cosmetics: move DST() def closer to use"
+7073bfb3 Merge "split 64-mult hashing into two 32-bit multiplies"
+0768b252 dsp/enc.c: cosmetics: move DST() def closer to use
+6a48b8f0 Merge "fix MSVC size_t->int conversion warning"
+1db07cde Merge "anim_encode: cosmetics: fix alignment"
+e28271a3 anim_encode: cosmetics: fix alignment
+7fe357b8 split 64-mult hashing into two 32-bit multiplies
+af74c145 populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions
+61214134 remove VP8Residual::cost unused field
+e2544823 fix MSVC size_t->int conversion warning
+b69a6c35 vwebp: don't redefine snprintf with VS2015+
+0ac29c51 AnimEncoder API: Consistent use of trailing underscores in struct.
+d4845550 AnimEncoder API: Use timestamp instead of duration as input to Add().
+9904e365 dsp/dec_sse2: DC8uv / DC8uvNoLeft speedup
+7df20497 dsp/dec_sse2: DC16 / DC16NoLeft speedup
+8e515dfe Merge "makefile.unix: add some missing headers"
+db12250f cosmetics: vp8enci.h: break long line
+bf516a87 makefile.unix: add some missing headers
+b44eda3f dsp: add DSP_INIT_STUB
+03e76e96 clarify the comment about double-setting the status in SetError()
+9fecdd71 remove unused EmitRGB()
+43f010dd move ReconstructRow to top
+82d98020 add a dec/common.h header to collect common enc/dec #defines
+5d4744a2 Merge "enc_sse41: add Disto4x4 / Disto16x16"
+e38886a7 mux.h: Bump up ABI version
+46305ca6 configure: add --disable-<avx2|sse4.1|sse2>
+2fc8b658 CPPFLAGS->CFLAGS for detecting sse4.1 in preprocessor
+1a338fb3 enc_sse41: add Disto4x4 / Disto16x16
+94055503 encoding SSE4.1 stub for StoreHistogram + Quantize + SSE_16xN
+c64659e1 remove duplicate variables after the lossless{_enc}.c split
+67ba7c7a enc_sse2: call local FTransform in CollectHistogram
+18249799 dsp: s/VP8LSetHistogramData/VP8SetHistogramData/
+ede5e158 cosmetics: dsp/lossless.h: reorder prototypes
+553051f7 dsp/lossless: split enc/dec functions
+9064adc8 Merge "conditionally add -msse4.1 in Makefile.unix"
+cecf5096 dsp/yuv*.c: rework WEBP_USE_<arch> ifdef
+6584d398 dsp/upsampling*.c: rework WEBP_USE_<arch> ifdef
+80809422 dsp/rescaler*.c: rework WEBP_USE_<arch> ifdef
+1d93ddec dsp/lossless*.c: rework WEBP_USE_<arch> ifdef
+73805ff2 dsp/filters*.c: rework WEBP_USE_<arch> ifdef
+fbdcef24 dsp/enc*.c: rework WEBP_USE_<arch> ifdef
+66de69c1 dsp/dec*.c: rework WEBP_USE_<arch> ifdef
+48e4ffd1 dsp/cost*.c: rework WEBP_USE_<arch> ifdef
+29fd6f90 dsp/argb*.c: rework WEBP_USE_<arch> ifdef
+80ff3813 dsp/alpha*.c: rework WEBP_USE_<arch> ifdef
+bf09cf1e conditionally add -msse4.1 in Makefile.unix
+e9570dd9 stub for SSE4.1 support.
+4a95384b Merge "dsp: add sse4.1 detection"
+cabf4bd2 dsp: add sse4.1 detection
+4ecba1ab thread.h: rename interface param
+b8d706c8 Merge "sync versions with 0.4.3"
+ae64a711 Merge "add shell for libwebpextras"
+92a5da9c sync versions with 0.4.3
+9d4e2d16 Merge "~30% faster smart-yuv (-pre 4) with early-out criterion"
+b1bdbbab ~30% faster smart-yuv (-pre 4) with early-out criterion
+7efb9748 Merge "Disable NEON code on Native Client"
+ac4f5784 Disable NEON code on Native Client
+0873f85b AnimEncoder API: Support input frames in YUV(A) format.
+5c176d2d add shell for libwebpextras
+44bd9561 fix signature for VP8RecordCoeffTokens()
+c9b8ea0e small cosmetics on TokenBuffer.
+76394c09 Merge "MIPS: dspr2: added optimization for TrueMotion"
+0f773693 WebPPictureRescale: add a note about 0 width/height
+241bb5d9 MIPS: dspr2: added optimization for TrueMotion
+6cef0e4f examples/Android.mk: add webpmux_example target
+53c16ff0 Android.mk: add webpmux target
+21852a00 Android.mk: add webpdemux target
+8697a3bc Android.mk: add webpdecoder{,_static} targets
+4a670491 Android.mk: split source lists per-directory
+b5e79422 MIPS: dspr2: Added optimization for some convert functions
+0f595db6 MIPS: dspr2: Added optimization for some convert functions
+8a218b4a MIPS: [mips32|dspr2]: GetResidualCost rebased
+ef987500 Speedup method StoreImageToBitMask by 5%.
+602a00f9 fix iOS arm64 build with Xcode 6.3
+23820507 1-2% faster encoding by removing an indirection in GetResidualCost()
+eddb7e70 MIPS: dspr2: added otpimization for DC8uv, DC8uvNoTop and DC8uvNoLeft
+73ba2915 MIPS: dspr2: added optimization for functions RD4 and LD4
+c7129da5 Merge "4-5% faster encoding using SSE2 for GetResidualCost"
+94380d00 MIPS: dspr2: added optimizaton for functions VE4 and DC4
+2a407092 4-5% faster encoding using SSE2 for GetResidualCost
+17e19862 Merge "MIPS: dspr2: added optimization for simple filtering functions"
+3ec404c4 Merge "dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage"
+b969f5df dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage
+d7b8e711 MIPS: dspr2: added optimization for simple filtering functions
+235f774e Merge "MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C"
+42a8a628 MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C
+b442bef3 Merge "ApplyFiltersAndEncode: only copy lossless stats"
+b510fbfe doc/webp-container-spec: note MSB order for chunk diagrams
+9bc0f922 ApplyFiltersAndEncode: only copy lossless stats
+3030f115 Merge "dsp/mips: add some missing TSan annotations"
+dfcf4593 Merge "MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C"
+55c75a25 dsp/mips: add some missing TSan annotations
+2cb879f0 MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C
+e1556010 move some cost tables from enc/ to dsp/
+c3a03168 Merge "picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined"
+39537d7c Merge "VP8LDspInitMIPSdspR2: add missing TSan annotation"
+1dd419ce picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined
+43fd3543 VP8LDspInitMIPSdspR2: add missing TSan annotation
+c7233dfc Merge "VP8LDspInit: remove memcpy"
+0ec4da96 picture_csp::InitGammaTables*: add missing TSan annotations
+35579a49 VP8LDspInit: remove memcpy
+97f6aff8 VP8YUVInit: add missing TSan annotation
+f9016d66 dsp/enc::InitTables: add missing TSan annotation
+e3d9771a VP8EncDspCostInit*: add missing TSan annotations
+d97c143d Merge "doc/webp-container-spec: cosmetics"
+309b7908 MIPS: mips32: Added optimization for function SetResidualCoeffs
+a987faed MIPS: dspr2: added optimization for function GetResidualCost
+e7d3df23 doc/webp-container-spec: cosmetics
+be6635e9 Merge "VP8TBufferClear: remove some misleading const's"
+02971e72 Merge "VP8EmitTokens: remove unnecessary param void cast"
+3b77e5a7 VP8TBufferClear: remove some misleading const's
+aa139c8f VP8EmitTokens: remove unnecessary param void cast
+c24d8f14 cosmetics: upsampling_sse2: add const to some casts
+1829c42c cosmetics: lossless_sse2: add const to some casts
+183168f3 cosmetics: enc_sse2: add const to some casts
+860badca cosmetics: dec_sse2: add const to some casts
+0254db97 cosmetics: argb_sse2: add const to some casts
+1aadf856 cosmetics: alpha_processing_sse2: add const to some casts
+1579de3c vwebp: clear canvas at the beginning of each loop
+4b9fa5d0 Merge "webp-container-spec: clarify background clear on loop"
+4c82284d Updated the near-lossless level mapping.
+56039479 webp-container-spec: clarify background clear on loop
+19f0ba0e Implement true-motion prediction in SSE2
+774d4cb7 make VP8PredLuma16[] array non-const
+d7eabb80 Merge "MIPS: dspr2: Added optimization for function CollectHistogram"
+fe42739c Use integers for kmin/kmax for simplicity.
+b9df35f7 AnimEncode API: kmax=0 should imply all keyframes.
+6ce296da MIPS: dspr2: Added optimization for function CollectHistogram
+2c906c40 vwebp: remove unnecessary static Help() prototype
+be0fd1d5 Merge "dec/vp8: clear 'dither_' on skipped blocks"
+e96170fe Merge "vwebp/animation: display last frame on end-of-loop"
+0f017b56 vwebp/animation: display last frame on end-of-loop
+c86b40cc enc/near_lossless.c: fix alignment
+66935fb9 dec/vp8: clear 'dither_' on skipped blocks
+b7de7946 Merge "lossless_neon: enable subtract green for aarch64"
+77724f70 SSE2 version of GradientUnfilter
+416e1cea lossless_neon: enable subtract green for aarch64
+72831f6b Speedup AnalyzeAndInit for low effort compression.
+a6597483 Speedup Analyze methods for lossless compression.
+98c81386 Enable Near-lossless feature.
+c6b24543 AnimEncoder API: Fix for kmax=1 and default kmin case.
+022d2f88 add SSE2 variants for alpha filtering functions
+2db15a95 Temporarily disable encoding of alpha plane with color cache.
+1d575ccd Merge "Lossless decoding: Remove an unnecessary if condition."
+cafa1d88 Merge "Simplify backward refs calculation for low-effort."
+7afdaf84 Alpha coding: reorganize the filter/unfiltering code
+4d6d7285 Simplify backward refs calculation for low-effort.
+ec0d1be5 Cleaup Near-lossless code.
+9814ddb6 Remove the post-transform near-lossless heuristic.
+4509e32e Lossless decoding: Remove an unnecessary if condition.
+f2ebc4a8 Merge "Regression fix for lossless decoding"
+783a8cda Regression fix for lossless decoding
+9a062b8e AnimEncoder: Bugfix for kmin = 1 and kmax = 2.
+0f027a72 simplify smart RGB->YUV conversion code
+0d5b334e BackwardReferencesHashChainFollowChosenPath: remove unused variable
+f480d1a7 Fix to near lossless artefacts on palettized images.
+d4615d08 Merge changes Ia1686828,I399fda40
+cb4a18a7 rename HashChainInit into HashChainReset
+f079e487 use uint16_t for chosen_path[]
+da091212 MIPS: dspr2: Added optimization for function FTransformWHT
+b8c20135 Merge "wicdec: (msvs) quiet some /analyze warnings"
+9b228b54 wicdec: (msvs) quiet some /analyze warnings
+daeb276a Merge "MIPS: dspr2: Added optimization for MultARGBRow function"
+cc087424 Merge "dsp/cpu: (msvs) add include for __cpuidex"
+4a82aab5 Merge changes I87544e92,I0bb6cda5
+7a191398 dwebp/WritePNG: mark png variables volatile
+775dfad2 dwebp: include setjmp.h w/WEBP_HAVE_PNG
+47d26be7 dwebp: correct sign in format strings
+f0e0677b VP8LEncodeStream: add an assert
+c5f7747f VP8LColorCacheCopy: promote an int before shifting
+0de5f33e dsp/cpu: (msvs) add include for __cpuidex
+7d850f7b MIPS: dspr2: Added optimization for MultARGBRow function
+54875293 MIPS: dspr2: added optimization for function QuantizeBlock
+4fbe9cf2 dsp/cpu: (msvs) avoid immintrin.h on _M_ARM
+3fd59039 simplify/reorganize arguments for CollectColorBlueTransforms
+b9e356b9 Disable costly TraceBackwards for method=0.
+a7e7caa4 MIPS: dspr2: added optimization for function TransformColorRed
+2cb39180 Merge "MIPS: dspr2: added optimization for function TransformColorBlue"
+279e6613 Merge "dsp/cpu: add include for _xgetbv() w/MSVS"
+b6c0428e dsp/cpu: add include for _xgetbv() w/MSVS
+d1c4ffae gif2webp: Move GIF decoding related code to a support library.
+07c39559 Merge "AnimEncoder API: Add info in README.mux"
+7b161973 MIPS: dspr2: added optimization for function TransformColorBlue
+d7c4b02a cpu: fix AVX2 detection for gcc/clang targets
+9d299469 AnimEncoder API: Add info in README.mux
+d581ba40 follow-up: clean up WebPRescalerXXX dsp function
+f8740f0d dsp: s/USE_INTRINSICS/WEBP_USE_INTRINSICS/
+ce73abe0 Merge "introduce a separate WebPRescalerDspInit to initialize pointers"
+ab66beca introduce a separate WebPRescalerDspInit to initialize pointers
+205c7f26 fix handling of zero-sized partition #0 corner case
+cbcdd5ff Merge "move rescaler functions to rescaler* files in src/dsp/"
+bf586e88 Merge changes I230b3532,Idf3057a7
+6dc79dc2 Merge "anim_encode: fix type conversion warnings"
+11fce25a Merge "dec_neon: remove returns from void functions"
+c4e63f99 Makefile.vc: add gif2webp target
+4f43d38c enable NEON for Windows ARM builds
+3f6615ac Makefile.vc: add rudimentary Windows ARM support
+e7c5954c dec_neon: remove returns from void functions
+f79c163b anim_encode: fix type conversion warnings
+0f54f1ec Remove gif2webp_util which is no longer needed.
+cbcbedd0 move rescaler functions to rescaler* files in src/dsp/
+ac79ed19 webpmux: remove experimental fragment handling
+e8694d4d mux: remove experimental FRGM parsing
+9e92b6ea AnimEncoder API: Optimize single-frame animated images
+abbae279 Merge "Move over gif2webp to the new AnimEncoder API."
+a28c4b36 MIPS: move WORK_AROUND_GCC define to appropriate place
+012d2c60 MIPS: dspr2: added optimization for functions SSEAxB
+67720c8b Move over gif2webp to the new AnimEncoder API.
+9241ecf4 MIPS: dspr2: added optimization for function Average
+9422211d Merge "Tune BackwardReferencesLz77 for low_effort (m=0)."
+df40057b Merge "Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode."
+ea08466d Tune BackwardReferencesLz77 for low_effort (m=0).
+b0b973c3 Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode.
+c6d32927 argb_sse2: cosmetics
+67f601cd make the 'last_cpuinfo_used' variable names unique
+b9489861 AnimEncoder API: Init method for default options.
+856f8ec1 Merge "AnimEncoder API: Remove AnimEncoderFrameOptions."
+c537514d Merge "AnimEncoder API: GenerateCandidates bugfix."
+dc0ce039 Merge "AnimEncoder API: Compute change rectangle for first frame too."
+f00b639b Merge "AnimEncoder API: In Assemble(), always set animation parameters."
+29ed796c Merge "AnimEncoder lib cleanup: prev to prev canvas not needed."
+9f0dd6e5 Merge "WebPAnimEncoder API: Header and implementation"
+5e56bbe0 AnimEncoder API: Remove AnimEncoderFrameOptions.
+b902c3ea AnimEncoder API: GenerateCandidates bugfix.
+ef3c39bb AnimEncoder API: Compute change rectangle for first frame too.
+eec423ab AnimEncoder API: In Assemble(), always set animation parameters.
+ae1c046e AnimEncoder lib cleanup: prev to prev canvas not needed.
+4b997ae4 WebPAnimEncoder API: Header and implementation
+72208bec move argb_*.o build target to encoder list
+95920538 Merge "multi-thread fix: lock each entry points with a static var"
+4c1b300a Merge "SSE2 implementation of VP8PackARGB"
+fbcc2004 Merge "add -Wformat-nonliteral and -Wformat-security"
+80d950d9 add -Wformat-nonliteral and -Wformat-security
+04c20e75 Merge "MIPS: dspr2: added optimization for function Intra4Preds"
+a437694a multi-thread fix: lock each entry points with a static var
+ca7f60db SSE2 implementation of VP8PackARGB
+72d573f6 simplify the PackARGB signature
+4e2589ff demux: restore strict fragment flag check
+4ba8e074 Merge "webp-container-spec: remove references to fragments"
+e752f0a6 Merge "demux: remove experimental FRGM parsing"
+f8abb112 Merge changes I109ec4d9,I73fe7743
+ae2188a4 MIPS: dspr2: added optimization for function Intra4Preds
+1f4b8642 move VP8EncDspARGBInit() call closer to where it's needed
+14108d78 dec_neon: add DC8uvNoTop / DC8uvNoLeft
+d8340da7 dec_neon: add DC8uv
+a66e66c7 webp-container-spec: remove references to fragments
+7ce8788b MIPS: dspr2: added optimization for function MakeARGB32
+012e623d demux: remove experimental FRGM parsing
+87c3d531 method=0: Don't evaluate any predictor
+6f4fcb98 Merge "MIPS: dspr2: added optimization for function ImportRow"
+24284459 replace unneeded calls to HistogramCopy() by swaps
+bdf7b40c MIPS: dspr2: added optimization for function ImportRow
+e66a9225 Merge "MIPS: dspr2: added optimization for function ExportRowC"
+c279fec1 MIPS: dspr2: added optimization for function ExportRowC
+31a9cf64 Speedup WebP lossless compression for low effort (m=0) mode with following: - Disable Cross-Color transform. - Evaluate predictors #11 (paeth), #12 and #13 only.
+9275d91c MIPS: dspr2: added optimization for function TrueMotion
+26106d66 Merge "enc_neon: fix building with non-Xcode clang (iOS)"
+1c4e3efe unroll the kBands[] indirection to remove a dereference in GetCoeffs()
+a3946b89 enc_neon: fix building with non-Xcode clang (iOS)
+8ed9c00d Merge "simplify the Histogram struct, to only store max_value and last_nz"
+bad77571 simplify the Histogram struct, to only store max_value and last_nz
+3cca0dc7 MIPS: dspr2: Added optimization for DCMode function
+37e395fd MIPS: fix functions to use generic BPS istead of hardcoded value
+9475bef4 PickBestUV: fix VP8Copy16x8 invocation
+441f273f Merge changes I55f8da52,Id73a1e96
+4a279a68 cosmetics: add some missing != NULL comparisons
+66ad3725 factorize BPS definition in dsp.h and add VP8Copy16x8
+432e5b55 make ALIGN_xxx naming consistent
+57606047 encoder: switch BPS to 32 instead of 16
+1b66bbe9 MIPS: dspr2: added optimization for function TransformColor_C
+c6d0f9e7 histogram: cosmetics
+f399d307 Merge changes I6eac17e5,I32d2b514
+9de9074c dec_neon: add TM8uv
+8e517eca bit_reader/kVP8NewRange: range_t -> uint8_t
+e1857139 dsp: initialize VP8PredChroma8 in VP8DspInit()
+e0c809ad Move Entropy methods to lossless.c
+a96ccf8f iosbuild: add x64_64 simulator support
+a0df5510 Remove handling for WEBP_HINT_GRAPH
+413dfc0c Move static method definition before its usage.
+0f235665 Update BackwardRefsWithLocalCache.
+d69e36ec Remove TODOs from lossless encoder code.
+fdaac8e0 Optmize VP8LGetBackwardReferences LZ77 references.
+2f0e2ba8 MIPS: dspr2: added optimization for function Select
+a3e79a46 Merge "WebPEncode: Support encoding same pic twice (even if modified)"
+e4f4dddb WebPEncode: Support encoding same pic twice (even if modified)
+cbc3fbb4 Merge "Updated VP8LGetBackwardReferences and color cache."
+95a9bd85 Updated VP8LGetBackwardReferences and color cache.
+54f2c14c MIPS: dspr2: added optimization for function FTransform
+aa42f423 MIPS: dspr2: Added optimization for function VP8LSubtractGreenFromBlueAndRed
+11a25f75 Merge "FlattenSimilarBlocks should only be tried when blending is possible."
+5cccdadf FlattenSimilarBlocks should only be tried when blending is possible.
+95ca44a7 MIPS: dspr2: added optimization for Disto4x4
+4171b672 backward_references.c: reindent after c8581b0
+c8581b06 Optimize BackwardReferences for RLE encoding.
+5798eee6 MIPS: dspr2: unfilters bugfix (Ie7b7387478a6b5c3f08691628ae00f059cf6d899)
+4167a3f5 Optimize backwardreferences
+d18554c3 Merge "webp/types.h: use inline for clang++/-std=c++11"
+7489b0e7 gif2webp: Add '-min-size' option to get best compression.
+77bdddf0 Speed up BackwardReferences
+6638710b webp/types.h: use inline for clang++/-std=c++11
+abf04205 Enable entropy based merge histo for (q<100)
+572022a3 filters_mips_dsp_r2.c: disable unfilters
+a28e21b1 MIPS: dspr2: Added optimization for function ClampedAddSubtractFull
+18d5a1ef MIPS: dspr2: added optimization for function ClampedAddSubtractHalf
+829a8c19 MIPS: dspr2: added optimization for ITransform
+c94ed49e gif2webp: Use the default hint instead of WEBP_HINT_GRAPH.
+653ace55 Increase the MAX_COLOR_CACHE_BITS from 9 to 10.
+919220c7 Change the logic adjusting the Histogram bits.
+53b096c0 Merge "Fix bug in VP8LCalculateEstimateForCacheSize."
+e912bd55 Fix bug in VP8LCalculateEstimateForCacheSize.
+541d7839 Merge "dec_neon: add RD4 intra predictor"
+f8cd0672 Merge "Makefile.vc: add a 'legacy' RTLIBCFG option"
+22881c99 dec_neon: add RD4 intra predictor
+613d281e update NEWS
+1304eb34 Merge "dec_neon: DC4: use pair-wise adds for top row"
+34c20c06 Makefile.vc: add a 'legacy' RTLIBCFG option
+7083006b Merge "dsp/dec_{neon,sse2}: VE4: normalize variable names"
+0db9031c dsp/dec_{neon,sse2}: VE4: normalize variable names
+b5bc1530 dec_neon: DC4: use pair-wise adds for top row
+5b90d8fe Unify the API between VP8BitWriter and VP8LBitWriter
+f7ada560 Merge changes I2e06907b,Ia9ed4ca6,I782282ff
+5beb6bf0 Merge "dec_neon: add VE4 intra predictor"
+eba6ce06 dec_neon: add DC4 intra predictor
+79abfbd9 dec_neon: add TM4 intra predictor
+fe395f0e dec_neon: add LD4 intra predictor
+32de385e dec_neon: add VE4 intra predictor
+72395ba9 Merge "Modify CostModel to allocate optimal memory."
+65e5eb8a gif2webp: Support GIF_DISPOSE_RESTORE_PREVIOUS
+e4c829ef gif2webp: Handle frames with odd offsets + disposal to background.
+c2b5a039 Modify CostModel to allocate optimal memory.
+b7a33d7e implement VE4/HE4/RD4/... in SSE2
+97c76f1f make VP8PredLuma4[] non-const and initialize array in VP8DspInit()
+0ea8c6c2 Merge "PrintReg: output to stderr"
+d7ff2f97 Merge "stopwatch.h: fix includes"
+f85ec712 PrintReg: output to stderr
+54edbf65 stopwatch.h: fix includes
+139142e4 Optimize BackwardReferenceHashChainFollowPath.
+5f36b68d enc/backward_references.c: fix indent
+e0e9960d Merge "sync version numbers to 0.4.2 release"
+64ac5144 sync version numbers to 0.4.2 release
+c24f8954 Simplify and speedup Backward refs computation.
+d1c359ef fix shared object build with -fvisibility=hidden
+a4c3a31b WEBP_TSAN_IGNORE_FUNCTION: fix gcc compat warning
+f358eeb8 add code for testing random incremental decoding in dwebp
+80247291 mark some init function as being safe for thread_sanitizer.
+79b5bdbf bit_reader.h: cosmetics: fix a typo
+6c673681 Improved near-lossless mode.
+0ce27e71 enc_mips32: workaround gcc-4.9 bug
+aca1b98f enc/vp8l.c: fix indent
+ca005027 Evaluate non-palette compression for palette image
+c8a87bb6 AssignSegments: quiet -Warray-bounds warning
+32f67e30 Merge "enc_neon: initialize vectors w/vdup_n_u32"
+fabc65da 1-3% faster encoding optimizing SSE_NxN functions
+7534d716 enc_neon: initialize vectors w/vdup_n_u32
+5f813912 Merge "Fix return code of EncodeImageInternal()"
+e321abe4 Fix return code of EncodeImageInternal()
+f82cb06a optimize palette ordering
+f545feee don't set the alpha value for histogram index image
+2d9b0a44 add WebPDispatchAlphaToGreen() to dsp
+1bd4c2ad Merge "Change Entropy based Histogram Combine heuristic."
+e295b8f1 Merge "iosbuild: cleanup"
+1be4e760 Merge "iosbuild: output autoconf req. on failure"
+d5e498d4 Change Entropy based Histogram Combine heuristic.
+47a2d8e1 fix MSVC float->int conversion warning
+041956f6 iosbuild: cleanup
+767eb402 iosbuild: output autoconf req. on failure
+35ad48b8 HistoHeapInit: correct positions allocation size
+45d9635f lossless: entropy clustering for high qualities.
+dc37df8c fix type warning for VS9_x64
+9f7d9e6d iosbuild: make iOS 6 the minimum requirement
+fdd6528b Remove unused VP8LDecoder member variable
+ea3bba5a Merge "rewrite Disto4x4 in enc_neon.c with intrinsic"
+f060dfc4 add lossless incremental decoding support
+ab70794d rewrite Disto4x4 in enc_neon.c with intrinsic
+d4471637 MIPS: dspr2: added optimization for function FilterLoop24
+2aef54d4 Merge "prepare VP8LDecodeImage for incremental decode"
+aed0f5a2 Merge "MIPS: dspr2: added optimization for function FilterLoop26"
+28630685 prepare VP8LDecodeImage for incremental decode
+248f3aed remove br->error_ field
+49e15044 MIPS: dspr2: added optimization for function FilterLoop26
+38128cb9 iobuild.sh: only install .h files in Headers
+c792d412 Premultiply with alpha during U/V downsampling
+0cc811d7 gif2webp: Background color correction
+d7167ff7 Amend the lossless spec according to issue #205, #206 and #224
+b901416b Record the lossless size stats.
+cddd3340 Add a WebPExtractAlpha function to dsp
+0716a98e fix indent after I0204949917836f74c0eb4ba5a7f4052a4797833b
+f9ced95a Optimize lossless decoding for trivial(ARB) codes.
+924fcfd9 Merge "webpmux: simplify InitializeConfig()"
+c0a462ca webpmux: simplify InitializeConfig()
+6986bb5e webpmux: fix indent
+f89e1690 webpmux: fix exit status on numeric value parse error
+2172cb62 Merge "webpmux: fix loop_count range check"
+e3b343ec Merge "examples: warn on invalid numeric parameters"
+0e23c487 webpmux: fix loop_count range check
+6208338a Merge "fix loop bug in DispatchAlpha()"
+d51f3e40 gif2webp: Handle frames with missing graphic control extension
+690b491a fix loop bug in DispatchAlpha()
+96d43a87 examples: warn on invalid numeric parameters
+3101f537 MIPS: dspr2: added optimization for TransformOne
+a6bb9b17 SSE2 for inverse Mult(ARGB)Row and ApplyAlphaMultiply
+d84a8ffd Remove default initialization of decoder status.
+be70b86c configure: simplify libpng-config invocation
+e0a99321 Rectify bug in lossless incremental decoding.
+e2502a97 MIPS: dspr2: added optimization for TransformAC3
+24e1072a MIPS: dspr2: added optimization for TransformDC
+c0e84df8 Merge "Slightly faster lossless decoding (1%)"
+8dd28bb5 Slightly faster lossless decoding (1%)
+f0103595 MIPS: dspr2: added optimization for ColorIndexInverseTransforms
+d3242aee make VP8LSetBitPos() set br->eos_ flag
+a9decb55 Lossless decoding: fix eos_ flag condition
+3fea6a28 fix erroneous dec->status_ setting
+80b8099f MIPS: dspr2: add some specific mips code to commit I2c3f2b12f8df15b785fad5a9c56316e954ae0c53
+e5640625 Merge "further refine the COPY_PATTERN optim for DecodeAlpha"
+854509fe enc/histogram.c: reindent after f4059d0
+34421964 Merge "~3-5% faster encoding optimizing PickBestIntra*()"
+865069c1 further refine the COPY_PATTERN optim for DecodeAlpha
+a5956228 added C-level optimization for DecodeAlphaData function
+187d379d add a fallback to ALPHA_NO_COMPRESSION
+a48a2d76 ~3-5% faster encoding optimizing PickBestIntra*()
+a6140194 ExUtilReadFromStdin: (windows) open stdin in bin mode
+e80eab1f webpmux: (windows) open stdout in binary mode
+e9bfb116 cwebp: (windows) open stdout in binary mode
+5927e15b example_util: add ExUtilSetBinaryMode
+30f3b75b webpmux man page: Clarify some title, descriptions and examples
+77d4c7e3 address cosmetic comments from patch #71380
+f75dfbf2 Speed up Huffman decoding for lossless
+637b3888 dsp/lossless: workaround gcc-4.9 bug on arm
+8323a903 dsp.h: collect gcc/clang version test macros
+e6c4b52f move static initialization of WebPYUV444Converters[] to the Init function.
+49911d4d Merge "fix indentation"
+f4059d0c Code cleanup for HistogramRemap.
+e632b092 fix indentation
+f5c04d64 Merge "add a DispatchAlpha() for SSE2 that handles 8 pixels at a time"
+fc98edd9 add a DispatchAlpha() for SSE2 that handles 8 pixels at a time
+73d361dd introduce VP8EncQuantize2Blocks to quantize two blocks at a time
+0b21c30b MIPS: dspr2: added optimization for EmitAlphaRGB
+953acd56 enc_neon: enable QuantizeBlock for aarch64
+f4ae1437 MIPS: mips32: code rebase
+56977154 MIPS: dspr2: added optimizations for VP8YuvTo*
+2523aa73 SmartRGBYUV: fix odd-width problem with pixel replication
+ee52dc4e fix some MSVC64 warning about float conversion
+3fca851a cpu: check for _MSC_VER before using msvc inline asm
+e2a83d71 faster RGB->YUV conversion function (~7% speedup)
+de2d03e1 Merge "Add smart RGB->YUV conversion option -pre 4"
+3fc4c539 Add smart RGB->YUV conversion option -pre 4
+b4dc4069 MIPS: dspr2: added optimization for (un)filters
+137e6090 Merge "configure: add work around for gcc-4.9 aarch64 bug"
+b61c9cec MIPS: dspr2: Optimization of some simple point-sampling functions
+e2b8cec0 configure: add work around for gcc-4.9 aarch64 bug
+98c54107 MIPS: mips32r2: added optimization for BSwap32
+dab702b3 Update PATENTS to reflect s/VP8/WebM/g
+b564f7c7 Merge "MIPS: detect mips32r6 and disable mips32r1 code"
+b7e5a5c4 MIPS: detect mips32r6 and disable mips32r1 code
+63c2fc02 Correctly use the AC_CANONICAL_* macros
+bb07022b Merge "cosmetics"
+e300c9d8 cosmetics
+0e519eea Merge "cosmetics: remove some extraneous 'extern's"
+3ef0f08a Merge "vp8enci.h: cosmetics: fix '*' placement"
+4c6dde37 bit_writer: cosmetics: rename kFlush() -> Flush()
+f7b4c48b cosmetics: remove some extraneous 'extern's
+b47fb00a vp8enci.h: cosmetics: fix '*' placement
+b5a36cc9 add -near_lossless [0..100] experimental option
+0524d9e5 dsp: detect mips64 & disable mips32 code
+d3485d96 cwebp.1: fix quality description placement
+29a9fe22 Merge tag 'v0.4.1'
+8af27718 update ChangeLog (tag: v0.4.1, origin/0.4.1)
+e09e9ff6 Record & log the image pre-processing time.
+f59c0b4b iosbuild.sh: specify optimization flags
+8d34ea3e update ChangeLog (tag: v0.4.1-rc1)
+dbc3da66 makefile.unix: add vwebp.1 to the dist target
+89a7c83c update ChangeLog
+ffe67ee9 Merge "update NEWS for the next release" into 0.4.1
+2def1fe6 gif2webp: dust up the help message
+fb668d78 remove -noalphadither option from README/vwebp.1
+e49f693b update NEWS for the next release
+cd013580 Merge "update AUTHORS" into 0.4.1
+268d01eb update AUTHORS
+85213b9b bump version to 0.4.1
+695f80ae Merge "restore mux API compatibility" into 0.4.1
+862d296c restore mux API compatibility
+8f6f8c5d remove the !WEBP_REFERENCE_IMPLEMENTATION tweak in Put8x8uv
+d713a696 Merge changes If4debc15,I437a5d5f into 0.4.1
+c2fc52e4 restore encode API compatibility
+793368e8 restore decode API compatibility
+b8984f31 gif2webp: fix compile with giflib 5.1.0
+222f9b1a gif2webp: simplify giflib version checking
+d2cc61b7 Extend MakeARGB32() to accept Alpha channel.
+4595b62b Merge "use explicit size of kErrorMessages[] arrays"
+157de015 Merge "Actuate memory stats for PRINT_MEMORY_INFO"
+fbda2f49 JPEG decoder: delay conversion to YUV to WebPEncode() call
+0b747b1b use explicit size of kErrorMessages[] arrays
+3398d81a Actuate memory stats for PRINT_MEMORY_INFO
+6f3202be Merge "move WebPPictureInit to picture.c"
+6c347bbb move WebPPictureInit to picture.c
+fb3acf19 fix configure message for multi-thread
+40b086f7 configure: check for _beginthreadex
+1549d620 reorder the YUVA->ARGB and ARGB->YUVA functions correctly
+c6461bfd Merge "extract colorspace code from picture.c into picture_csp.c"
+736f2a17 extract colorspace code from picture.c into picture_csp.c
+645daa03 Merge "configure: check for -Wformat-security"
+abafed86 configure: check for -Wformat-security
+fbadb480 split monolithic picture.c into picture_{tools,psnr,rescale}.c
+c76f07ec dec_neon/TransformAC3: initialize vector w/vcreate
+bb4fc051 gif2webp: Allow single-frame animations
+46fd44c1 thread: remove harmless race on status_ in End()
+5a1a7264 Merge "configure: check for __builtin_bswapXX()"
+6781423b configure: check for __builtin_bswapXX()
+6450c48d configure: fix iOS builds
+6422e683 VP8LFillBitWindow: enable fast path for 32-bit builds
+4f7f52b2 VP8LFillBitWindow: respect WEBP_FORCE_ALIGNED
+e458badc endian_inl.h: implement htoleXX with BSwapXX
+f2664d1a endian_inl.h: add BSwap16
+6fbf5345 Merge "configure: add --enable-aligned"
+dc0f479d configure: add --enable-aligned
+9cc69e2b Merge "configure: support WIC + OpenGL under mingw64"
+257adfb0 remove experimental YUV444 YUV422 and YUV400 code
+10f4257c configure: support WIC + OpenGL under mingw64
+380cca4f configure.ac: add AC_C_BIGENDIAN
+ee70a901 endian_inl.h: add BSwap64
+47779d46 endian_inl.h: add BSwap32
+d5104b1f utils: add endian_inl.h
+58ab6224 Merge "make alpha-detection loop in IsKeyFrame() in good x/y order"
+9d562902 make alpha-detection loop in IsKeyFrame() in good x/y order
+516971b1 lossless: Remove unaligned read warning
+b8b596f6 Merge "configure.ac: add an autoconf version prerequisite"
+34b02f8c configure.ac: add an autoconf version prerequisite
+e59f5360 neon: normalize vdup_n_* usage
+6ee7160d Merge changes I0da7b3d3,Idad2f278,I4accc305
+abc02f24 Merge "fix (uncompiled) typo"
+bc03670f neon: add INIT_VECTOR4
+6c1c632b neon: add INIT_VECTOR3
+dc7687e5 neon: add INIT_VECTOR2
+4536e7c4 add WebPMuxSetCanvasSize() to the mux API
+824eab10 fix (uncompiled) typo
+1f3e5f1e remove unused 'shift' argument and QFIX2 define
+8e867051 Merge "VP8LoadNewBytes: use __builtin_bswap32 if available"
+1b6a2635 Merge "Fix handling of weird GIF with canvas dimension 0x0"
+1da3d461 VP8LoadNewBytes: use __builtin_bswap32 if available
+1582e402 Fix handling of weird GIF with canvas dimension 0x0
+b8811dac Merge "rename interface -> winterface"
+db8b8b5f Fix logic in the GIF LOOP-detection parsing
+25aaddc8 rename interface -> winterface
+5584d9d2 make WebPSetWorkerInterface() check its arguments
+a9ef7ef9 Merge "cosmetics: update thread.h comments"
+c6af9991 Merge "dust up the help message"
+0a8b8863 dust up the help message
+a9cf3191 cosmetics: update thread.h comments
+27bfeee4 QuantizeBlock SSE2 Optimization:
+2bc0dc3e Merge "webpmux: warn when odd frame offsets are used"
+3114ebe4 Merge changes Id8edd3c1,Id418eb96,Ide05e3be
+c0726634 webpmux: warn when odd frame offsets are used
+c5c6b408 Merge "add alpha dithering for lossy"
+d5146784 examples/Android.mk: add cwebp
+ca0fa7c7 Android.mk: move dwebp to examples/Android.mk
+73d8fca0 Android.mk: add ENABLE_SHARED flag
+6e93317f muxread: fix out of bounds read
+8b0f6a48 Makefile.vc: fix CFLAGS assignment w/HAVE_AVX2=1
+bbe32df1 add alpha dithering for lossy
+79020767 Merge "make error-code reporting consistent upon malloc failure"
+77bf4410 make error-code reporting consistent upon malloc failure
+7a93c000 **/Makefile.am: remove unused AM_CPPFLAGS
+24e30805 Add an interface abstraction to the WebP worker thread implementation
+d6cd6358 Merge "fix orig_rect==NULL case"
+2bfd1ffa fix orig_rect==NULL case
+059e21c1 Merge "configure: move config.h to src/webp/config.h"
+f05fe006 properly report back encoding error code in WebPFrameCacheAddFrame()
+32b31379 configure: move config.h to src/webp/config.h
+90090d99 Merge changes I7c675e51,I84f7d785
+ae7661b3 makefiles: define WEBP_HAVE_AVX2 when appropriate
+69fce2ea remove the special casing for res->first in VP8SetResidualCoeffs
+6e61a3a9 configure: test for -msse2
+b9d2efc6 rename upsampling_mips32.c to yuv_mips32.c
+bdfeebaa dsp/yuv: move sse2 functions to yuv_sse2.c
+46b32e86 Merge "configure: set WEBP_HAVE_AVX2 when available"
+88305db4 Merge "VP8RandomBits2: prevent signed int overflow"
+73fee88c VP8RandomBits2: prevent signed int overflow
+db4860b3 enc_sse2: prevent signed int overflow
+3fdaf4d2 Merge "real fix for longjmp warning"
+385e3340 real fix for longjmp warning
+230a0555 configure: set WEBP_HAVE_AVX2 when available
+a2ac8a42 restore original value_/range_ field order
+5e2ee56f Merge "remove libwebpdspdecode dep on libwebpdsp_avx2"
+61362db5 remove libwebpdspdecode dep on libwebpdsp_avx2
+42c447ae Merge "lossy bit-reader clean-up:"
+479ffd8b Merge "remove unused #include's"
+9754d39a Merge "strong filtering speed-up (~2-3% x86, ~1-2% for NEON)"
+158aff9b remove unused #include's
+09545eea lossy bit-reader clean-up:
+ea8b0a17 strong filtering speed-up (~2-3% x86, ~1-2% for NEON)
+6679f899 Optimize VP8SetResidualCoeffs.
+ac591cf2 fix for gcc-4.9 warnings about longjmp + local variables
+4dfa86b2 dsp/cpu: NaCl has no support for xgetbv
+4c398699 Merge "cwebp: fallback to native webp decode in WIC builds"
+33aa497e Merge "cwebp: add some missing newlines in longhelp output"
+c9b340a2 fix missing WebPInitAlphaProcessing call for premultiplied colorspace output
+57897bae Merge "lossless_neon: use vcreate_*() where appropriate"
+6aa4777b Merge "(enc|dec)_neon: use vcreate_*() where appropriate"
+0d346e41 Always reinit VP8TransformWHT instead of hard-coding
+7d039fc3 cwebp: fallback to native webp decode in WIC builds
+d471f424 cwebp: add some missing newlines in longhelp output
+bf0e0030 lossless_neon: use vcreate_*() where appropriate
+9251c2f6 (enc|dec)_neon: use vcreate_*() where appropriate
+399b916d lossy decoding: correct alpha-rescaling for YUVA format
+78c12ed8 Merge "Makefile.vc: add rudimentary avx2 support"
+dc5b122f try to remove the spurious warning for static analysis
+ddfefd62 Makefile.vc: add rudimentary avx2 support
+a8911643 Merge "simplify VP8LInitBitReader()"
+fdbcd44d simplify VP8LInitBitReader()
+7c004287 makefile.unix: add rudimentary avx2 support
+515e35cf Merge "add stub dsp/enc_avx2.c"
+a05dc140 SSE2: yuv->rgb speed-up for point-sampling
+178e9a69 add stub dsp/enc_avx2.c
+1b99c09c Merge "configure: add a test for -mavx2"
+fe728071 configure: add a test for -mavx2
+e46a247c cpu: fix check for __cpuidex availability
+176fda26 fix the bit-writer for lossless in 32bit mode
+541784c7 dsp.h: add a check for AVX2 / define WEBP_USE_AVX2
+bdb151ee dsp/cpu: add AVX2 detection
+ab9f2f86 Merge "revamp the point-sampling functions by processing a full plane"
+a2f8b289 revamp the point-sampling functions by processing a full plane
+ef076026 use decoder's DSP functions for autofilter
+2b5cb326 Merge "dsp/cpu: add AVX detection"
+df08e67e dsp/cpu: add AVX detection
+e2f405c9 Merge "clean-up and slight speed-up in-loop filtering SSE2"
+f60957bf clean-up and slight speed-up in-loop filtering SSE2
+9fc3ae46 .gitattributes: treat .ppm as binary
+3da924b5 Merge "dsp/WEBP_USE_NEON: test for __aarch64__"
+c7164490 Android.mk: always include *_neon.c in the build
+a577b23a dsp/WEBP_USE_NEON: test for __aarch64__
+54bfffca move RemapBitReader() from idec.c to bit_reader code
+34168ecb Merge "remove all unused layer code"
+f1e77173 remove all unused layer code
+b0757db7 Code cleanup for VP8LGetHistoImageSymbols.
+5fe628d3 make the token page size be variable instead of fixed 8192
+f948d08c memory debug: allow setting pre-defined malloc failure points
+ca3d746e use block-based allocation for backward refs storage, and free-lists
+1ba61b09 enable NEON intrinsics in aarch64 builds
+b9d2bb67 dsp/neon.h: coalesce intrinsics-related defines
+b5c75258 iosbuild: add support for iOSv7/aarch64
+9383afd5 Reduce number of memory allocations while decoding lossless.
+888e63ed Merge "dsp/lossless: prevent signed int overflow in left shift ops"
+8137f3ed Merge "instrument memory allocation routines for debugging"
+2aa18736 instrument memory allocation routines for debugging
+d3bcf72b Don't allocate VP8LHashChain, but treat like automatic object
+bd6b8619 dsp/lossless: prevent signed int overflow in left shift ops
+b7f19b83 Merge "dec/vp8l: prevent signed int overflow in left shift ops"
+29059d51 Merge "remove some uint64_t casts and use."
+e69a1df4 dec/vp8l: prevent signed int overflow in left shift ops
+cf5eb8ad remove some uint64_t casts and use.
+38e2db3e MIPS: MIPS32r1: Added optimization for HistogramAdd.
+e0609ade dwebp: fix exit code on webp load failure
+bbd358a8 Merge "example_util.h: avoid forward declaring enums"
+8955da21 example_util.h: avoid forward declaring enums
+6d6865f0 Added SSE2 variants for Average2/3/4
+b3a616b3 make HistogramAdd() a pointer in dsp
+c8bbb636 dec_neon: relocate some inline-asm defines
+4e393bb9 dec_neon: enable intrinsics-only functions
+ba99a922 dec_neon: use positive tests for USE_INTRINSICS
+69058ff8 Merge "example_util: add ExUtilDecodeWebPIncremental"
+a7828e8b dec_neon: make WORK_AROUND_GCC conditional on version
+3f3d717a Merge "enc_neon: enable intrinsics-only functions"
+de3cb6c8 Merge "move LOCAL_GCC_VERSION def to dsp.h"
+1b2fe14d example_util: add ExUtilDecodeWebPIncremental
+ca49e7ad Merge "enc_neon: move Transpose4x4 to dsp/neon.h"
+ad900abd Merge "fix warning about size_t -> int conversion"
+4825b436 fix warning about size_t -> int conversion
+42b35e08 enc_neon: enable intrinsics-only functions
+f937e012 move LOCAL_GCC_VERSION def to dsp.h
+5e1a17ef enc_neon: move Transpose4x4 to dsp/neon.h
+c7b92a5a dec_neon: (WORK_AROUND_GCC) delete unused Load4x8
+8e5f90b0 Merge "make ExUtilLoadWebP() accept NULL bitstream param."
+05d4c1b7 Merge "cwebp: add webpdec"
+ddeb6ac8 cwebp: add webpdec
+35d7d095 Merge "Reduce memory footprint for encoding WebP lossless."
+0b896101 Reduce memory footprint for encoding WebP lossless.
+f0b65c9a make ExUtilLoadWebP() accept NULL bitstream param.
+9c0a60cc Merge "dwebp: move webp decoding to example_util"
+1d62acf6 MIPS: MIPS32r1: Added optimization for HuffmanCost functions.
+4a0e7390 dwebp: move webp decoding to example_util
+c0220460 Merge "Bugfix: Incremental decode of lossy-alpha"
+8c7cd722 Bugfix: Incremental decode of lossy-alpha
+7955152d MIPS: fix error with number of registers.
+b1dabe37 Merge "Move the HuffmanCost() function to dsp lib"
+75b12006 Move the HuffmanCost() function to dsp lib
+2772b8bd MIPS: fix assembler error revealed by clang's debug build
+6653b601 enc_mips32: fix unused symbol warning in debug
+8dec1209 enc_mips32: disable ITransform(One) in debug builds
+98519dd5 enc_neon: convert Disto4x4 to intrinsics
+fe9317c9 cosmetics:
+953b0746 enc_neon: cosmetics
+a9fc697c Merge "WIP: extract the float-calculation of HuffmanCost from loop"
+3f84b521 Merge "replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8)"
+4ae0533f MIPS: MIPS32r1: Added optimizations for ExtraCost functions.
+b30a04cf WIP: extract the float-calculation of HuffmanCost from loop
+a8fe8ce2 Merge "NEON intrinsics version of CollectHistogram"
+95203d2d NEON intrinsics version of CollectHistogram
+7ca2e74b replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8)
+41c6efbd fix lossless_neon.c
+8ff96a02 NEON intrinsics version of FTransform
+0214f4a9 Merge "MIPS: MIPS32r1: Added optimizations for FastLog2"
+baabf1ea MIPS: MIPS32r1: Added optimizations for FastLog2
+3d49871d NEON functions for lossless coding
+3fe02915 MIPS: MIPS32r1: Added optimizations for SSE functions.
+c503b485 Merge "fix the gcc-4.6.0 bug by implementing alternative method"
+abe6f487 fix the gcc-4.6.0 bug by implementing alternative method
+5598bdec enc_mips32.c: fix file mode
+2b1b4d5a MIPS: MIPS32r1: Add optimization for GetResidualCost
+f0a1f3cd Merge "MIPS: MIPS32r1: Added optimization for FTransform"
+7231f610 MIPS: MIPS32r1: Added optimization for FTransform
+869eaf6c ~30% encoding speedup: use NEON for QuantizeBlock()
+f758af6b enc_neon: convert FTransformWHT to intrinsics
+7dad095b MIPS: MIPS32r1: Added optimization for Disto4x4 (TTransform)
+2298d5f3 MIPS: MIPS32r1: Added optimization for QuantizeBlock
+e88150c9 Merge "MIPS: MIPS32r1: Add optimization for ITransform"
+de693f25 lossless_neon: disable VP8LConvert* functions
+4143332b NEON intrinsics for encoding
+0ca2914b MIPS: MIPS32r1: Add optimization for ITransform
+71bca5ec dec_neon: use vst_lane instead of vget_lane
+bf061052 Intrinsics NEON version of TransformOne
+19c6f1ba Merge "dec_neon: use vld?_lane instead of vset?_lane"
+7a94c0cf upsampling_neon: drop NEON suffix from local functions
+d14669c8 upsampling_sse2: drop SSE2 suffix from local functions
+2ca42a4f enc_sse2: drop SSE2 suffix from local functions
+d038e619 dec_sse2: drop SSE2 suffix from local functions
+fa52d752 dec_neon: use vld?_lane instead of vset?_lane
+c520e77d cosmetic: fix long line
+4b0f2dae Merge "add intrinsics NEON code for chroma strong-filtering"
+e351ec07 add intrinsics NEON code for chroma strong-filtering
+aaf734b8 Merge "Add SSE2 version of forward cross-color transform"
+c90a902e Add SSE2 version of forward cross-color transform
+bc374ff3 Use histogram_bits to initalize transform_bits.
+2132992d Merge "Add strong filtering intrinsics (inner and outer edges)"
+5fbff3a6 Add strong filtering intrinsics (inner and outer edges)
+d4813f0c Add SSE2 function for Inverse Cross-color Transform
+26029568 dec_neon: add strong loopfilter intrinsics
+cca7d7ef Merge "add intrinsics version of SimpleHFilter16NEON()"
+1a05dfa7 windows: fix dll builds
+d6c50d8a Merge "add some colorspace conversion functions in NEON"
+4fd7c82e SSE2 variants of Subtract-Green: Rectify loop condition
+97e5fac3 add some colorspace conversion functions in NEON
+b9a7a45f add intrinsics version of SimpleHFilter16NEON()
+daccbf40 add light filtering NEON intrinsics
+af444608 fix typo in STORE_WHT
+6af6b8e1 Tune HistogramCombineBin for large images.
+af93bdd6 use WebPSafe[CM]alloc/WebPSafeFree instead of [cm]alloc/free
+51f406a5 lossless_sse2: relocate VP8LDspInitSSE2 proto
+0f4f721b separate SSE2 lossless functions into its own file
+514fc251 VP8LConvertFromBGRA: use conversion function pointers
+6d2f3527 dsp/dec: TransformDCUV: use VP8TransformDC
+defc8e1b Merge "fix out-of-bound read during alpha-plane decoding"
+fbed3643 Merge "dsp: reuse wht transform from dec in encoder"
+d8467084 Merge "Add SSE2 version of ARGB -> BGR/RGB/... conversion functions"
+207d03b4 fix out-of-bound read during alpha-plane decoding
+d1b33ad5 2-5% faster trellis with clang/MacOS (and ~2-3% on ARM)
+369c26dd Add SSE2 version of ARGB -> BGR/RGB/... conversion functions
+df230f27 dsp: reuse wht transform from dec in encoder
+80e218d4 Android.mk: fix build with APP_ABI=armeabi-v7a-hard
+59daf083 Merge "cosmetics:"
+53622008 cosmetics:
+3e7f34a3 AssignSegments: quiet array-bounds warning
+3c2ebf58 Merge "UpdateHistogramCost: avoid implicit double->float"
+cf821c82 UpdateHistogramCost: avoid implicit double->float
+312e638f Extend the search space for GetBestGreenRedToBlue
+1c58526f Fix few nits
+fef22704 Optimize and re-structure VP8LGetHistoImageSymbols
+068b14ac Optimize lossless decoding.
+5f0cfa80 Do a binary search to get the optimum cache bits.
+24ca3678 Merge "allow 'cwebp -o -' to emit output to stdout"
+e12f874e allow 'cwebp -o -' to emit output to stdout
+2bcad89b allow some more stdin/stout I/O
+84ed4b3a fix cwebp.1 typos after patch #69199
+65b99f1c add a -z option to cwebp, and WebPConfigLosslessPreset() function
+30176619 4-5% faster trellis by removing some unneeded calculations.
+687a58ec histogram.c: reindent after b33e8a0
+06d456f6 Merge "~3-4% faster lossless encoding"
+c60de260 ~3-4% faster lossless encoding
+42eb06fc Merge "few cosmetics after patch #69079"
+82af8264 few cosmetics after patch #69079
+b33e8a05 Refactor code for HistogramCombine.
+ca1bfff5 Merge "5-10% encoding speedup with faster trellis (-m 6)"
+5aeeb087 5-10% encoding speedup with faster trellis (-m 6)
+82ae1bf2 cosmetics: normalize VP8GetCPUInfo checks
+e3dd9243 Merge "Refactor GetBestPredictorForTile for future tuning."
+206cc1be Refactor GetBestPredictorForTile for future tuning.
+3cb84062 Merge "speed-up trellis quant (~5-10% overall speed-up)"
+b66f2227 Merge "lossy encoding: ~3% speed-up"
+4287d0d4 speed-up trellis quant (~5-10% overall speed-up)
+390c8b31 lossy encoding: ~3% speed-up
+9a463c4a Merge "dec_neon: convert TransformWHT to intrinsics"
+e8605e96 Merge "dec_neon: add ConvertU8ToS16"
+4aa3e412 MIPS: MIPS32r1: rescaler bugfix
+c16cd99a Speed up lossless encoder.
+9d6b5ff1 dec_neon: convert TransformWHT to intrinsics
+2ff0aae2 dec_neon: add ConvertU8ToS16
+77a8f919 fix compilation with USE_YUVj flag
+4acbec1b Merge changes I3b240ffb,Ia9370283,Ia2d28728
+2719bb7e dec_neon: TransformAC3: work on packed vectors
+b7b60ca1 dec_neon: add SaturateAndStore4x4
+b7685d73 Rescale: let ImportRow / ExportRow be pointer-to-function
+e02f16ef dec_neon.c: convert TransformDC to intrinsics
+9cba963f add missing file
+8992ddb7 use static clipping tables
+0235d5e4 1-2% faster quantization in SSE2
+b2fbc36c fix VC12-x64 warning
+6e37cb94 Merge "cosmetics: backward_references.c: reindent after a7d2ee3"
+a42ea974 cosmetics: backward_references.c: reindent after a7d2ee3
+6c327442 Merge "fix missing __BIG_ENDIAN__ definition on some platform"
+a8b6aad1 fix missing __BIG_ENDIAN__ definition on some platform
+fde2904b Increase initial buffer size for VP8L Bit Writer.
+a7d2ee39 Optimize cache estimate logic.
+7fb6095b Merge "dec_neon.c: add TransformAC3"
+bf182e83 VP8LBitWriter: use a bit-accumulator
+3f40b4a5 Merge "MIPS: MIPS32r1: clang macro warning resolved"
+1684f4ee WebP Decoder: Mark some truncated bitstreams as invalid
+acbedac4 MIPS: MIPS32r1: clang macro warning resolved
+228e4877 dec_neon.c: add TransformAC3
+393f89b7 Android.mk: avoid gcc-specific flags with clang
+32aeaf11 revamp VP8LColorSpaceTransform() a bit
+0c7cc4ca Merge "Don't dereference NULL, ensure HashChain fully initialized"
+391316fe Don't dereference NULL, ensure HashChain fully initialized
+926ff402 WEBP_SWAP_16BIT_CSP: remove code dup
+1d1cd3bb Fix decode bug for rgbA_4444/RGBA_4444 color-modes.
+939e70e7 update AUTHORS file
+8934a622 cosmetics: *_mips32.c
+dd438c9a MIPS: MIPS32r1: Optimization of some simple point-sampling functions. PATCH [6/6]
+53520911 Added support for calling sampling functions via pointers.
+d16c6974 MIPS: MIPS32r1: Optimization of filter functions. PATCH [5/6]
+04336fc7 MIPS: MIPS32r1: Optimization of function TransformOne. PATCH [4/6]
+92d8fc7d MIPS: MIPS32r1: Optimization of function WebPRescalerImportRow. PATCH [3/6]
+bbc23ff3 parse one row of intra modes altogether
+a2f608f9 Merge "MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6]"
+88230854 MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6]
+c5a5b028 decode mt+incremental: fix segfault in debug builds
+9882b2f9 always use fast-analysis for all methods.
+000adac0 Merge "autoconf: update ax_pthread.m4"
+2d2fc37d update .gitignore
+5bf4255a Merge "Make it possible to avoid automagic dependencies"
+c1cb1933 disable NEON for arm64 platform
+73a304e9 Make it possible to avoid automagic dependencies
+4d493f8d MIPS: MIPS32r1: Decoder bit reader function optimized. PATCH [1/6]
+c741183c make WebPCleanupTransparentArea work with argb picture
+5da18552 add a decoding option to flip image vertically
+00c3c4e1 Merge "add man/vwebp.1"
+2c6bb428 add man/vwebp.1
+ea59a8e9 Merge "Merge tag 'v0.4.0'"
+7574bed4 fix comments related to array sizes
+0b5a90fd dwebp.1: fix option formatting
+effcb0fd Merge tag 'v0.4.0'
+7c76255d autoconf: update ax_pthread.m4
+fff2a11b make -short work with -print_ssim, -print_psnr, etc.
+68e7901d update ChangeLog (tag: v0.4.0-rc1, tag: v0.4.0, origin/0.4.0)
+256e4333 update NEWS description with new general features
+29625340 Merge "gif2webp: don't use C99 %zu" into 0.4.0
+3b9f9dd0 gif2webp: don't use C99 %zu
+b5b2e3c7 cwebp: fix metadata output w/lossy+alpha
+ad26df1a makefile.unix: clean up libgif2webp_util.a
+c3b45570 update Changelog
+ca841121 Merge "bump version to 0.4.0" into 0.4.0
+8c524db8 bump version to 0.4.0
+eec2398c update AUTHORS & .mailmap
+b9bbf6a1 update NEWS for 0.4.0
+c72e0811 Merge "dec/webp.c: don't wait for data before reporting w/h"
+5ad65314 dec/frame.c: fix formatting
+f7fc4bc8 dec/webp.c: don't wait for data before reporting w/h
+66a32af5 Merge "NEON speed up"
+26d842eb NEON speed up
+f307f98b Merge "webpmux: let -- stop parameter parsing"
+fe051da7 Merge "README: add a section on gif2webp"
+6fd2bd62 Merge "manpage pedantry"
+4af19007 README: add a section on gif2webp
+6f36ade9 manpage pedantry
+f9016cb9 README: update dwebp options
+b4fa0a47 webpmux: let -- stop parameter parsing
+a9a20acf gif2webp: Add a multi-threaded encode option
+495bef41 fix bug in TrellisQuantize
+605a7127 simplify __cplusplus ifdef
+33109f99 Merge "drop: ifdef __cplusplus checks from C files"
+7f9de0b9 Merge changes I994a5587,I8467bb71,I13b50688,I1e2c9c7b
+5459030b gif2webp: let -- stop parameter parsing
+a4b0aa06 vwebp: let -- stop parameter parsing
+98af68fe cwebp: let -- stop parameter parsing
+a33831e2 dwebp: let -- stop parameter parsing
+36301249 add some checks on error paths
+ce4c7139 Merge "autoconf: add --disable-wic"
+5227d991 drop: ifdef __cplusplus checks from C files
+f6453559 dwebp.1: fix typo
+f91034f2 Merge "cwebp: print metadata stats when no output file is given"
+d4934553 gif2webp: Backward compatibility for giflib version <= 4.1.3
+4c617d32 gif2webp: Disable output of ICC profile by default
+73b731fb introduce a special quantization function for WHT
+41c0cc4b Make Forward WHT transform use 32bit fixed-point calculation
+a3359f5d Only compute quantization params once
+70490437 cwebp: print metadata stats when no output file is given
+d513bb62 * fix off-by-one zthresh calculation * remove the sharpening for non luma-AC coeffs * adjust the bias a little bit to compensate for this
+ad9dec0c Merge "cosmetics: dwebp: fix local function name format"
+f737f037 Merge "dwebp: remove a dead store"
+3c3a70da Merge "makefile.unix: install binaries in $(DESTDIR)/bin/"
+150b655f Merge "Android.mk: add some release compile flags"
+dbebd33b cosmetics: dwebp: fix local function name format
+27749951 dwebp: remove a dead store
+a01e04fe autoconf: add --disable-wic
+5009b227 makefile.unix: install binaries in $(DESTDIR)/bin/
+bab30fca Merge "fix -print_psnr / ssim options"
+ebef7fb3 fix -print_psnr / ssim options
+cb637855 Merge "fix bug due to overzealous check in WebPPictureYUVAToARGB()"
+8189885b Merge "EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE"
+4ad7d335 Android.mk: add some release compile flags
+c12e2369 cosmetics: fix a few typos
+6f104034 fix bug due to overzealous check in WebPPictureYUVAToARGB()
+3f6c35c6 EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE
+cc55790e Merge changes I8bb7a4dc,I2c180051,I021a014f,I8a224a62
+c536afb5 Merge "cosmetics: fix some typos"
+cbdd3e6e add a -dither dithering option to the decoder
+e8124012 Updated iosbuild.sh for XCode 5.x
+4931c329 cosmetics: fix some typos
+05aacf77 mux: add some missing casts
+617d9348 enc/vp8l: add a missing cast
+46db2865 idec: add some missing casts
+b524e336 ErrorStatusLossless: correct return type
+cb261f79 fix a descaling bug for vertical/horizontal U/V interpolation
+bcb3955c Merge changes I48968468,I181bc736
+73f52133 gif2webp: Add a mixed compression mode
+6198715e demux: split chunk parsing from ParseVP8X
+d2e3f4e6 demux: add a tail pointer for chunks
+87cffcc3 demux: cosmetics: s/has_frames/is_animation/
+e18e6677 demux: strictly enforce the animation flag
+c4f39f4a demux: cosmetics: remove a useless break
+61cb884d demux: (non-exp) fail if the fragmented flag is set
+ff379db3 few % speedup of lossless encoding
+df3649a2 remove all disabled code related to P-frames
+6d0cb3de Merge "gif2webp: kmin = 0 should suppress key-frame addition."
+36555983 gif2webp: kmin = 0 should suppress key-frame addition.
+7708e609 Merge "detect flatness in blocks and favor DC prediction"
+06b1503e Merge "add comment about the kLevelsFromDelta[][] LUT generation"
+5935259c add comment about the kLevelsFromDelta[][] LUT generation
+e3312ea6 detect flatness in blocks and favor DC prediction
+ebc9b1ee Merge "VPLBitReader bugfix: Catch error if bit_pos > LBITS too."
+96ad0e0a VPLBitReader bugfix: Catch error if bit_pos > LBITS too.
+a014e9c9 tune quantization biases toward higher precision
+1e898619 add helpful PrintBlockInfo() function
+596a6d73 make use of 'extern' consistent in function declarations
+c8d48c6e Merge "extract random utils to their own file util/random.[ch]"
+98aa33cf extract random utils to their own file util/random.[ch]
+432a723e Merge "swig: add basic go bindings"
+fab618b5 Merge "rename libwebp.i -> libwebp.swig"
+e4e7fcd6 swig: add basic go bindings
+d3408720 Merge "fast auto-determined filtering strength"
+f8bfd5cd fast auto-determined filtering strength
+ac0bf951 small clean-up in ExpandMatrix()
+1939607e rename libwebp.i -> libwebp.swig
+43148b6c filtering: precompute ilimit and hev_threshold
+18f992ec simplify f_inner calculation a little
+241d11f1 add missing const
+86c0031e add a 'format' field to WebPBitstreamFeatures
+dde91fde Demux: Correct the extended format validation
+5d6c5bd2 add entry for '-resize' option in cwebp's man
+7c098d18 Use some gamma-curve range compression when computing U/V average
+0b2b0504 Use deterministic random-dithering during RGB->YUV conversion
+8a2fa099 Add a second multi-thread method
+7d6f2da0 Merge "up to 20% faster multi-threaded decoding"
+266f63ea Merge "libwebp.jar: build w/Java 1.6 for Android compat"
+0532149c up to 20% faster multi-threaded decoding
+38efdc2e Simplify the gif2webp tool: move the optimization details to util
+de899516 libwebp.jar: build w/Java 1.6 for Android compat
+cb221552 Decode a full row of bitstream before reconstructing
+dca8a4d3 Merge "NEON/simple loopfilter: avoid q4-q7 registers"
+9e84d901 Merge "NEON/TransformWHT: avoid q4-q7 registers"
+fc10249b NEON/simple loopfilter: avoid q4-q7 registers
+2f09d63e NEON/TransformWHT: avoid q4-q7 registers
+77585a2b Merge "use a macrofunc for setting NzCoeffs bits"
+d155507c Merge "use HINT_GRAPH as image_hint for gif source"
+9c561646 Merge "only print GIF_DISPOSE_WARNING once"
+05879865 use HINT_GRAPH as image_hint for gif source
+0b28d7ab use a macrofunc for setting NzCoeffs bits
+f9bbc2a0 Special-case sparse transform
+00125196 gif2webp: detect and flatten uniformly similar blocks
+0deaf0fa only print GIF_DISPOSE_WARNING once
+6a8c0eb7 Merge "small optimization in segment-smoothing loop"
+f7146bc1 small optimization in segment-smoothing loop
+5a7533ce small gif2webp fix
+4df0c89e Merge changes Ic697660c,I27285521
+5b2e6bd3 Android.mk: add a dwebp target
+f910a84e Android.mk: update build flags
+63f9aba4 special-case WHT transform when there's only DC
+80911aef Merge "7-8% faster decoding by rewriting GetCoeffs()"
+606c4304 gif2webp: Improved compression for lossy animated WebP
+fb887f7f gif2webp: Different kmin/kmax defaults for lossy and lossless
+2a981366 7-8% faster decoding by rewriting GetCoeffs()
+92d47e4c improve VP8L signature detection by checking the version bits too
+5cd43e43 Add -incremental option to dwebp
+54b8e3f6 webpmux: DisplayInfo(): remove unnecessary error checks.
+40ae3520 fix memleak in WebPIDelete()
+d9662658 mux.h doc: WebPMuxGetFrame() can return WEBP_MUX_MEMORY_ERROR too.
+0e6747f8 webpmux -info: display dimensions and has_alpha per frame
+d78a82c4 Sanity check for underflow
+8498f4bf Merge "remove -Wshadow warnings"
+e89c6fc8 Avoid a potential memleak
+3ebe1757 Merge "break down the proba 4D-array into some handy structs"
+6a44550a break down the proba 4D-array into some handy structs
+2f5e8934 remove -Wshadow warnings
+bf3a29b3 Merge "add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags"
+2b0a7593 Merge "fix some warnings from static analysis"
+22dd07ce mux.h: Some doc corrections
+79ff0346 add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags
+d51f45f0 fix some warnings from static analysis
+d134307b fix conversion warning on MSVC
+d538cea8 gif2webp: Support a 'min' and 'max' key frame interval
+80b54e1c allow search with token buffer loop and fix PARTITION0 problem
+b7d4e042 add VP8EstimateTokenSize()
+10fddf53 enc/quant.c: silence a warning
+399cd456 Merge "fix compile error on ARM/gcc"
+9f24519e encoder: misc rate-related fixes
+c663bb21 Merge "simplify VP8IteratorSaveBoundary() arg passing"
+fa46b312 Demux.h: Correct a method name reference
+f8398c9d fix compile error on ARM/gcc
+f691f0e4 simplify VP8IteratorSaveBoundary() arg passing
+42542be8 up to 6% faster encoding with clang compiler
+93402f02 multi-threaded segment analysis
+7e2d6595 Merge "remove the PACK() bit-packing tricks"
+c13fecf9 remove the PACK() bit-packing tricks
+2fd091c9 Merge "use NULL for lf_stats_ testing, not bool"
+b11c9d62 dwebp: use default dct_method
+4bb8465f Merge "(de)mux.h: wrap pseudo-code in /* */"
+cfb56b17 make -pass option work with token buffers
+5416aab4 (de)mux.h: wrap pseudo-code in /* */
+35dba337 use NULL for lf_stats_ testing, not bool
+733a7faa enc->Iterator memory cleanup
+e81fac86 Add support for "no blend" in webpmux binary
+3b80bc48 gif2webp: Separate out each step into a method
+bef7e9cc Add doc precision about demux object keeping pointers to data.
+61405a14 dwebp: enable stdout output with WIC
+6eabb886 Merge "Animated WebP: add "do no blend" option to spec"
+be20decb fix compilation for BITS 24
+e58cc137 Merge "dwebp: s/unsigned char/uint8_t/"
+72501d43 dwebp: s/unsigned char/uint8_t/
+2c9633e8 Merge "gif2webp: Insert independent frames at regular intervals."
+f0d6a14b gif2webp: Insert independent frames at regular intervals.
+b25a6fbf yuv.h: fix indent
+ede3602e Merge "cosmetics: fix indent"
+3a65122a dwebp: fix stdout related output
+388a7249 cosmetics: fix indent
+4c7322c8 Merge "dsp: msvc compatibility"
+d50c7e32 Merge "5-7% faster SSE2 versions of YUV->RGB conversion functions"
+b8ab7847 Merge "simplify upsampler calls: only allow 'bottom' to be NULL"
+df6cebfa 5-7% faster SSE2 versions of YUV->RGB conversion functions
+ad6ac32d simplify upsampler calls: only allow 'bottom' to be NULL
+a5e8afaf output to stdout if file name is "-"
+f358450f dsp: msvc compatibility
+43a7c8eb Merge "cosmetics"
+4c5f19c1 Merge "bit_reader.h: cosmetics"
+f72fab70 cosmetics
+14dd5e78 fix const-ness
+b20aec49 Merge "Support for 'do not blend' option in vwebp"
+dcf65222 Support for 'do not blend' option in vwebp
+d5bad033 Animated WebP: add "do no blend" option to spec
+a2f5f73d Merge "Support for "Do not blend" in mux and demux libraries"
+e081f2f3 Pack code & extra_bits to Struct (VP8LPrefixCode).
+6284854b Support for "Do not blend" in mux and demux libraries
+f486aaa9 Merge "slightly faster ParseIntraMode"
+d1718632 slightly faster ParseIntraMode
+3ceca8ad bit_reader.h: cosmetics
+69257f70 Create LUT for PrefixEncode.
+988b7084 add WebPWorkerExecute() for convenient bypass
+06e24987 Merge "VP8EncIterator clean-up"
+de4d4ad5 VP8EncIterator clean-up
+7bbe9529 Merge "cosmetics: thread.c: drop a redundant comment"
+da411485 cosmetics: thread.c: drop a redundant comment
+feb4b6e6 thread.h: #ifdef when checking WEBP_USE_THREAD
+8924a3a7 thread.c: drop WebPWorker prefix from static funcs
+1aed8f2a Merge "fix indent"
+4038ed15 fix indent
+1693fd9b Demux: A new state WEBP_DEMUX_PARSE_ERROR
+8dcae8b3 fix rescaling-with-alpha inaccuracy
+11249abf Merge changes I9b4dc36c,I4e0eef4d
+52508a1f Mux: support parsing unknown chunks within a frame/fragment.
+05db0572 WebPMuxSetChunk: remove unused variable
+8ba1bf61 Stricter check for presence of alpha when writing lossless images
+a03c3516 Demux: WebPIterator now also denotes if the frame has alpha.
+6df743a3 Decoder: handle fragments case correctly too.
+faa4b07e Support for unknown chunks in mux library
+7d60bbc6 Speed up HashChainFindCopy function.
+66740140 Speedup Alpha plane encoding.
+b7346a1e 0.1 % speedup to decoding
+c606182e webp-container-spec: Tighten language added by last
+a34a5029 pngdec: output error messages from libpng
+e84c625d Merge "Detect canvas and image size mismatch in decoder."
+f626fe2e Detect canvas and image size mismatch in decoder.
+f5fbdee0 demux: stricter image bounds check
+30c8158a add extra assert in Huffman decode code
+8967b9f3 SSE2 for lossless decoding (critical) functions.
+699d80ea Jump-lookup for Huffman coding
+c34307ab fix some VS9 warnings about type conversion
+eeada35c pngdec: add missing include
+54b65108 gif2webp: If aligning to even offsets, extra pixels should be transparent
+0bcf5ce3 Merge "remove a malloc() in case we're using only FILTER_NONE for alpha"
+2c07143b remove a malloc() in case we're using only FILTER_NONE for alpha
+a4d5f59d Faster lossless decoding
+fd53bb75 Merge "alternate LUT-base reverse-bits code"
+d1c166ef Merge "Container spec: a clarification on background color."
+fdb91779 Rename a method
+5e967532 Container spec: a clarification on background color.
+30e77d0f Merge branch '0.3.0'
+1b631e29 alternate LUT-base reverse-bits code
+24cc307a ~20% faster lossless decoding
+313d853f Speedup for decoding lossless WebP photographs:
+24ee098a change the bytes_per_pixels_ field into more evocative use_8b_decode
+2a04b034 update ChangeLog (tag: v0.3.1-rc2, tag: v0.3.1)
+7288950b Regression fix for alpha channels using color cache:
+2e377b53 wicdec: silence a format warning
+ad9e42a6 muxedit: silence some uninitialized warnings
+3307c163 Don't set alpha-channel to 0xff for alpha->green uplift
+5130770c Merge "wicdec: silence a format warning"
+a37eff47 Regression fix for alpha channels using color cache:
+241cf99b Merge "muxedit: silence some uninitialized warnings"
+c8f9c84d Regression fix for alpha unfiltering:
+14cd5c6c muxedit: silence some uninitialized warnings
+a368db81 dec/vp8l: quiet vs9 x64 type conversion warning
+ffae9f31 wicdec: silence a format warning
+8cf0701e Alpha encoding: never filter in case of NO_COMPRESSION
+825e73b1 update ChangeLog (tag: v0.3.1-rc1)
+abf6f691 update NEWS
+5a92c1a5 bump version to 0.3.1
+86daf77c store top Y/U/V samples in packed fashion
+67bc353e Revert "add WebPBlendAlpha() function to blend colors against background"
+068db59e Intertwined decoding of alpha and RGB
+38cc0114 Simplify forward-WHT + SSE2 version
+3fa595a5 Support decoding upto given row in DECODE_DATA_FUNC
+520f005f DequantizeLevels(): Add 'row' and 'num_rows' args
+47374b82 Alpha unfilter for given set of rows
+f32097e0 probe input file and quick-check for WebP format.
+a2aed1d0 configure: improve gl/glut library test
+c7e89cbb update copyright text
+a00380d2 configure: remove use of AS_VAR_APPEND
+a94a88dd fix EXIF parsing in PNG
+a71e5d84 add doc precision for WebPPictureCopy() and WebPPictureView()
+8287012e remove datatype qualifier for vmnv
+e1908430 fix a memory leak in gif2webp
+0b18b9ee fix two minor memory leaks in webpmux
+db5095d5 remove some cruft from swig/libwebp.jar
+850e956f README: update swig notes
+bddd9b0a swig/python: add minimal documentation
+d573a8d5 swig: add python encode support
+6b931875 swig/java: reduce wrapper function code duplication
+6fe536f4 swig/java: rework uint8_t typemap
+a2ea4643 Fix the bug in ApplyPalette.
+7bb28d2a webp/lossless: fix big endian BGRA output
+f036d4bf Speed up ApplyPalette for ARGB pixels.
+8112c8cf remove some warnings:
+cc128e0b Further reduce memory to decode lossy+alpha images
+07db70d2 fix for big-endian
+eda8a7de gif2webp: Fix signed/unsigned comparison mismatch
+31f346fe Makefile.vc: fix libwebpdemux dll variable typo
+6c76d28e swig: add python (decode) support
+b4f5bb6c swig: cosmetics
+498d4dd6 WebP-Lossless encoding improvements.
+26e72442 swig: ifdef some Java specific code
+8ecec686 configure: add warning related flags
+e676b043 configure: add GLUT detection; build vwebp
+b0ffc437 Alpha decoding: significantly reduce memory usage
+20aa7a8d configure: add --enable-everything
+b8307cc0 configure.ac: add some helper macros
+980e7ae9 Remove the gcc compilation comments
+7f25ff99 gif2webp: Fix ICC and XMP support
+d8e53211 Add missing name to AUTHORS
+11edf5e2 Demux: Fix a potential memleak
+c7b92184 don't forward declare enums
+7a650c6a prevent signed int overflow in left shift ops
+31bea324 add precision about dynamic output reallocation with IDecoder
+c22877f7 Add incremental support for extended format files
+5051245f Makefile.vc: have 'all' target build everything
+8191deca Makefile.vc: flags cleanup
+b9d74735 Makefile.vc: drop /FD flag
+5568dbcf update gitignore
+f4c7b654 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded.
+1fb04bec pngdec: Avoid a double-free.
+dcbb1ca5 add WebPBlendAlpha() function to blend colors against background
+bc9f5fbe configure.ac: add AM_PROG_AR for automake >= 1.12
+bf867bf2 Tuned cross_color parameter (step) for lower qual
+90e2ec5a Merge "probe input file and quick-check for WebP format."
+7180d7ff Merge "update copyright text"
+830f72b7 probe input file and quick-check for WebP format.
+2ccf58d6 configure: improve gl/glut library test
+d640614d update copyright text
+c2113ad4 Merge "configure: remove use of AS_VAR_APPEND"
+9326a56f configure: remove use of AS_VAR_APPEND
+ea63d619 fix a type warning on VS9 x86
+bec11092 fix EXIF parsing in PNG
+b6e65f3d Merge "fix warnings for vs9 x64"
+438946dc fix warnings for vs9 x64
+f4710e3b collect macroblock reconstruction data in VP8MBData struct
+23d28e21 add doc precision for WebPPictureCopy() and WebPPictureView()
+518f2cd7 cosmetics: gif2webp: fix indent
+af358e68 Merge "remove datatype qualifier for vmnv"
+3fe91635 remove datatype qualifier for vmnv
+764fdffa fix a memory leak in gif2webp
+3e59a74d fix two minor memory leaks in webpmux
+47b9862f Merge "README: update swig notes"
+325d15ff remove some cruft from swig/libwebp.jar
+4a7627c2 README: update swig notes
+5da81e33 Merge "swig/python: add minimal documentation"
+f39e08f2 Merge "swig: add python encode support"
+6ca4a3e3 Merge "swig/java: reduce wrapper function code duplication"
+8f8702b0 Merge "swig/java: rework uint8_t typemap"
+91413be2 reduce memory for VP8MB and remove bitfields use
+7413394e Fix the memory leak in ApplyFilters.
+2053c2cf simplify the alpha-filter testing loop
+825b64db swig/python: add minimal documentation
+14677e11 swig: add python encode support
+a5c297c8 swig/java: reduce wrapper function code duplication
+ad4a367d swig/java: rework uint8_t typemap
+0d25876b use uint8_t for inv_palette[]
+afa3450c Fix the bug in ApplyPalette.
+2d6ac422 Merge "webp/lossless: fix big endian BGRA output"
+2ca83968 webp/lossless: fix big endian BGRA output
+742110cc Speed up ApplyPalette for ARGB pixels.
+2451e47d misc code cleanup
+83db4043 Merge "swig: add python (decode) support"
+eeeea8b5 Merge "swig: cosmetics"
+d5f9b8f3 Merge "libwebp: fix vp8 encoder mem alloc offsetting"
+d8edd835 libwebp: fix vp8 encoder mem alloc offsetting
+8983b83e remove use of bit-fields in VP8FInfo
+87a4fca2 remove some warnings:
+ba8f74e2 Merge "fix for big-endian"
+a65067fa Merge "Further reduce memory to decode lossy+alpha images"
+64c84486 Further reduce memory to decode lossy+alpha images
+332130b9 Mux: make a few methods static
+44370617 fix for big-endian
+5199eab5 Merge "add uncompressed TIFF output support"
+a3aede97 add uncompressed TIFF output support
+f975b67f Merge "gif2webp: Fix signed/unsigned comparison mismatch"
+5fbc734b Merge "GetFeatures: Detect invalid VP8X/VP8/VP8L data"
+d5060c87 Merge "mux.h: A comment fix + some consistency fixes"
+352d0dee GetFeatures: Detect invalid VP8X/VP8/VP8L data
+3ef79fef Cosmetic: "width * height"
+043e1ae4 gif2webp: Fix signed/unsigned comparison mismatch
+5818cff7 mux.h: A comment fix + some consistency fixes
+1153f888 Merge "swig: ifdef some Java specific code"
+3eeedae1 Makefile.vc: fix libwebpdemux dll variable typo
+f980faf4 swig: add python (decode) support
+7f5f42bb swig: cosmetics
+8eae188a WebP-Lossless encoding improvements.
+c7247c4c swig: ifdef some Java specific code
+4cb234d5 Merge "Mux: make ValidateForSingleImage() method static"
+ed6f5308 Merge "Add GetCanvasSize() method to mux"
+1d530c9a Mux: make ValidateForSingleImage() method static
+bba4c2b2 configure: add warning related flags
+fffefd18 Add GetCanvasSize() method to mux
+732da8d0 Merge "configure: add GLUT detection; build vwebp"
+0e513f7a configure: add GLUT detection; build vwebp
+55d1c150 Merge "Alpha decoding: significantly reduce memory usage"
+13d99fb5 Merge "configure: add --enable-everything"
+2bf698fe Merge "configure.ac: add some helper macros"
+edccd194 Alpha decoding: significantly reduce memory usage
+3cafcc9a configure: add --enable-everything
+4ef14477 configure.ac: add some helper macros
+a4e1cdbb Remove the gcc compilation comments
+6393fe4b Cosmetic fixes
+9c4ce971 Simplify forward-WHT + SSE2 version
+878b9da5 fix missed optim
+00046171 VP8GetInfo(): Check for zero width or height.
+9bf31293 align VP8Encoder::nz_ allocation
+5da165cf fix CheckMode() signature
+0ece07dc Merge "explicitly pad bitfields to 32-bits"
+9dbc9d19 explicitly pad bitfields to 32-bits
+5369a80f Merge "prevent signed int overflow in left shift ops"
+70e39712 Merge "cosmetics: remove unnecessary ';'s"
+d3136ce2 Merge "don't forward declare enums"
+b26e5ad5 gif2webp: Fix ICC and XMP support
+46089b20 Add missing name to AUTHORS
+94328d64 Demux: Fix a potential memleak
+96e948d7 don't forward declare enums
+f4f90880 prevent signed int overflow in left shift ops
+0261545e cosmetics: remove unnecessary ';'s
+7ebdf110 Merge "Fix few missing comparisons to NULL"
+1579989e Fix few missing comparisons to NULL
+ea1b21cf Cleaned up VP8GetHeaders() so that it parses only frame header
+b66caee4 dwebp: add support for BMP output
+ff885bfe add precision about dynamic output reallocation with IDecoder
+79241d5a Merge "Makefile.vc: have 'all' target build everything"
+ac1c729b Merge "Makefile.vc: flags cleanup"
+118a055c Merge "Makefile.vc: drop /FD flag"
+ecad0109 Merge "update gitignore"
+a681b4f4 Rename PRE_VP8 state to WEBP_HEADER
+ead4d478 Add incremental support for extended format files
+69d0f926 Makefile.vc: have 'all' target build everything
+52967498 Makefile.vc: flags cleanup
+c61baf0c Makefile.vc: drop /FD flag
+3a15125d update gitignore
+5167ca47 Merge "WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded."
+67708d67 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded.
+b68912af pngdec: Avoid a double-free.
+82abbe12 Merge "configure.ac: add AM_PROG_AR for automake >= 1.12"
+e7d9548c add WebPBlendAlpha() function to blend colors against background
+ed4dc717 configure.ac: add AM_PROG_AR for automake >= 1.12
+df4a406d Merge branch '0.3.0'
+1e0d4b8c Update ChangeLog (tag: v0.3.0-rc7, tag: v0.3.0)
+d52b405d Cosmetic fixes
+6cb4a618 misc style fix
+68111ab0 add missing YUVA->ARGB automatic conversion in WebPEncode()
+e9a7990b Cosmetic fixes
+403bfe82 Container spec: Clarify frame disposal
+2aaa423b Merge "add missing YUVA->ARGB automatic conversion in WebPEncode()"
+07d87bda add missing YUVA->ARGB automatic conversion in WebPEncode()
+142c4629 misc style fix
+3e7a13a0 Merge "Container spec: clarify the background color field" into 0.3.0
+14af7745 container doc: add a note about the 'ANMF' payload
+cc635efa Container spec: clarify the background color field
+e3e33949 container doc: move RIFF description to own section
+4299f398 libwebp/mux: fix double free
+33f9a692 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0
+a2a7b959 use WebPDataCopy() instead of re-coding it.
+6f18f12f demux: keep a frame tail pointer; used in AddFrame
+e5af49e9 add doc precision about WebPParseHeaders() return codes
+db46daab Merge "Makefile.vc: fix dynamic builds" into 0.3.0
+53c77afc Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0
+a5ebd143 gif2webp: Bgcolor fix for a special case
+6378f238 Merge "vwebp/animation: fix background dispose" into 0.3.0
+3c8eb9a8 fix bad saturation order in QuantizeBlock
+04c7a2ec vwebp/animation: fix background dispose
+81a50695 Makefile.vc: fix dynamic builds
+5f25c396 update ChangeLog (tag: v0.3.0-rc6)
+14d42af2 examples: don't use C99 %zu
+5ccf1fe5 update ChangeLog
+2560c243 update NEWS
+f43bafc3 Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0
+a788644f dwebp: warn when decoding animated webp's
+302efcdb Decode: return more meaningful error for animation
+ad452735 WebPBitstreamFeatures: add has_animation field
+783dfa49 disable FRGM decoding for good in libwebpmux
+4b956be0 Update ChangeLog
+ad8b86d7 update NEWS
+3e084f63 Merge "demux cosmetics: comments/rename internal function" into 0.3.0
+d3f8c621 Merge "move WebPFeatureFlags declaration" into 0.3.0
+7386fe50 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0
+d6cd4e90 Merge "bump decode abi" into 0.3.0
+17f8da5c bump decode abi
+97684ae2 Merge "add doc precision about WebPDemuxPartial()" into 0.3.0
+f933fd2a move WebPFeatureFlags declaration
+289bc47b libwebp{demux,mux}: install mux_types.h
+224e8d46 add doc precision about WebPDemuxPartial()
+4c18e80c demux cosmetics: comments/rename internal function
+7cfd1bf1 update AUTHORS
+401f7b85 Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0
+1fc8ffca Merge "makefile.unix: dist related changes" into 0.3.0
+8a89c6ed Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0
+f4ffb2d5 speed-up lossless (~3%) with ad-hoc histogram cost evaluation
+723847d5 gif2webp: only write error messages to stderr
+701b9e2a makefile.unix: dist related changes
+bb85b437 Merge "update NEWS" into 0.3.0
+59423a24 gif2webp: fix crash on open failure with libgif5
+9acb17de gif2webp: silence a unused param warning
+7d9fdc23 Merge "README updates" into 0.3.0
+5621934e Merge "build: fix install race on shared headers" into 0.3.0
+70809d89 Merge "bump version to 0.3.0" into 0.3.0
+d851cd1d demux: make the parse a bit more strict
+28bb4107 update NEWS
+cef93882 bump version to 0.3.0
+9048494d build: fix install race on shared headers
+1e67e8ef README updates
+42b611a4 Merge "configure: drop experimental from mux/demux" into 0.3.0
+096a8e32 Merge "vwebp: add color profile support" into 0.3.0
+ddfee5dc vwebp: add color profile support
+0d6927d3 Merge "Mark fragment options as experimental in webpmux" into 0.3.0
+5dbd4030 Mark fragment options as experimental in webpmux
+a0a6648c configure: drop experimental from mux/demux
+ee65bad8 Merge "add support for BITS > 32" into 0.3.0
+744930db add support for BITS > 32
+7dd288f0 cwebp: fix build
+19a8dd01 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0
+50eeddad Merge "examples: normalize icc related program arguments" into 0.3.0
+757f637f Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0
+b65c4b7c Makefile.vc: add libwebpdecoder target
+f8db7b4a Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0
+d99aa56f Makefile.vc: add vwebp.exe target
+013023e7 vwebp: replace doubles w/floats where appropriate
+9b3db894 README.mux: add version reference
+7b6a26cf Merge "cwebp: output metadata statistics" into 0.3.0
+d8dc72a0 examples: normalize icc related program arguments
+7bfc9056 Merge "make alpha unfilter work in-place" into 0.3.0
+0037b2d2 Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0
+166bf744 Merge "demux: disable fragment parsing" into 0.3.0
+126974b4 add LUT-free reference code for YUV->RGB conversion.
+0aef3ebd make alpha unfilter work in-place
+14ef5005 Merge "Remove 'status: experimental' from container spec" into 0.3.0
+d40c98e1 Merge "webpmux binary: tiny style fix" into 0.3.0
+0bc42689 cwebp: output metadata statistics
+bc039803 Merge "autoconf: normalize experimental define" into 0.3.0
+d1e21b13 Remove 'status: experimental' from container spec
+7681bb96 webpmux binary: tiny style fix
+a3dd3d0f avoid installing example_util.h
+252320e2 demux: disable fragment parsing
+537bde05 autoconf: normalize experimental define
+5e338e0b Merge changes I33e8a613,I8e8a7b44 into 0.3.0
+d9d0ea1b Merge changes If21e3ec7,I991fc30b into 0.3.0
+627f5ca6 automake: add reference to libwebp for mux/demux
+eef73d07 don't consolidate proba stats too often
+05ec4cc2 libwebp{,decoder}.pc: add pthread flags
+1bfcf5bf add libwebpmux.pc
+26ca843d add libwebpdemux.pc
+69e25906 Merge "Tune Lossless compression for lower qualities."
+0478b5d2 Tune Lossless compression for lower qualities.
+39f7586f add a mention of parallel alpha encoding in the NEWS
+5a21d967 Merge "1.5x-2x faster encoding for method 3 and up"
+9bfbdd14 1.5x-2x faster encoding for method 3 and up
+27dc741b Correct frame options order in README.mux
+be2fd173 Mux: fix a scenario with bad ANMF/FRGM size
+19eb012c Merge "Demux: Add option to get frame count using GetI()"
+7368b8cb Merge "WebPGetFeatures() out of if condition for clarity."
+f604c9a4 Merge "fix windows build"
+153f94e8 fix windows build
+847b4924 Merge "vwebp: use magenta for 'i'nfo display"
+25ea46bd Merge "vwebp: add keyboard shortcuts to help output"
+bea7ccaf vwebp: use magenta for 'i'nfo display
+8fab161a webpmux: correct -frame param order in help output
+03cc23d6 vwebp: add keyboard shortcuts to help output
+068eba8d Demux: Add option to get frame count using GetI()
+988b8f56 WebPGetFeatures() out of if condition for clarity.
+6933d910 Merge "gif2webp: Be lenient about background color index."
+4d0f7c55 Merge "WebPGetFeatures() behavior change:"
+fdeeb01d gif2webp: Be lenient about background color index.
+ad250320 Merge "multi-threaded alpha encoding for lossy"
+4e32d3e1 Merge "fix compilation of token.c"
+f817930a multi-threaded alpha encoding for lossy
+88050351 fix compilation of token.c
+fc816219 code using the actual values for num_parts_, not the ones from config
+72655350 Merge "move the config check from .c to .h"
+dd9e76f7 move the config check from .c to .h
+956b217a WebPGetFeatures() behavior change:
+df02e4ce WebPDemuxGetI behavior change:
+633c004d Merge "rebalance method tools (-m) for methods [0..4]"
+58ca6f65 rebalance method tools (-m) for methods [0..4]
+7648c3cc Merge "describe rd-opt levels introduce VP8RDLevel enum"
+67fb1003 Merge "autoconf: enable silent-rules by default"
+a5042a32 GetVersion() methods for mux and demux
+5189957e describe rd-opt levels introduce VP8RDLevel enum
+4e094ace autoconf: enable silent-rules by default
+b7eaa85d inline VP8LFastLog2() and VP8LFastSLog2 for small values
+5cf7792e split quant_levels.c into decoder and encoder version
+e5d3ffe2 Merge "Update code example in README.mux"
+ac5a9156 Update code example in README.mux
+38a91e99 Add example code snippet for demux API
+5f557f3c README.mux: add info about Demux API and vwebp
+c0ba0903 backward_references: avoid signed integer overflow
+943386db disable SSE2 for now
+9479fb7d lossless encoding speedup
+ec2030a8 merge two lines together
+b67956c0 Merge "Remove ReadOneBit() and ReadSymbolUnsafe()"
+1667bded Remove ReadOneBit() and ReadSymbolUnsafe()
+3151669b wicdec + dwebp cosmetics: normalize formatting
+92668da6 change default filtering parameters: * type is now 'strong' * strength is now '60'
+b7490f85 introduce WEBP_REFERENCE_IMPLEMENTATION compile option
+33838857 faster decoding (3%-6%)
+5c3e381b Merge "add a -jpeg_like option"
+c2311046 remove unused declaration of VP8Zigzag
+36152957 Merge "wicdec: add alpha support for paletted formats"
+c9f16490 wicdec: add alpha support for paletted formats
+1262f81e Merge "wicdec: silence some warnings"
+e7ea61eb wicdec: silence some warnings
+23c0f354 fix missing intptr_t->int cast for MSVC
+e895059a add a -jpeg_like option
+1f803f64 Merge "Tune alpha quality mapping to more reasonable values."
+1267d498 Tune alpha quality mapping to more reasonable values.
+043076e2 Merge "speed-up lossless in BackwardTrace"
+f3a44dcd remove one malloc from TraceBackwards()
+0fc1a3a0 speed-up lossless in BackwardTrace
+7c732e59 cwebp: centralize WebPCleanupTransparentArea()
+7381254e Merge "wicdec: add ICC profile extraction"
+e83ff7de wicdec: add ICC profile extraction
+146c6e3b Merge "cosmetics: pngdec: normalize default label location"
+a8f549d7 Merge "manpages: italicize option parameters"
+e118db83 Merge "encode.h: note the need to free() WebPMemoryWriter"
+1dfee6db cosmetics: pngdec: normalize default label location
+14c38200 manpages: italicize option parameters
+7defbfad encode.h: note the need to free() WebPMemoryWriter
+88d382a0 cwebp: cleanup after memory_writer
+12d6cecf fix extra space in dwebp.1 man
+b01681a9 Fix for demuxer frame iteration:
+56c12aa6 Demuxer creation fix:
+66c810bc add a -yuv option to dwebp (very similar to -pgm)
+841a3ba5 Merge "Remove -Wshadow warnings."
+8fd02527 Merge "upsampling_neon.c: fix build"
+6efed268 Remove -Wshadow warnings.
+60904aa6 Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer."
+b7adf376 allow WebPINewRGB/YUVA to be passed a NULL output buffer.
+27f8f742 upsampling_neon.c: fix build
+06b9cdf1 gitignore: add IOS related directories
+f112221e Merge "Fix more comments for iobuild.sh"
+fe4d25dd Fix more comments for iobuild.sh
+1de3e252 Merge "NEON optimised yuv to rgb conversion"
+090b708a NEON optimised yuv to rgb conversion
+daa06476 Merge "Add ios build script for building iOS library."
+79fe39e2 Add ios build script for building iOS library.
+126c035f remove some more -Wshadow warnings
+522e9d61 Merge "cwebp: enable '-metadata'"
+76ec5fa1 cwebp: enable '-metadata'
+aeb91a9d Merge "cosmetics: break a few long lines"
+be7c96b0 cosmetics: break a few long lines
+cff8ddb6 Merge "add libwebpdecoder.pc"
+93148ab8 Merge "libwebp.pc.in: detab"
+6477f955 Merge "Makefile.vc: normalize path separator"
+bed1ed7c add libwebpdecoder.pc
+46168b2d libwebp.pc.in: detab
+a941a346 Fixed few nits in the build files.
+dd7a49b2 Makefile.vc: normalize path separator
+9161be86 Merge "cwebp: extract WIC decoding to its own module"
+08e7c58e Merge "Provide an option to build decoder library."
+0aeba528 Provide an option to build decoder library.
+757ebcb1 catch malloc(0)/calloc(0) with an assert
+152ec3d2 Merge "handle malloc(0) and calloc(0) uniformly on all platforms"
+a452a555 cwebp: extract WIC decoding to its own module
+2b252a53 Merge "Provide option to swap bytes for 16 bit colormodes"
+94a48b4b Provide option to swap bytes for 16 bit colormodes
+42f8f934 handle malloc(0) and calloc(0) uniformly on all platforms
+8b2152c5 Merge "add an extra assert to check memory bounds"
+0d19fbff remove some -Wshadow warnings
+cd22f655 add an extra assert to check memory bounds
+8189feda Merge "Add details and reference about the YUV->RGB conversion"
+1d2702b1 Merge "Formatting fixes in lossless bitstream spec"
+8425aaee Formatting fixes in lossless bitstream spec
+a556cb1a Add details and reference about the YUV->RGB conversion
+d8f21e0b add link to SSIM description on Wikipedia
+18e9167e Merge "WebP-lossless spec clarifications:"
+98e25b9b Merge "cwebp: add -metadata option"
+f01c2a53 WebP-lossless spec clarifications:
+f4a97970 Merge "Disto4x4 and Disto16x16 in NEON"
+47b7b0ba Disto4x4 and Disto16x16 in NEON
+7eaee9f1 cwebp: add -metadata option
+36c52c2c tiffdec: use toff_t for exif ifd offset
+7c8111e4 Merge "cwebp/tiffdec: add TIFF metadata extraction"
+e6409adc Remove redundant include from dsp/lossless code.
+1ab5b3a7 Merge "configure: fix --with-gifincludedir"
+03c749eb configure: fix --with-gifincludedir
+8b650635 multiple libgif versions support for gif2webp
+476e293f gif2webp: Use DGifOpenFileName()
+b50f277b tiffdec: correct format string
+2b9048e3 Merge "tiffdec: check error returns for width/height"
+a1b5a9a3 Merge "cwebp/tiff: use the first image directory"
+079423f5 tiffdec: check error returns for width/height
+d62824af Merge "cwebp/jpegdec: add JPEG metadata extraction"
+03afaca4 Merge "cwebp: add PNG metadata extraction"
+2c724968 cwebp/jpegdec: add JPEG metadata extraction
+dba64d91 cwebp: add PNG metadata extraction
+1f075f89 Lossless spec corrections/rewording/clarifications
+2914ecfd cwebp/tiffdec: add TIFF metadata extraction
+d82a3e33 More corrections/clarifications in lossless spec:
+bd002557 cwebp/tiff: use the first image directory
+df7aa076 Merge "Cleanup around jpegdec"
+0f57dcc3 decoding speed-up (~1%)
+bcec339b Lossless bitstream clarification:
+6bf20874 add examples/metadata.c
+207f89c0 Merge "configure: add libwebpdemux status to summary"
+1bd287a6 Cleanup around jpegdec
+91455679 Merge "cosmetics: use '== 0' in size checks"
+d6b88b76 cosmetics: use '== 0' in size checks
+d3dace2f cosmetics: jpegdec
+2f69af73 configure: add libwebpdemux status to summary
+1c1c5646 cwebp: extract tiff decoding to its own module
+6a871d66 cwebp: extract jpeg decoding to its own module
+2ee228f9 cwebp: extract png decoding to its own module
+4679db00 Merge "cwebp: add metadata framework"
+63aba3ae cwebp: add metadata framework
+931bd516 lossless bitstream: block size bits correction
+e4fc4c1c lossless bitstream: block size bits correction
+d65ec678 fix build, move token.c to src/enc/
+657f5c91 move token buffer to its own file (token.c)
+c34a3758 introduce GetLargeValue() to slim-fast GetCoeffs().
+d5838cd5 faster non-transposing SSE2 4x4 FTransform
+f76191f9 speed up GetResidualCost()
+ba2aa0fd Add support for BITS=24 case
+2e7f6e8e makefile.unix: Dependency on libraries
+dca84219 Merge "Separate out mux and demux code and libraries:"
+23782f95 Separate out mux and demux code and libraries:
+bd56a01f configure: add summary output
+90e5e319 dwebp manual: point to webpmux, gif2webp.
+540790ca gif2webp.c: add a note about prerequisites
+d1edf697 cwebp man page: meaning of '-q' for lossy/lossless
+79efa1d0 Add man page for gif2webp utility
+2243e40c Merge "gif2webp build support with autoconf tools"
+c40efca1 gif2webp build support with autoconf tools
+6523e2d4 WebP Container:
+4da788da Merge "simplify the fwd transform"
+42c3b550 simplify the fwd transform
+41a6ced9 user GLfloat instead of float
+b5426119 fix indentation
+68f282f7 * handle offset in anim viewer 'vwebp' * fix gif2webp to handle disposal method and odd offset correctly
+118cb312 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case"
+8a7c3cc8 Merge "Change the order of -frame argument to be more natural"
+99e0a707 Merge "Simplify the texture evaluation Disto4x4()"
+0f923c3f make the bundling work in a tmp buffer
+e5c3b3f5 Simplify the texture evaluation Disto4x4()
+48600084 Change the order of -frame argument to be more natural
+35bfd4c0 add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case
+a7305c2e Clarification for unknown chunks
+4c4398e2 Refine WebP Container Spec wrt unknown chunks.
+2ca642e0 Rectify WebPMuxGetFeatures:
+7caab1d8 Some cosmetic/comment fixes.
+60b2651a Merge "Write a GIF to WebP converter based on libgif."
+c7127a4d Merge "Add NEON version of FTransformWHT"
+11b27212 Write a GIF to WebP converter based on libgif.
+e9a15a37 ExUtilWriteFile() to write memory segment to file
+74356eb5 Add a simple cleanup step in mux assembly:
+51bb1e5d mux.h: correct WebPDemuxSelectFragment() prototype
+22a0fd9d Add NEON version of FTransformWHT
+fa30c863 Update mux code to match the spec wrt animation
+d9c5fbef by-pass Analysis pass in case segments=1
+d2ad4450 Merge changes Ibeccffc3,Id1585b16
+5c8be251 Merge "Chunk fourCCs for XMP/EXIF"
+a00a3daf Use 'frgm' instead of 'tile' in webpmux parameters
+81b8a741 Design change in ANMF and FRGM chunks:
+f903cbab Chunk fourCCs for XMP/EXIF
+812933d6 Tune performance of HistogramCombine
+52ad1979 Animation specification in container spec
+001b9302 Image fragment specification in container spec
+391f9db9 Ordering of description of bits in container spec
+d5735776 Metadata specification in container spec
+1c4609b1 Merge commit 'v0.2.1'
+0ca584cb Merge "Color profile specification in container spec"
+e8b41ad1 add NEON asm version for WHT inverse transform
+af6f0db2 Color profile specification in container spec
+a61a824b Merge "Add NULL check in chunk APIs"
+0e8b7eed fix WebPPictureView() unassigned strides
+75e5f17e ARM/NEON: 30% encoding speed-up
+02b43568 Add NULL check in chunk APIs
+a0770727 mux struct naming
+6c66dde8 Merge "Tune Lossless encoder"
+ab5ea217 Tune Lossless encoder
+74fefc8c Update ChangeLog (tag: v0.2.1, origin/0.2.0)
+92f8059c Rename some chunks:
+3bb4bbeb Merge "Mux API change:"
+d0c79f05 Mux API change:
+abc06044 Merge "update NEWS" into 0.2.0
+57cf313b update NEWS
+25f585c4 bump version to 0.2.1
+fed7c048 libwebp: validate chunk size in ParseOptionalChunks
+552cd9bc cwebp (windows): fix alpha image import on XP
+b14fea99 autoconf/libwebp: enable dll builds for mingw
+4a8fb272 [cd]webp: always output windows errors
+d6621580 fix double to float conversion warning
+72b96a69 cwebp: fix jpg encodes on XP
+734f762a VP8LAllocateHistogramSet: fix overflow in size calculation
+f9cb58fb GetHistoBits: fix integer overflow
+b30add20 EncodeImageInternal: fix uninitialized free
+3de58d77 fix the -g/O3 discrepancy for 32bit compile
+77aa7d50 fix the BITS=8 case
+e5970bda Make *InitSSE2() functions be empty on non-SSE2 platform
+ef5cc47e make *InitSSE2() functions be empty on non-SSE2 platform
+c4ea259d make VP8DspInitNEON() public
+8344eadf Merge "libwebp: validate chunk size in ParseOptionalChunks"
+4828bb93 Merge "cwebp (windows): fix alpha image import on XP"
+30763333 libwebp: validate chunk size in ParseOptionalChunks
+70481898 AccumulateLSIM: fix double -> float warnings
+eda8ee4b cwebp (windows): fix alpha image import on XP
+c6e98658 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace"
+f0360b4f add EXPERIMENTAL code for YUV-JPEG colorspace
+f86e6abe add LSIM metric to WebPPictureDistortion()
+c3aa215a Speed up HistogramCombine for lower qualities.
+1765cb1c Merge "autoconf/libwebp: enable dll builds for mingw"
+a13562e8 autoconf/libwebp: enable dll builds for mingw
+9f469b57 typo: no_fancy -> no_fancy_upsampling
+1a27f2f8 Merge "fix double to float conversion warning"
+cf1e90de Merge "cwebp: fix jpg encodes on XP"
+f2b5d19b [cd]webp: always output windows errors
+e855208c fix double to float conversion warning
+ecd66f77 cwebp: fix jpg encodes on XP
+7b3eb372 Tune lossless compression to get better gains.
+ce8bff45 Merge "VP8LAllocateHistogramSet: fix overflow in size calculation"
+ab5b67a1 Merge "EncodeImageInternal: fix uninitialized free"
+7fee5d12 Merge "GetHistoBits: fix integer overflow"
+a6ae04d4 VP8LAllocateHistogramSet: fix overflow in size calculation
+80237c43 GetHistoBits: fix integer overflow
+8a997235 EncodeImageInternal: fix uninitialized free
+0b9e6829 minor cosmetics
+a792b913 fix the -g/O3 discrepancy for 32bit compile
+73ba4357 Merge "detect and merge similar segments"
+fee66275 detect and merge similar segments
+0c44f415 src/webp/*.h: don't forward declare enums in C++
+d7a5ac86 vwebp: use demux interface
+931e0ea1 Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};""
+8f216f7e remove cases of equal comparison for qsort()
+28d25c82 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"
+2afee60a speed up for ARM using 8bit for boolean decoder
+5725caba new segmentation algorithm
+2cf1f815 Merge "fix the BITS=8 case"
+12f78aec fix the BITS=8 case
+6920c71f fix MSVC warnings regarding implicit uint64 to uint32 conversions
+f6c096aa webpmux binary: Rename 'xmp' option to 'meta'
+ddfe871a webpmux help correction
+b7c55442 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform"
+1c04a0d4 Common APIs for chunks metadata and color profile.
+2a3117a1 Merge "Create WebPMuxFrameInfo struct for Mux APIs"
+5c3a7231 Make *InitSSE2() functions be empty on non-SSE2 platform
+7c6e60f4 make *InitSSE2() functions be empty on non-SSE2 platform
+c7eb4576 make VP8DspInitNEON() public
+ab3234ae Create WebPMuxFrameInfo struct for Mux APIs
+e3990fd8 Alignment fixes
+e55fbd6d Merge branch '0.2.0'
+4238bc0a Update ChangeLog (tag: v0.2.0)
+c655380c dec/io.c: cosmetics
+fe1958f1 RGBA4444: harmonize lossless/lossy alpha values
+681cb30a fix RGBA4444 output w/fancy upsampling
+f06c1d8f Merge "Alignment fix" into 0.2.0
+f56e98fd Alignment fix
+6fe843ba avoid rgb-premultiply if there's only trivial alpha values
+528a11af fix the ARGB4444 premultiply arithmetic
+a0a48855 Lossless decoder fix for a special transform order
+62dd9bb2 Update encoding heuristic w.r.t palette colors.
+6f4272b0 remove unused ApplyInverseTransform()
+93bf0faa Update ChangeLog (tag: v0.2.0-rc1)
+5934fc59 update AUTHORS
+014a711d update NEWS
+43b0d610 add support for ARGB -> YUVA conversion for lossless decoder
+33705ca0 bump version to 0.2.0
+c40d7ef1 fix alpha-plane check + add extra checks
+a06f8023 MODE_YUVA: set alpha to opaque if the image has none
+52a87dd7 Merge "silence one more warning" into 0.2.0
+3b023093 silence one more warning
+f94b04f0 move some RGB->YUV functions to yuv.h
+4b71ba03 README: sync [cd]webp help output
+c9ae57f5 man/dwebp.1: add links to output file format details
+292ec5cc quiet a few 'uninitialized' warnings
+4af3f6c4 fix indentation
+9b261bf5 remove the last NOT_HAVE_LOG2 instances
+323dc4d9 remove use of log2(). Use VP8LFastLog2() instead.
+8c515d54 Merge "harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc" into 0.2.0
+d4b4bb02 Merge changes I46090628,I1a41b2ce into 0.2.0
+bff34ac1 harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc
+a3c063c7 Merge "extra size check for security" into 0.2.0
+5e796300 Merge "WebPEncode: clear stats at the start of encode" into 0.2.0
+f1edf62f Merge "rationalize use of color-cache" into 0.2.0
+c1933317 extra size check for security
+906be657 rationalize use of color-cache
+dd1c3873 Add image-hint for low-color images.
+4eb7aa64 Merge "WebPCheckMalloc() and WebPCheckCalloc():" into 0.2.0
+80cc7303 WebPCheckMalloc() and WebPCheckCalloc():
+183cba83 check VP8LBitWriterInit return
+cbfa9eec lossless: fix crash on user abort
+256afefa cwebp: exit immediately on version mismatch
+475d87d7 WebPEncode: clear stats at the start of encode
+a7cc7291 fix type and conversion warnings
+7d853d79 add stats for lossless
+d39177b7 make QuantizeLevels() store the sum of squared error
+5955cf5e replace x*155/100 by x*101581>>16
+7d732f90 make QuantizeLevels() store the sum of squared error
+e45a446a replace x*155/100 by x*101581>>16
+159b75d3 cwebp output size consistency:
+cbee59eb Merge commit 'v0.1.99'
+1889e9b6 dwebp: report -alpha option
+3bc3f7c0 Merge "dwebp: add PAM output support" into 0.2.0
+d919ed06 dwebp: add PAM output support
+85e215d3 README/manpages/configure: update website link
+c3a207b9 Update ChangeLog (tag: v0.1.99)
+d1fd7826 Merge "add extra precision about default values and behaviour" into 0.2.0
+efc826e0 add extra precision about default values and behaviour
+9f29635d header/doc clean up
+ff9fd1ba Makefile.vc: fix webpmux.exe *-dynamic builds
+8aacc7b0 remove INAM, ICOP, ... chunks from the test webp file.
+2fc13015 harmonize authors as "Name (mail@address)"
+4a9f37b7 Merge "update NEWS" into 0.2.0
+7415ae13 makefile.unix: provide examples/webpmux target
+ce82cedc update NEWS
+641e28e8 Merge "man/cwebp.1: wording, change the date" into 0.2.0
+c37c23e5 README: cosmetics
+3976dcd5 man/cwebp.1: wording, change the date
+3e5bbe1c Merge "rename 'use_argb_input' to 'use_argb'" into 0.2.0
+ce90847a Merge "add some padding bytes areas for later use" into 0.2.0
+2390dabc Merge "fixing the findings by Frederic Kayser to the bitstream spec" into 0.2.0
+02751591 add a very crude progress report for lossless
+a4b9b1c6 Remove some unused enum values.
+dd108176 rename 'use_argb_input' to 'use_argb'
+90516ae8 add some padding bytes areas for later use
+d03b2503 fixing the findings by Frederic Kayser to the bitstream spec
+ce156afc add missing ABI compatibility checks
+9d45416a Merge "Doc: container spec text tweaks" into 0.2.0
+4e2e0a8c Doc: container spec text tweaks
+f7f16a29 add ABI compatibility check
+2a775570 Merge "swig: add WebPEncodeLossless* wrappers" into 0.2.0
+a3ec6225 mux.h: remove '* const' from function parameters
+31426eba encode.h: remove '* const' from function parameters
+9838e5d5 decode.h: remove '* const' from function parameters
+4972302d swig: add WebPEncodeLossless* wrappers
+9ff00cae bump encoder/decoder versions
+c2416c9b add lossless quick encoding functions to the public API
+4c1f5d64 Merge "NEWS: mention decode_vp8.h is no longer installed" into 0.2.0
+6cb2277d NEWS: mention decode_vp8.h is no longer installed
+d5e5ad63 move decode_vp8.h from webp/ to dec/
+8d3b04a2 Merge "header clean-up" into 0.2.0
+02201c35 Merge "remove one malloc() by making color_cache non dynamic" into 0.2.0
+d708ec14 Merge "move MIN/MAX_HISTO_BITS to format_constants.h" into 0.2.0
+ab2da3e9 Merge "add a malloc() check" into 0.2.0
+2d571bd8 add a malloc() check
+7f0c178e remove one malloc() by making color_cache non dynamic
+6569cd7c Merge "VP8LFillBitWindow: use 64-bit path for msvc x64 builds" into 0.2.0
+23d34f31 header clean-up
+2a3ab6f9 move MIN/MAX_HISTO_BITS to format_constants.h
+985d3da6 Merge "shuffle variables in HashChainFindCopy" into 0.2.0
+cdf885c6 shuffle variables in HashChainFindCopy
+c3b014db Android.mk: add missing lossless files
+8c1cc6b5 makefile.unix dist: explicitly name installed includes
+7f4647ee Merge "clarify the colorspace naming and byte ordering of decoded samples" into 0.2.0
+cbf69724 clarify the colorspace naming and byte ordering of decoded samples
+857650c8 Mux: Add WebPDataInit() and remove WebPImageInfo
+ff771e77 don't install webp/decode_vp8.h
+596dff78 VP8LFillBitWindow: use 64-bit path for msvc x64 builds
+3ca7ce98 Merge "doc: remove non-finalized chunk references" into 0.2.0
+1efaa5a3 Merge "bump versions" into 0.2.0
+51fa13e1 Merge "README: update cwebp help output" into 0.2.0
+12f9aede README: update cwebp help output
+f0b5defb bump versions
+4c42a61b update AUTHORS
+6431a1ce doc: remove non-finalized chunk references
+8130c4cc Merge "build: remove libwebpmux from default targets/config"
+23b44438 Merge "configure: broaden test for libpng-config"
+85bff2cd Merge "doc: correct lossless prefix coding table & code"
+05108f6e Merge "More spec/code matching in mux:"
+6808e69d More spec/code matching in mux:
+bd2b46f5 Merge "doc/webp-container-spec: light cosmetics"
+20ead329 doc/webp-container-spec: light cosmetics
+1d40a8bc configure: add pthread detection
+b5e9067a fix some int <-> size_t mix for buffer sizes
+e41a7596 build: remove libwebpmux from default targets/config
+0fc2baae configure: broaden test for libpng-config
+45b8272c Merge "restore authorship to lossless bitstream doc"
+06ba0590 restore authorship to lossless bitstream doc
+44a09a3c add missing description of the alpha filtering methods
+63db87dd Merge "vwebp: add checkboard background for alpha display"
+a73b8978 vwebp: add checkboard background for alpha display
+939158ce Merge "vwebp: fix info display"
+b35c07d9 vwebp: fix info display
+48b39eb1 fix underflow for very short bitstreams
+7e622984 cosmetics: param alignment, manpage wording
+1bd7dd50 Merge changes I7b0afb0d,I7ecc9708
+ac69e63e Merge "Updated cwebp man's help for Alpha & Lossless."
+c0e8859d Get rid of image_info_ from WebPChunk struct.
+135ca69e WebP Container Spec:
+eb6f9b8a Updated cwebp man's help for Alpha & Lossless.
+0fa844fb cosmetic fixes on assert and 'const' where applicable
+7f22bd25 check limit of width * height is 32 bits
+16c46e83 autoconf/make: cosmetics: break long lines
+ab22a07a configure: add helper macro to define --with-*
+c17699b3 configure: add libtiff test
+0e09732c Merge "cwebp: fix crash with yuv input + lossless"
+88a510ff Merge "fix big-endian VP8LWriteBits"
+da99e3bf Merge "Makefile.vc: split mux into separate lib"
+7bda392b cwebp: fix crash with yuv input + lossless
+f56a369a fix big-endian VP8LWriteBits
+54169d6c Merge "cwebp: name InputFileFormat members consistently"
+e2feefa9 Makefile.vc: split mux into separate lib
+27caa5aa Merge "cwebp: add basic TIFF support"
+d8921dd4 cwebp: name InputFileFormat members consistently
+6f76d246 cwebp: add basic TIFF support
+4691407b Merge changes If39ab7f5,I3658b5ae
+cca7c7b8 Fixed nit: 10 -> 10.f
+5d09a244 WebPMuxCreate() error handling:
+777341c3 Fix a memleak in WebPMuxCreate()
+61c9d161 doc: correct lossless prefix coding table & code
+4c397579 Merge "mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN"
+e4e36cc6 Merge "Mux: Allow only some frames/tiles to have alpha."
+ad2aad3c Merge "WebP Decoding error handling:"
+97649c8f Mux: Allow only some frames/tiles to have alpha.
+f864be3b Lower the quality settings for Alpha encoding.
+3ba81bbe WebP Decoding error handling:
+fcc69923 add automatic YUVA/ARGB conversion during WebPEncode()
+802e012a fix compilation in non-FANCY_UPSAMPLING mode
+e012dfd9 make width/height coding match the spec
+228d96a5 mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN
+637a314f remove the now unused *KeepA variants
+d11f6fcc webpmux returns error strings rather than numbers
+fcec0593 makefile.unix: cwebp: fix OSX link
+6b811f1b Merge "doc: remove lossless pdf"
+c9634821 doc: remove lossless pdf
+b9ae4f0d cosmetics after mux changes b74ed6e, b494ad5
+b494ad50 Mux: only allow adding frame/tiles at the end.
+2c341b0e Merge "Added image characteristic hint for the codec."
+d373076a Added image characteristic hint for the codec.
+2ed2adb5 Merge "msvc: add intrinsic based BitsLog2Floor"
+e595e7c5 Merge "add demux.c to the makefiles"
+da47b5bd Merge "demux: add {Next,Prev}Chunk"
+e5f46742 add demux.c to the makefiles
+4708393c demux: add {Next,Prev}Chunk
+e8a0a821 demux: quiet msvc warnings
+7f8472a6 Update the WebP Container Spec.
+31b68fe6 cleanup WebPPicture struct and API
+9144a186 add overflow check before calling malloc()
+81720c91 consistency cosmetics
+2ebe8394 Merge "Add kramdown version information to README"
+71443084 enc/vp8l.c: fix build
+b7ac19fe Add kramdown version information to README
+efdcb667 Merge "Edit for consistency, usage and grammar."
+08220102 Enable alpha in vvwebp
+8de9a084 Merge "Mux API change:"
+b74ed6e7 Mux API change:
+233a589e take picture->argb_stride into account for lossless coding
+04e33f17 Edit for consistency, usage and grammar.
+a575b4bc Merge "cosmetics: add missing const"
+8d99b0f4 Merge "cosmetics: remove unimplemented function proto"
+69d02217 cosmetics: add missing const
+5b08318b cosmetics: remove unimplemented function proto
+b7fb0ed5 Log warning for unsupported options for lossless.
+e1f769fe msvc: add intrinsic based BitsLog2Floor
+8a69c7d8 Bug-fix: Clamp backward dist to 1.
+b5b6ac97 Merge "Bring the special writer 'WebPMemoryWriter' to public API"
+a6a1909f Merge "Fix floating point exception with cwebp -progress"
+f2cee067 Fix floating point exception with cwebp -progress
+91b7a8c7 Bring the special writer 'WebPMemoryWriter' to public API
+310e2972 support resize and crop for RGBA input
+a89835d3 Merge changes Ice662960,Ie8d7aa90,I2d996d5e,I01c04772
+ce614c0c Merge "dec/vp8: avoid setting decoder status twice"
+900285da dec/vp8: avoid setting decoder status twice
+8227adc8 Merge changes I6f02b0d0,I5cbc9c0a,I9dd9d4ed,Id684d2a1
+dcda59c1 Merge "demux: rename SetTile to SelectTile"
+622ef12e demux: rename SetTile to SelectTile
+81ebd375 Merge "demux: add {Next,Prev}Frame"
+02dd37a2 demux: add {Next,Prev}Frame
+4b79fa59 Merge "Limit the maximum size of huffman Image to 16MB."
+9aa34b34 Manually number "chapters," as chapter numbers are used in the narrative.
+2a4c6c29 Re-wrap at <= 72 columns
+a45adc19 Apply inline emphasis and monospacing, per gdoc / PDF
+91011206 Incorporate gdoc changes through 2012-06-08
+7a182487 Removed CodeRay syntax declarations ...
+b3ec18c5 Provide for code-block syntax highlighting.
+709d7702 Replace high ASCII artifacts (curly quotes, etc.).
+930e8abb Lossless WebP doc largely ported to markdown text.
+18cae37b msvc: silence some build warnings
+b3923084 Limit the maximum size of huffman Image to 16MB.
+f180df2a Merge "libwebp/demux: add Frame/Chunk iteration"
+2bbe1c9a Merge "Enable lossless encoder code"
+d0601b01 Merge changes I1d97a633,I81c59093
+78f3e345 Enable lossless encoder code
+d974a9cc Merge "libwebp/demux: add simple format parsing"
+26bf2232 Merge "libwebp: add WebPDemux stub functions"
+2f666688 Merge "modify WebPParseHeaders to allow reuse by GetFeatures"
+b402b1fb libwebp/demux: add Frame/Chunk iteration
+ad9ada3b libwebp/demux: add WebPDemuxGetI
+2f2d4d58 libwebp/demux: add extended format parsing
+962dcef6 libwebp/demux: add simple format parsing
+f8f94081 libwebp: add WebPDemux stub functions
+fb47bb5c Merge "NumNamedElements() should take an enum param."
+7c689805 Fix asserts in Palette and BackwardReference code.
+fbdcb7ea NumNamedElements() should take an enum param.
+fb4943bd modify WebPParseHeaders to allow reuse by GetFeatures
+3697b5ce write an ad-hoc EncodeImageInternal variant
+eaee9e79 Bug-Fix: Decode small (less than 32 bytes) images.
+0bceae48 Merge "cwebp: fix alpha reporting in stats output"
+0424b1ef Rebase default encoding settings.
+c71ff9e3 cwebp: fix alpha reporting in stats output
+e2ffe446 Merge "Stop indefinite recursion for Huffman Image."
+70eb2bd6 Stop indefinite recursion for Huffman Image.
+f3bab8eb Update vwebp
+6d5c797c Remove support for partial files in Mux.
+f1df5587 WebPMuxAssemble() returns WebPData*.
+814a0639 Rename 'Add' APIs to 'Set'.
+bbb0218f Update Mux psuedo-code examples.
+4fc4a47f Use WebPData in MUX set APIs
+c67bc979 Merge "add WebPPictureImportRGBX() and WebPPictureImportBGRX()"
+27519bc2 add WebPPictureImportRGBX() and WebPPictureImportBGRX()
+f80cd27e factorize code in Import()
+9b715026 histogram: add log2 wrapper
+8c34378f Merge "fix some implicit type conversion warnings"
+42f6df9d fix some implicit type conversion warnings
+250c16e3 Merge "doc: update lossless pdf"
+9d9daba4 Merge "add a PDF of the lossless spec"
+8fbb9188 prefer webp/types.h over stdint.h
+0ca170c2 doc: update lossless pdf
+0862ac6e add a PDF of the lossless spec
+437999fb introduce a generic WebPPictureHasTransparency() function
+d2b6c6c0 cosmetic fixes after Idaba281a
+b4e6645c Merge "add colorspace for premultiplied alpha"
+48f82757 add colorspace for premultiplied alpha
+069f903a Change in lossless bit-stream.
+5f7bb3f5 Merge "WebPReportProgress: use non-encoder specific params"
+f18281ff WebPReportProgress: use non-encoder specific params
+9ef32283 Add support for raw lossless bitstream in decoder.
+7cbee29a Fix bug: InitIo reseting fancy_upsampling flag.
+880fd98c vwebp: fix exit w/freeglut
+1875d926 trap two unchecked error conditions
+87b4a908 no need to have mux.h as noinst clause in enc/
+88f41ec6 doc: fix bit alignment in VP8X chunk
+52f5a4ef Merge "fix bug with lossy-alpha output stride"
+3bde22d7 fix bug with lossy-alpha output stride
+42d61b6d update the spec for the lossy-alpha compression methods.
+e75dc805 Move some more defines to format_constants.h
+c13f6632 Move consts to internal header format_constants.h
+7f2dfc92 use a bit-set transforms_seen_ instead of looping
+18da1f53 modulate alpha-compression effort according to config.method
+f5f2fff6 Merge "Alpha flag fix for lossless."
+c975c44e Alpha flag fix for lossless.
+4f067fb2 Merge "Android: only build dec_neon with NEON support"
+255c66b4 Android: only build dec_neon with NEON support
+8f9117a9 cosmetics: signature fixes
+39bf5d64 use header-less lossless bitstream for alpha channel
+75d7f3b2 Merge "make input data be 'const' for VP8LInverseTransform()"
+9a721c6d make input data be 'const' for VP8LInverseTransform()
+9fc64edc Disallow re-use of same transformation.
+98ec717f use a function pointer for ProcessRows()
+f7ae5e37 cosmetics: join line
+140b89a3 factor out buffer alloc in AllocateARGBBuffers()
+a107dfa8 Rectify WebPParseOptionalChunks().
+237eab67 Add two more color-spaces for lossless decoding.
+27f417ab fix orthographic typo
+489ec335 add VP8LEncodeStream() to compress lossless image stream
+fa8bc3db make WebPEncodingSetError() take a const picture
+638528cd bitstream update for lossy alpha compression
+d73e63a7 add DequantizeLevels() placeholder
+ec122e09 remove arch-dependent rand()
+d40e7653 fix alignment
+1dd6a8b6 Merge "remove tcoder, switch alpha-plane compression to lossless"
+3e863dda remove tcoder, switch alpha-plane compression to lossless
+8d77dc29 Add support for lossless in mux:
+831bd131 Make tile size a function of encoding method.
+778c5228 Merge "remove some variable shadowing"
+817c9dce Few more HuffmanTreeToken conversions.
+37a77a6b remove some variable shadowing
+89c07c96 Merge "normalize example header includes"
+4aff411f Merge "add example_util.[hc]"
+00b29e28 normalize example header includes
+061263a7 add example_util.[hc]
+c6882c49 merge all tree processing into a single VP8LProcessTree()
+9c7a3cf5 fix VP8LHistogramNumCodes to handle the case palette_code_bits == 0
+b5551d2e Merge "Added HuffmanTreeCode Struct for tree codes."
+8b85d01c Added HuffmanTreeCode Struct for tree codes.
+093f76d8 Merge "Allocate single memory in GetHuffBitLengthsAndCodes."
+41d80494 Allocate single memory in GetHuffBitLengthsAndCodes.
+1b04f6d2 Correct size in VP8L header.
+2924a5ae Makefile.vc: split object lists based on directory
+c8f24165 Merge "add assert(tokens)"
+43239947 add assert(tokens)
+9f547450 Catch an error in DecodeImageData().
+ac8e5e42 minor typo and style fix
+9f566d1d clean-up around Huffman-encode
+c579a710 Introduce CHUNK_SIZE_BYTES in muxi.h.
+14757f8a Make sure huffman trees always have valid symbols
+41050618 makefile.unix: add support for building vwebp
+48b37721 Merge "fixed signed/unsigned comparison warning"
+57f696da Merge "EncodeImageInternal: fix potential leak"
+d972cdf2 EncodeImageInternal: fix potential leak
+5cd12c3d fixed signed/unsigned comparison warning
+cdca30d0 Merge "cosmetics: shorten long line"
+e025fb55 cosmetics: shorten long line
+22671ed6 Merge "enc/vp8l: fix double free on error"
+e1b9b052 Merge "cosmetics: VP8LCreateHuffmanTree: fix indent"
+a8e725f8 enc/vp8l: fix double free on error
+27541fbd cosmetics: VP8LCreateHuffmanTree: fix indent
+1d38b258 cwebp/windows: use MAKE_REFGUID where appropriate
+817ef6e9 Merge "cwebp: fix WIC/Microsoft SDK compatibility issue"
+902d3e3b cwebp: fix WIC/Microsoft SDK compatibility issue
+89d803c4 Merge "Fix a crash due to wrong pointer-integer arithmetic."
+cb1bd741 Merge "Fix a crash in lossless decoder."
+de2fe202 Merge "Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability."
+ce69177a Fix a crash due to wrong pointer-integer arithmetic.
+e40a3684 Fix a crash in lossless decoder.
+3927ff3a remove unneeded error condition for WebPMuxNumNamedElements()
+2c140e11 Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability.
+861a5b7b add support for animation
+eb5c16cc Merge "Set correct encode size in encoder's stats."
+4abe04a2 fix the return value and handle missing input file case.
+2fafb855 Set correct encode size in encoder's stats.
+e7167a2b Provide one entry point for backward references.
+c4ccab64 Print relevant lossless encoding stats in cwebp.
+e3302cfd GetHuffBitLengthsAndCodes: reduce level of indirection
+b5f2a9ed enc/vp8l: fix uninitialized variable warning
+7885f8b2 makefile.unix: add lossless encoder files
+1261a4c8 Merge "cosmetics"
+3926b5be Merge "dsp/cpu.c: Android: fix crash on non-neon arm builds"
+834f937f dsp/cpu.c: Android: fix crash on non-neon arm builds
+126e1606 cosmetics
+e38602d2 Merge branch 'lossless_encoder'
+e8d3d6a0 split StoreHuffmanCode() into smaller functions
+d0d88990 more consolidation: introduce VP8LHistogramSet
+1a210ef1 big code clean-up and refactoring and optimization
+41b5c8ff Some cosmetics in histogram.c
+ada6ff77 Approximate FastLog between value range [256, 8192]
+ec123ca3 Forgot to update out_bit_costs to symbol_bit_costs at one instance.
+cf33ccd1 Evaluate output cluster's bit_costs once in HistogramRefine.
+781c01f4 Simple Huffman code changes.
+a2849bc5 Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths().
+b39e7487 Reducing emerging palette size from 11 to 9 bits.
+bfc73db4 Move GetHistImageSymbols to histogram.c
+889a5786 Improve predict vs no-predict heuristic.
+01f50663 code-moving and clean-up
+31035f3b reduce memory usage by allocating only one histo
+fbb501b8 Restrict histo_bits to ensure histo_image size is under 32MB
+8415ddf3 further simplification for the meta-Huffman coding
+e4917299 A quick pass of cleanup in backward reference code
+83332b3c Make transform bits a function of encode method (-m).
+72920caa introduce -lossless option, protected by USE_LOSSLESS_ENCODER
+c6ac4dfb Run TraceBackwards for higher qualities.
+412222c8 Make histo_bits and transform_bits function of quality.
+149b5098 Update lossless encoder strategy:
+0e6fa065 cache_bits passed to EncodeImageInternal()
+e38b40a9 Factorize code for clearing HtreeGroup.
+6f4a16ea Removing the indirection of meta-huffman tables.
+3d33ecd1 Some renaming/comments related to palette in lossless encoder.
+4d02d586 Lossless encoder: correction in Palette storage
+4a636235 fix a memleak in EncodeImageInternal()
+0993a611 Full and final fix for prediction transform
+afd2102f Fix cross-color transform in lossless encoder
+b96d8740 Need to write a '0' bit at the end of transforms.
+54dad7e5 Color cache size should be counted as 0 when cache bits = 0
+4f0c5caf Fix prediction transform in lossless encoder.
+36dabdad Fix memory leak in method EncodeImageInternal for histogram_image.
+352a4f49 Get rid of PackLiteralBitLengths()
+d673b6b9 Change the predictor function to pass left pixel
+b2f99465 Fix CopyTileWithPrediction()
+84547f54 Add EncodeImageInternal() method.
+6b38378a Guard the lossless encoder (in flux) under a flag
+09f7532c Fix few nits (const qualifiers)
+648be393 Added implementation for various lossless functions
+32714ce3 Add VP8L prefix to backward ref & histogram methods.
+fcba7be2 Fixed header file tag (WEBP_UTILS_HUFFMAN_ENCODE_H_)
+bc703746 Add backward_ref, histogram & huffman encode modules from lossless.
+fdccaadd Fixing nits
+227110c4 libwebp interface changes for lossless encoding.
+50679acf minor style fixes
+b38dfccf remove unneeded reference to NUM_LITERAL_CODES
+8979675b harmonize header description
+c04eb7be tcoder.c: define NOT_HAVE_LOG2 for MSVC builds
+9a214fa1 Merge "VP8[L]GetInfo: check input pointers"
+5c5be8ba VP8[L]GetInfo: check input pointers
+0c188fec Merge changes I431acdfe,I713659b7
+b3515c62 mux: drop 'chunk' from ChunkInfo member names
+aea7923c muxi.h: remove some unused defines
+01422492 update NEWS file for next release
+29e3f7ec Merge "dec: remove deprecated WebPINew()"
+4718e449 Merge "muxedit: a few more size_t changes"
+82654f96 Merge "muxedit: remove a few redundant NULL checks"
+02f27fbd dec: remove deprecated WebPINew()
+ccddb3fc muxedit: remove a few redundant NULL checks
+a6cdf710 muxedit: a few more size_t changes
+a3846892 Merge "mux: remove unused LIST_ID"
+11ae46ae alpha.c: quiet some size_t -> int conversion warnings
+dee46692 mux: remove unused LIST_ID
+03f1f493 mux: add version checked entry points
+6a0abdaa Merge "doc: tile/alpha corrections"
+c8139fbe Merge "few cosmetics"
+68338737 Merge "lossless: remove some size_t -> int conversions"
+5249e94a doc: tile/alpha corrections
+d96e722b huffman: quiet int64 -> int conversion warning
+532020f2 lossless: remove some size_t -> int conversions
+23be6edf few cosmetics
+1349edad Merge "configure: AC_ARG_* use AS_HELP_STRING"
+bfbcc60a configure: AC_ARG_* use AS_HELP_STRING
+1427ca8e Merge "Makefile.am: header file maintenance"
+087332e3 Merge "remove unused parameter 'round' from CalcProba()"
+9630e168 remove unused parameter 'round' from CalcProba()
+92092eaa Merge "bit_reader.h: correct include"
+a87fc3f6 Merge "mux: ensure # images = # tiles"
+53af99b1 Merge "mux: use size_t consistently"
+39a57dae Makefile.am: header file maintenance
+1bd0bd0d bit_reader.h: correct include
+326a3c6b mux: ensure # images = # tiles
+95667b8d mux: use size_t consistently
+231ec1fb Removing the indirection of meta-huffman tables.
+15ebcbaa check return pointer from MuxImageGetListFromId
+b0d6c4a7 Merge "configure: remove test for zlib.h"
+8cccac50 Merge "dsp/lossless: silence some build warnings"
+b08819a6 dsp/lossless: silence some build warnings
+7ae22521 Android.mk: SSE2 & NEON updates
+0a49e3f3 Merge "makefile.unix add missing header files"
+2e75a9a1 Merge "decode.h: use size_t consistently"
+fa13035e configure: remove test for zlib.h
+d3adc81d makefile.unix add missing header files
+262fe01b Merge "makefile.unix & Android.mk: cosmetics"
+4cce137e Merge "enc_sse2 add missing stdlib.h include"
+80256b85 enc_sse2 add missing stdlib.h include
+9b3d1f3a decode.h: use size_t consistently
+64083d3c Merge "Makefile.am: cosmetics"
+dceb8b4d Merge changes If1331d3c,I86fe3847
+0e33d7bf Merge "webp/decode.h: fix prototypes"
+fac0f12e rename BitReader to VP8LBitReader
+fbd82b5a types.h: centralize use of stddef.h
+2154835f Makefile.am: cosmetics
+1c92bd37 vp8io: use size_t for buffer size
+90ead710 fix some more uint32_t -> size_t typing
+cbe705c7 webp/decode.h: fix prototypes
+3f8ec1c2 makefile.unix & Android.mk: cosmetics
+217ec7f4 Remove tabs in configure.ac
+b3d35fc1 Merge "Android.mk & Makefile.vc: add new files"
+0df04b9e Android.mk & Makefile.vc: add new files
+e4f20c5b Merge "automake: replace 'silent-rules' w/AM_SILENT_RULES"
+8d254a09 cosmetics
+6860c2ea fix some uint32_t -> size_t typing
+4af1858a Fix a crash due to max symbol in a tree >= alphabet size
+6f01b830 split the VP8 and VP8L decoding properly
+f2623dbe enable lossless decoder
+b96efd7d add dec/vp8i.h changes from experimental
+19f6398e add dec/vp8l{i.h,.c} from experimental
+c4ae53c8 add utils/bit_reader.[hc] changes from experimental
+514d0089 add dsp/lossless.[hc] from experimental
+9c67291d add utils/huffman.[hc] from experimental
+337914a0 add utils/color_cache.[hc] from experimental
+b3bf8fe7 the read-overflow code-path wasn't reporting as an error
+1db888ba take colorspace into account when cropping
+61c2d51f move the rescaling code into its own file and make enc/ and dec/ use it.
+efc2016a Make rescaler methods generic
+3eacee81 Move rescaler methods out of io.c.
+a69b893d automake: replace 'silent-rules' w/AM_SILENT_RULES
+6f7bf645 issue 111: fix little-endian problem in bit-reader
+ed278e22 Removed unnecessary lookup
+cd8c3ba7 fix some warnings: down-cast and possibly-uninitialized variable
+0a7102ba ~1% improvement of alpha compression
+3bc1b141 Merge "Reformat container doc"
+dc17abdc mux: cosmetics
+cb5810df Merge "WebPMuxGetImage: allow image param to be NULL"
+506a4af2 mux: cosmetics
+135e8b19 WebPMuxGetImage: allow image param to be NULL
+de556b68 Merge "README.mux: reword some descriptions"
+0ee2aeb9 Makefile.vc: use batch mode rules
+d9acddc0 msvc: move {i,p}db creation to object directory
+237c9aa7 Merge "expose WebPFree function for DLL builds"
+b3e4054f silence msvc debug build warning
+45feb55d expose WebPFree function for DLL builds
+11316d84 README.mux: reword some descriptions
+4be52f4a factorize WebPMuxValidate
+14f6b9f6 mux: light cleanup
+5e96a5db add more param checks to WebPPictureDistortion()
+8abaf820 Merge "silence some type size related warnings"
+1601a39b silence some type size related warnings
+f3abe520 Merge "idec: simplify buffer size calculation"
+a9c5cd4c idec: simplify buffer size calculation
+7b06bd7f Merge "configure/automake: add silent-rules option"
+e9a7d145 Reformat container doc
+d4e5c7f3 configure/automake: add silent-rules option
+5081db78 configure/automake: no -version-info for convenience libs
+85b6ff68 Merge "idec: fix WebPIUpdate failure"
+7bb6a9cc idec: fix internal state corruption
+89cd1bb8 idec: fix WebPIUpdate failure
+01b63806 4-5% faster decoding, optimized byte loads in arithmetic decoder.
+631117ea Merge "cosmetics & warnings"
+a0b2736d cosmetics & warnings
+f73947f4 use 32bit for storing dequant coeffs, instead of 16b.
+b9600308 Merge "store prediction mode array as uint8_t[16], not int[16]."
+7b67881a store prediction mode array as uint8_t[16], not int[16].
+cab8d4dc Merge "NEON TransformOne"
+ba503fda NEON TransformOne
+9f740e3b Merge "gcc warning fix: remove the 'const' qualifier."
+f76d3587 gcc warning fix: remove the 'const' qualifier.
+e78478d6 Merge "webpmux: make more use of WebPData"
+f85bba3d Merge "manpages: add BUGS section"
+48a43bbf Merge "makefile.unix: variable cosmetics"
+c274dc96 makefile.unix: variable cosmetics
+1f7b8595 re-organize the error-handling in the main loop a bit
+1336fa71 Only recompute level_cost_[] when needed
+771ee449 manpages: add BUGS section
+0f7820e6 webpmux: make more use of WebPData
+974aaff3 examples: logging updates
+6c14aadd Merge "better token buffer code"
+f4054250 better token buffer code
+18d959fa Merge "mux: add WebPData type"
+eec4b877 mux: add WebPData type
+0de3096b use 16bit counters for recording proba counts
+7f23678d fix for LevelCost + little speed-up
+7107d544 further speed-up/cleanup of RecordCoeffs() and GetResidualCost()
+fd221040 Introduce Token buffer (unused for now)
+5fa148f4 Merge "speed-up GetResidualCost()"
+28a9d9b4 speed-up GetResidualCost()
+11e7dadd Merge "misc cosmetics"
+378086bd misc cosmetics
+d61479f9 add -print_psnr and -print_ssim options to cwebp.
+2e3e8b2e add a WebPCleanupTransparentArea() method
+552c1217 Merge "mux: plug some memory leaks on error"
+a2a81f7d Merge "fix Mach-O shared library build"
+b3482c43 Merge "fix gcc-4.0 apple 32-bit build"
+e4e3ec19 fix gcc-4.0 apple 32-bit build
+b0d2fecf mux: plug some memory leaks on error
+f0d2c7a7 pass of cosmetics
+b309a6f9 fix Mach-O shared library build
+241ddd38 doc: delete mux container pdf
+8b1ba272 doc: update VP8 decode guide link
+7e4371c5 WebPMuxCreate: fix unchecked malloc
+eb425586 Merge "have makefile.unix clean up src/webp/*~ too"
+a85c3631 Merge "correct EncodeAlpha documentation"
+a33842fd Merge "Update webp container spec with alpha filter options."
+8d6490da Incremental support for some of the mux APIs.
+b8375abd have makefile.unix clean up src/webp/*~ too
+b5855fc7 correct EncodeAlpha documentation
+dba37fea Update webp container spec with alpha filter options.
+2e74ec8b fix compile under MINGW
+716d1d7f fix suboptimal MAX_LEN cut-off limit
+57cab7b8 Harmonize the alpha-filter predictions at boundary
+3a989534 Merge "Fix bug for Alpha in RGBA_4444 color-mode."
+8ca2076d Introduce a 'fast' alpha mode
+221a06bb Fix bug for Alpha in RGBA_4444 color-mode.
+ad1e163a cosmetics: normalize copyright headers
+c77424d7 cosmetics: light include cleanup
+9d0e17c9 fix msvc build breakage after 252028a
+7c4c177c Some readability fixes for mux library
+d8a47e66 Merge "Add predictive filtering option for Alpha."
+252028aa Add predictive filtering option for Alpha.
+9b69be1c Merge "Simplify mux library code"
+a056170e Simplify mux library code
+992187a3 improve log2 test
+e852f832 update Android.mk file list
+a90cb2be reduce number of copies and mallocs in alpha plane enc/dec
+b1662b05 fix some more type conversion warnings w/MSVC
+223d8c60 fix some uint64_t -> int conversion warnings with MSC
+c1a0437b Merge "simplify checks for enabling SSE2 code"
+f06817aa simplify checks for enabling SSE2 code
+948d4fe9 silence a msvc build warning
+91179549 vwebp: msvc build tweaks
+7937b409 simple WebP viewer, based on OpenGL
+6aac1df1 add a bunch of missing 'extern "C"'
+421eb99d Merge "Remove assigned-but-not-used variable "br""
+91e27f45 better fitting names for upsampling functions
+a5d7ed5c Remove assigned-but-not-used variable "br"
+f62d2c94 remove unused 'has_alpha' from VP8GetInfo() signature
+08e86582 trap alpha-decoding error
+b361eca1 add cut-off to arith coder probability update.
+8666a93a Some bug-fixes for images with alpha.
+273a12a0 fix off-by-1 diff in case cropping and simple filtering
+2f741d1e webpmux: ReadImage: fix ptr free in error case
+721f3f48 fix alpha decode
+60942c8c fix the has_alpha_ order
+30971c9e Implement progress report (and user abort)
+eda520a9 cosmetics after 9523f2a
+38bd5bb5 Merge "Better alpha support in webpmux binary"
+ccbaebfe Merge "Updated the includes to relative paths."
+d71fbdcc fix small typo in error message array
+cdf97aa2 Better alpha support in webpmux binary
+885f25bc Updated the includes to relative paths.
+a0ec9aac Update WebP encoder (cwebp) to support Alpha.
+667b769a Fixed the include for types.h within mux.h
+9523f2a5 Add Alpha Encode support from WebPEncode.
+16612ddd Merge "Add Alpha Decode support from WebPDecode."
+d117a940 Add Alpha Decode support from WebPDecode.
+67228734 cosmetics after e1947a9
+e1947a92 Add Alpha encode/decode code.
+afc4c5d6 simplify code by introducing a CopyPlane() helper func
+113b3128 Merge "MUX API Updates"
+c398f595 MUX API Updates
+5acf04ef remove orphan source file
+059f03ef Merge "dec: validate colorspace before using as array index"
+70a03989 Merge "factorize some code"
+9b243b3d factorize some code
+372e2b46 Correct a bug in ReadPNG() with GRAY_ALPHA images
+469d6eb9 Merge "Makefile.am: remove redundant noinst_HEADERS"
+9fe3372f dec: validate colorspace before using as array index
+8962030f remove orphan source file
+ced3e3f4 Makefile.am: remove redundant noinst_HEADERS
+964387ed use WEBP_INLINE for inline function declarations
+90880a11 Merge "manpages: break long lines"
+b5910895 Merge "manpages: minor formatting updates"
+4c451e4a Merge "Rectify the Chunk parsing logic."
+04e84cf1 examples: slight cleanup
+099717ce manpages: break long lines
+1daf39bb manpages: minor formatting updates
+abd030b5 fix missing "(void)" in function signature
+f6a7d758 remove useless test
+f07b2138 Rectify the Chunk parsing logic.
+b8634f7d webpmux: fix lib link order
+42c2e682 Fix missing coma (on uncompiled code)
+d8329d41 Android.mk: add missing source files
+13a54df5 Merge "More aggressive copy-edit; add TODO; validate HTML5"
+868b96ae More aggressive copy-edit; add TODO; validate HTML5
+767afea2 configure: check for a symbol contained in libpng
+408b8918 Merge "Linewrap at 72 cols. Casual copy-edit."
+3ae318c7 Merge "Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)"
+918eb2d8 Merge "Basic container doc source clean-up; fix lists and pseudocode blocks."
+03bec9e0 Linewrap at 72 cols. Casual copy-edit.
+2678d819 Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)
+428674da Basic container doc source clean-up; fix lists and pseudocode blocks.
+6a77d928 Merge "Makefile.vc: cosmetics"
+28c38e8c Merge "Makefile.vc: condense directory creation rules"
+55be2cf8 Initial import of container spec document, from pdftotext transform.
+a82a788b Makefile.vc: cosmetics
+c8f41ce5 Makefile.vc: condense directory creation rules
+2b877cd0 Some fixes to Makefile.vc to support the src\mux directory.
+3eb969b3 Merge "Add Makefile.vc for Mux library & binary."
+e78e971e Add Makefile.vc for Mux library & binary.
+6aedde58 Add manual for WebPMux tool.
+8a360d0a Merge "Added WebPMux Binary."
+a4f32cae Added WebPMux Binary.
+f3bf4c76 Added Mux Container Spec & README for MUX-API.
+9f761cfa Changed function signature for WebPMuxCreate
+5f31b5ec Merge "Add Mux library for manipulating WebP container."
+2315785f Add Mux library for manipulating WebP container.
+7e198abb update ChangeLog (tag: v0.1.3)
+dfc9c1ea Harmonize the dates
+28ad70c5 Fix PNG decoding bug
+846e93c5 Update AUTHORS & add .mailmap
+563e52d6 cosmetics after '76036f5 Refactor decoder library'
+76036f54 Refactor decoder library
+377ef43c configure.ac: update AC_INIT params
+7a8d8762 use a user-visible MACRO for max width/height.
+d4e9f559 NEON decode support in WebP
+0ee683b5 update libtool version-info
+fdbe02c5 windows: match _cond_destroy logic w/return variable name
+206b686b README: correct advanced decode api pseudo-code
+6a32a0f5 make VP8BitReader a typedef, for better re-use
+b112e836 create a libwebputils under src/utils
+ee697d9f harmonize the include guards and #endif comments
+a1ec07a6 Fixing compiler error in non x86 arch.
+dcfa509a Fixed recursive inclusion of bit_writer.h and vp8enci.h.
+e06ac088 create a separate libwebpdsp under src/dsp
+ebeb412a use unsigned int for bitfields
+341cc56a make kNewRange a static array
+227a91e5 README: minor wording update
+05bd8e6a add man pages to dist
+812dfa1a bump up versions in preparations for 0.1.3
+a5b78c81 wrap alpha-related options under WEBP_EXPERIMENTAL_FEATURES flag
+34dc7907 regen ChangeLog for 0.1.3-rc2
+7c436630 Silence some (more) Visual Studio warnings.
+60306e8c add top-level gitattributes
+2aa6b80e Slience some Visual Studio warnings.
+4cbbb290 Merge "bump up version for next freeze"
+a3291674 bump up version for next freeze
+c7e86aba cosmetics: fix comment line lengths
+c9e037ab makefile.unix: add simple dist target
+87d58ce9 makefile.unix: rule maintenance
+d477de77 mend
+fac15ec7 Update NEWS & README for next release V0.1.3
+6215595c Merge "add a -partition_limit option to limit the number of bits used by intra4x4"
+3814b76c Merge "reorganize chunk-parsing code"
+900286e0 add a -partition_limit option to limit the number of bits used by intra4x4
+cd12b4b0 add the missing cost for I4/I16 mode selection
+dfcc2136 reorganize chunk-parsing code
+3cf20306 initialize pointers to function within VP8DspInit()
+d21b4795 Merge "windows: add decode threading support"
+473ae953 fix hang on thread creation failure
+fccca420 windows: add decode threading support
+a31f843a Use the exact PNG_INCLUDES/PNG_LIBS when testing for -lpng
+ad9b45f1 Merge "Makefile.vc: rule maintenance"
+565a2cab Makefile.vc: rule maintenance
+2d0da681 makefile.unix: disable Wvla by default
+fc7815d6 multi-thread decoding: ~25-30% faster
+acd8ba42 io->teardown() was not always called upon error
+c85527b1 Merge "Makefile.vc: add DLL configs"
+e1e9be35 cosmetics: spelling/grammar in README and lib headers
+b4d0ef8f Makefile.vc: add DLL configs
+998754a7 remove unused nb_i4_ and nb_i16_ fields.
+9f01ce3a rename WebPDecBuffer::memory -> private_memory
+fb5d659b fix an overflow bug in LUT calculation
+d646d5c7 swig: add WebPDecodeARGB
+78aeed40 add missing WebPDecodeARGBInto() and switch ARGB4444 to RGBA4444 as was intended
+cd7c5292 explicitly mark library functions as extern
+19db59f8 add support for RGB565, ARGB4444 and ARGB colorspace (decoder)
+c915fb2a encoder speed-up: hardcode special level values
+c558bdad Rename and improve the API to retrieve decoded area
+bf599d74 Merge "makefile.unix: disable -Wvla by default"
+c9ea03d7 SSE2 version of strong filtering
+993af3e2 makefile.unix: disable -Wvla by default
+3827e1bc Merge "examples: (windows/WIC) add alpha support"
+e291fae0 SSE2 functions for the fancy upsampler.
+a06bbe2e add WebPISetIOHooks() to set some custom hooks on the incremental decoder object.
+7643a6f2 Merge "makefile.unix: use uname to detect OSX environment"
+5142a0be export alpha channel (if present) when dumping to PGM format
+14d5731c makefile.unix: use uname to detect OSX environment
+08057062 examples: quiet warnings
+3cfe0888 examples: (windows/WIC) add alpha support
+13ed94b8 add compile warning for variable-length-array
+5a18eb1a Merge "add Advanced Decoding Interface"
+5c4f27f9 add missing \n
+f4c4e416 80 cols fix
+d2603105 add Advanced Decoding Interface
+bd2f65f6 sse2 version of the complex filter
+96ed9ce0 perform two idct transforms at a time when possible
+01af7b69 use aligned stored
+0e1d1fdf Merge "Makefile.vc: add experimental target"
+2a1292a6 Makefile.vc: add experimental target
+23bf351e Enable decode SSE2 for Visual Studio
+131a4b7b dec/dsp_sse2: fix visual studio compile
+00d9d680 swig: file reorganization
+7fc7e0d9 Merge "swig/java: basic encode support"
+3be57b16 fix MSVC compile for WEBP_EXPERIMENTAL_FEATURES
+40a7e347 dec/dsp: disable sse2 for Visual Studio builds
+e4d540c8 add SSE2 code for transform
+54f2170a swig/java: basic encode support
+c5d4584b call function pointers instead of C-version
+ea43f045 Merge "configure: mingw32 targets: test for WIC support"
+a11009d7 SSE2 version of simple in-loop filtering
+42548da9 shave one unneeded filter-cache line
+31f9dc6f configure: mingw32 targets: test for WIC support
+19559699 Merge "split expression in two."
+415dbe46 split expression in two.
+e29072a8 configure: test for zlib only w/--enable-experimental
+b2b0090b Simplify Visual Studio ifdefs
+ca7a2fd6 Add error reporting from encoding failures.
+6c9405db Merge "Makefile.vc: require CFG with clean target"
+0424ecd9 Makefile.vc: require CFG with clean target
+003417c7 Enable SSE2 for Visual Studio builds
+af10db4a little speed up for VP8BitUpdate()
+e71418f8 more MSVC files to ignore
+46d90363 cosmetics
+edf59ab3 typo fix
+72229f5f Add support for x64 and SSE2 builds under Windows.
+92e5c6e1 VP8GetInfo() + WebPResetDecParams()
+416b7a6b raise the fixed-point precision for the rescaler
+aa87e4e0 fix alignment
+eb66670c disable WEBP_EXPERIMENTAL_FEATURES
+c5ae7f65 typo fix: USE_ => WEBP_
+d041efae swig: add libwebp.jar/libwebp_java_wrap.c
+f6fb3877 add swig interface
+e9273902 align buffer for double too
+842c009b fix -strong option
+d0a70387 Merge "cosmetics"
+fc0a02e5 fix the dichotomy loop
+38369c03 cosmetics
+8dfc4c6f factorize and unify GetAlpha() between the C and SSE2 version
+6d0e66c2 prepare experimentation with yuv444 / 422
+79cc49f5 add a --enable-experimental option to './configure'
+d7575238 sse2 version of CollectHistogram()
+c1c728d6 add an extra #ifdef WEBP_EXPERIMENTAL_FEATURES to avoid 'unused variable' warning
+60c61d2d always call VP*EncDeleteAlpha() unconditionnally, for simplicity
+0f8c6384 simply don't call WriteExtensions() if WEBP_EXPERIMENTAL_FEATURES is not defined
+47c661d5 rename swap -> swap_rb
+10d55bbb move chunk[] declaration out of the for() loop
+517cec21 fix indentation
+f7d9e261 fix merge problems
+8fd42b3a add a stride 'a_stride' for the alpha plane
+b8dcbf2f fix alpha-plane copy and crop methods
+cdef89de fix some 'unused variable' warning
+fb29c262 SSE2 version of the fwd transform and the squared sum metric
+2ab4b72f EXPERIMENTAL: add support for alpha channel
+cfbf88a6 add SSE2 functions. ~2x faster encoding on average.
+e7ff3f9a merge two ITransforms together when applicable and change the TTransform to return the sum directly.
+ca554137 fix WebPIDecGetRGB() to accept any RGB(A) mode, not just MODE_RGB
+8aa50efd fix some 'man' typos
+d3f3bdda update ChangeLog (tag: v0.1.2)
+d7e9a69c update contributor list
+261abb8e add a 'superclean' section
+276ae825 Remove files not mean to be in git, and update .gitignore
+24868455 build: prepare libwebp.pc
+14ceb6e8 add "-version" description to man pages
+b247a3b2 Create the m4 directory, and also place .gitignore in there for libtool.
+cdd734c9 Resolve automake warnings
+c5fa726e build: add pkgconfig files
+b20aaca2 build: just use autoreconf, avoid calling tools manually
+4b0b0d66 cwebp: use modern functions
+efbc6c41 update Android.mk
+7777570b better version of ChangeLog
+fa70d2b7 update version number in the DOC
+f8db5d5d more C89-fixes
+0de013b3 fix typos
+650ffa3b add version getters for decoder and encoder
+be4867d2 doc for incremental decoding
+56732a1b add idec.obj in MSVC makefile
+208afb5e add c++ guards
+8bf76fe0 add incremental decoding
+1f288328 'inline' isn't defined in strict ansi c89
+8b77c632 move the quantization function to dsp.c
+b2c3575c add a 'last_y' field to WebPDecParams
+2654c3da correctly pass along the exact same status returned from ParsePartitions
+4704146a add missing precision in the man
+6d978a6c add error messages
+6463e6ab add some install instructions, and fix intel-mac flags
+05fb7bfc Merge ".gitignore: initial version"
+c33f0195 .gitignore: initial version
+e532b9ab Makefile: allow out of tree builds
+4c0da7aa enable sparse dc/ac transforms
+07dbb8d5 clarify the return logic
+5c69e1bb fix bigger-by-1 array
+7c5267e3 fix a (harmless) typo: non_zero_ -> non_zero_ac_
+bc752135 fix missing free()
+af3e2aaa remove trailing spaces
+13e50da6 make the bitreader preload at least 8bits, instead of post-load them (this makes initialization easier and will be helpful for incremental decoding). Modify ParsePartitions() to accommodate for truncated input.
+f4888f77 emit 9 - nb_bits trailing zeros instead of 8
+3db65255 separate block-parsing into a visible VP8DecodeMB()
+a871de02 add missing extern "C"
+b3ce8c52 remove a gcc warning about type pun by using a proper union'd type
+e1863715 update after addition of webpi.h
+3e856e2d Extract some useful functions around decoding buffer WebPDecParams.
+d5bc05a4 make the filtering process match libvpx and ffvp8
+dd60138d add man pages for cwebp(1) and dwebp(1)
+c4fa3644 fix header
+5b70b378 * add an option to bypass_filtering in VP8Io.
+b97a4003 simplify QuantizeBlock code a bit
+84b58ebb add more checks around picture allocation
+b65a3e10 remove absolute_delta_ field and syntax code
+0744e842 Dont' open output file until we're sure the input file is valid
+d5bd54c7 fix typo and buggy line
+f7a9549d Add a simple top-level makefile.unix for quick & easy build.
+5f36b944 update the doc for the -f option
+f61d14aa a WebP encoder converts PNG & JPEG to WebP
+81c96621 oops: forgotten call to Initialize() + move the error message to a more useful place
+87ffa005 typo: fix a missing 'R', was confusing.
+b04b857a * add decoding measurement using stopwatch.h (use -v option) * support PNG output through WIC on Win32
+746a4820 * make (*put)() hook return a bool for abort request. * add an enum for VP8Status() to make things clearer
+73c973e6 * strengthen riff/chunk size checks * don't consider odd-sized chunks being an error
+1dc4611a add support for PNG output (default) regularize include guards
+860641df fix a typo: sizeof(kYModeProbaInter0) => sizeof(kUVModeProbaInter0)
+3254fc52 fix some petty constness fix the ./configure file too
+504d3393 fix eof_ mis-initialization
+2bc0778f leftover Makefile.* from previous commit
+d2cf04e4 move Makefile.am one level below, to src/dec fix typos here and there dwebp is now an installed program
+ade92de8 typo: vp8.h -> decode_vp8.h
+d7241241 forgot to declare types.h to be installed
+6421a7a4 move the decoder sourcetree to a sub-location src/dec to make room for future libs sources
+a9b3eab6 correct layout name is IMC4.
+2330522c handle corner case of zero-dimensions
+280c3658 make VP8Init() handle short buffers (< 2 bytes) correctly
+b1c9e8b4 handle error cases more robustly
+0e94935c Merge "table-less version of clip_8b()"
+1e0a2d25 table-less version of clip_8b()
+e12109ee dwebp: change -yuv option to -raw change the layout to IMC2
+d72180a4 speed-up fancy upscaler
+9145f3bc reset eof_ at construction time
+a7ee0559 simplify the logic of GetCoeffs()
+f67b5939 lot of cosmetics
+ea27d7c6 fix endian problem on PowerPC
+beb0a1ba fix signature of VP8StoreBlock
+b128c5e2 Merge "fancy chroma upscaling"
+6a37a2aa fancy chroma upscaling
+ff565edc fix two numeric typos
+5a936a0a use uintptr_t for casting pointers to ints
+e14a0301 for cross_compiling=yes to prevent executing any binary
+83b545ee add vc9+ makefile
+296f6914 fix output loop for small height
+cbfbb5c3 convert to plain-C
+f09f96ee Fix declaration after statement warning
+5981ee55 Fix UV plane ac/dc quantizer transposition
+c8d15efa convert to ANSI-C
+c3f41cb4 Initial commit
diff --git a/METADATA b/METADATA
index d97975c..def00a9 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,15 @@
+name: "webp"
+description: "Android fork of the libwebp library."
third_party {
+ url {
+ type: GIT
+ value: "https://chromium.googlesource.com/webm/libwebp"
+ }
+ version: "v1.3.0"
license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 01
+ day: 13
+ }
}
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e1c1dd4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,9 @@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = sharpyuv src imageio man
+EXTRA_DIST = COPYING autogen.sh
+
+if BUILD_EXTRAS
+ SUBDIRS += extras
+endif
+
+SUBDIRS += examples
diff --git a/Makefile.vc b/Makefile.vc
new file mode 100644
index 0000000..00d899e
--- /dev/null
+++ b/Makefile.vc
@@ -0,0 +1,527 @@
+#
+# Stem for static libs and DLLs
+#
+LIBWEBPDECODER_BASENAME = libwebpdecoder
+LIBWEBP_BASENAME = libwebp
+LIBWEBPMUX_BASENAME = libwebpmux
+LIBWEBPDEMUX_BASENAME = libwebpdemux
+LIBSHARPYUV_BASENAME = libsharpyuv
+
+!IFNDEF ARCH
+!IF ! [ cl 2>&1 | find "x86" > NUL ]
+ARCH = x86
+!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ]
+ARCH = x64
+!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ]
+ARCH = ARM
+!ELSE
+!ERROR Unable to auto-detect toolchain architecture! \
+If cl.exe is in your PATH rerun nmake with ARCH=<arch>.
+!ENDIF
+!ENDIF
+
+!IF "$(ARCH)" == "x86"
+PLATFORM_LDFLAGS = /SAFESEH
+!ENDIF
+
+#############################################################
+## Nothing more to do below this line!
+
+NOLOGO = /nologo
+CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
+CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1
+CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c
+CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
+LDFLAGS = /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
+LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
+LNKDLL = link.exe /DLL $(NOLOGO)
+LNKEXE = link.exe $(NOLOGO)
+LNKLIB = lib.exe $(NOLOGO)
+RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
+RCDEBUG = $(RCNODBG) /D_DEBUG
+
+!IF "$(ARCH)" == "ARM"
+CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD
+!ELSE
+CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
+!ENDIF
+
+CFGSET = FALSE
+!IF "$(OBJDIR)" == ""
+OUTDIR = ..\obj\
+!ELSE
+OUTDIR = $(OBJDIR)
+!ENDIF
+
+##############################################################
+# Runtime library configuration
+!IF "$(RTLIBCFG)" == "static"
+RTLIB = /MT
+RTLIBD = /MTd
+!ELSE IF "$(RTLIBCFG)" == "legacy"
+RTLIBCFG = static
+RTLIB = /MT
+RTLIBD = /MTd
+CFLAGS = $(CFLAGS) /GS- /arch:IA32
+!ELSE
+RTLIB = /MD
+RTLIBD = /MDd
+!ENDIF
+DIRBASE = $(OUTDIR)\$(CFG)\$(ARCH)
+DIROBJ = $(DIRBASE)\obj
+DIRLIB = $(DIRBASE)\lib
+DIRINC = $(DIRBASE)\include
+DIRBIN = $(DIRBASE)\bin
+LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME).pdb
+OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
+ $(DIROBJ)\dec \
+ $(DIROBJ)\demux \
+ $(DIROBJ)\dsp \
+ $(DIROBJ)\enc \
+ $(DIROBJ)\examples \
+ $(DIROBJ)\extras \
+ $(DIROBJ)\imageio \
+ $(DIROBJ)\mux \
+ $(DIROBJ)\sharpyuv \
+ $(DIROBJ)\utils \
+
+# Target configuration
+!IF "$(CFG)" == "release-static"
+CC = $(CCNODBG)
+STATICLIBBUILD = TRUE
+!ELSE IF "$(CFG)" == "debug-static"
+CC = $(CCDEBUG)
+RTLIB = $(RTLIBD)
+STATICLIBBUILD = TRUE
+LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
+LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
+LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
+LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
+LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
+!ELSE IF "$(CFG)" == "release-dynamic"
+CC = $(CCNODBG)
+RC = $(RCNODBG)
+DLLBUILD = TRUE
+!ELSE IF "$(CFG)" == "debug-dynamic"
+CC = $(CCDEBUG)
+RC = $(RCDEBUG)
+RTLIB = $(RTLIBD)
+DLLBUILD = TRUE
+LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
+LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
+LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
+LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
+LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
+!ENDIF
+
+!IF "$(STATICLIBBUILD)" == "TRUE"
+CC = $(CC) $(RTLIB)
+CFGSET = TRUE
+LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
+LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
+LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
+LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
+LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME).lib
+!ELSE IF "$(DLLBUILD)" == "TRUE"
+CC = $(CC) /I$(DIROBJ) $(RTLIB) /DWEBP_DLL
+LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
+LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
+LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
+LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib
+LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME)_dll.lib
+LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
+CFGSET = TRUE
+!ENDIF
+
+!IF "$(UNICODE)" == "1"
+CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
+!ENDIF
+
+#######################
+# Usage
+#
+!IF "$(CFGSET)" == "FALSE"
+!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
+!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [UNICODE=1] [<target>]
+!MESSAGE
+!MESSAGE where <config> is one of:
+!MESSAGE - release-static - release static library
+!MESSAGE - debug-static - debug static library
+!MESSAGE - release-dynamic - release dynamic link library (DLL)
+!MESSAGE - debug-dynamic - debug dynamic link library (DLL)
+!MESSAGE
+!MESSAGE <target> may be:
+!MESSAGE - clean - perform a clean for CFG
+!MESSAGE - experimental - build CFG with experimental
+!MESSAGE . features enabled.
+!MESSAGE - (empty) - build libwebp-based targets for CFG
+!MESSAGE - all - build (de)mux-based targets for CFG
+!MESSAGE - gif2webp - requires libgif & >= VS2013
+!MESSAGE - anim_diff - requires libgif & >= VS2013
+!MESSAGE - anim_dump
+!MESSAGE
+!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'.
+!MESSAGE 'legacy' will produce a Windows 2000 compatible library.
+!MESSAGE OBJDIR is the path where you like to build (obj, bins, etc.),
+!MESSAGE defaults to ..\obj
+
+!IF "$(CFG)" != ""
+!MESSAGE
+!ERROR please choose a valid configuration instead of "$(CFG)"
+!ENDIF
+!ENDIF
+
+#######################
+# Rules
+#
+!IF "$(CFGSET)" == "TRUE"
+# A config was provided, so the library can be built.
+#
+
+SHARPYUV_OBJS = \
+ $(DIROBJ)\sharpyuv\sharpyuv.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_cpu.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_csp.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_neon.obj \
+ $(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \
+
+DEC_OBJS = \
+ $(DIROBJ)\dec\alpha_dec.obj \
+ $(DIROBJ)\dec\buffer_dec.obj \
+ $(DIROBJ)\dec\frame_dec.obj \
+ $(DIROBJ)\dec\idec_dec.obj \
+ $(DIROBJ)\dec\io_dec.obj \
+ $(DIROBJ)\dec\quant_dec.obj \
+ $(DIROBJ)\dec\tree_dec.obj \
+ $(DIROBJ)\dec\vp8_dec.obj \
+ $(DIROBJ)\dec\vp8l_dec.obj \
+ $(DIROBJ)\dec\webp_dec.obj \
+
+DEMUX_OBJS = \
+ $(DIROBJ)\demux\anim_decode.obj \
+ $(DIROBJ)\demux\demux.obj \
+
+DSP_DEC_OBJS = \
+ $(DIROBJ)\dsp\alpha_processing.obj \
+ $(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\alpha_processing_neon.obj \
+ $(DIROBJ)\dsp\alpha_processing_sse2.obj \
+ $(DIROBJ)\dsp\alpha_processing_sse41.obj \
+ $(DIROBJ)\dsp\cpu.obj \
+ $(DIROBJ)\dsp\dec.obj \
+ $(DIROBJ)\dsp\dec_clip_tables.obj \
+ $(DIROBJ)\dsp\dec_mips32.obj \
+ $(DIROBJ)\dsp\dec_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\dec_msa.obj \
+ $(DIROBJ)\dsp\dec_neon.obj \
+ $(DIROBJ)\dsp\dec_sse2.obj \
+ $(DIROBJ)\dsp\dec_sse41.obj \
+ $(DIROBJ)\dsp\filters.obj \
+ $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\filters_msa.obj \
+ $(DIROBJ)\dsp\filters_neon.obj \
+ $(DIROBJ)\dsp\filters_sse2.obj \
+ $(DIROBJ)\dsp\lossless.obj \
+ $(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\lossless_msa.obj \
+ $(DIROBJ)\dsp\lossless_neon.obj \
+ $(DIROBJ)\dsp\lossless_sse2.obj \
+ $(DIROBJ)\dsp\lossless_sse41.obj \
+ $(DIROBJ)\dsp\rescaler.obj \
+ $(DIROBJ)\dsp\rescaler_mips32.obj \
+ $(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\rescaler_msa.obj \
+ $(DIROBJ)\dsp\rescaler_neon.obj \
+ $(DIROBJ)\dsp\rescaler_sse2.obj \
+ $(DIROBJ)\dsp\upsampling.obj \
+ $(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\upsampling_msa.obj \
+ $(DIROBJ)\dsp\upsampling_neon.obj \
+ $(DIROBJ)\dsp\upsampling_sse2.obj \
+ $(DIROBJ)\dsp\upsampling_sse41.obj \
+ $(DIROBJ)\dsp\yuv.obj \
+ $(DIROBJ)\dsp\yuv_mips32.obj \
+ $(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\yuv_neon.obj \
+ $(DIROBJ)\dsp\yuv_sse2.obj \
+ $(DIROBJ)\dsp\yuv_sse41.obj \
+
+DSP_ENC_OBJS = \
+ $(DIROBJ)\dsp\cost.obj \
+ $(DIROBJ)\dsp\cost_mips32.obj \
+ $(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\cost_neon.obj \
+ $(DIROBJ)\dsp\cost_sse2.obj \
+ $(DIROBJ)\dsp\enc.obj \
+ $(DIROBJ)\dsp\enc_mips32.obj \
+ $(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\enc_msa.obj \
+ $(DIROBJ)\dsp\enc_neon.obj \
+ $(DIROBJ)\dsp\enc_sse2.obj \
+ $(DIROBJ)\dsp\enc_sse41.obj \
+ $(DIROBJ)\dsp\lossless_enc.obj \
+ $(DIROBJ)\dsp\lossless_enc_mips32.obj \
+ $(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \
+ $(DIROBJ)\dsp\lossless_enc_msa.obj \
+ $(DIROBJ)\dsp\lossless_enc_neon.obj \
+ $(DIROBJ)\dsp\lossless_enc_sse2.obj \
+ $(DIROBJ)\dsp\lossless_enc_sse41.obj \
+ $(DIROBJ)\dsp\ssim.obj \
+ $(DIROBJ)\dsp\ssim_sse2.obj \
+
+EX_ANIM_UTIL_OBJS = \
+ $(DIROBJ)\examples\anim_util.obj \
+
+IMAGEIO_DEC_OBJS = \
+ $(DIROBJ)\imageio\image_dec.obj \
+ $(DIROBJ)\imageio\jpegdec.obj \
+ $(DIROBJ)\imageio\metadata.obj \
+ $(DIROBJ)\imageio\pngdec.obj \
+ $(DIROBJ)\imageio\pnmdec.obj \
+ $(DIROBJ)\imageio\tiffdec.obj \
+ $(DIROBJ)\imageio\webpdec.obj \
+ $(DIROBJ)\imageio\wicdec.obj \
+
+IMAGEIO_ENC_OBJS = \
+ $(DIROBJ)\imageio\image_enc.obj \
+
+EX_GIF_DEC_OBJS = \
+ $(DIROBJ)\examples\gifdec.obj \
+
+EX_UTIL_OBJS = \
+ $(DIROBJ)\examples\example_util.obj \
+
+ENC_OBJS = \
+ $(DIROBJ)\enc\alpha_enc.obj \
+ $(DIROBJ)\enc\analysis_enc.obj \
+ $(DIROBJ)\enc\backward_references_cost_enc.obj \
+ $(DIROBJ)\enc\backward_references_enc.obj \
+ $(DIROBJ)\enc\config_enc.obj \
+ $(DIROBJ)\enc\cost_enc.obj \
+ $(DIROBJ)\enc\filter_enc.obj \
+ $(DIROBJ)\enc\frame_enc.obj \
+ $(DIROBJ)\enc\histogram_enc.obj \
+ $(DIROBJ)\enc\iterator_enc.obj \
+ $(DIROBJ)\enc\near_lossless_enc.obj \
+ $(DIROBJ)\enc\picture_enc.obj \
+ $(DIROBJ)\enc\picture_csp_enc.obj \
+ $(DIROBJ)\enc\picture_psnr_enc.obj \
+ $(DIROBJ)\enc\picture_rescale_enc.obj \
+ $(DIROBJ)\enc\picture_tools_enc.obj \
+ $(DIROBJ)\enc\predictor_enc.obj \
+ $(DIROBJ)\enc\quant_enc.obj \
+ $(DIROBJ)\enc\syntax_enc.obj \
+ $(DIROBJ)\enc\token_enc.obj \
+ $(DIROBJ)\enc\tree_enc.obj \
+ $(DIROBJ)\enc\vp8l_enc.obj \
+ $(DIROBJ)\enc\webp_enc.obj \
+
+EXTRAS_OBJS = \
+ $(DIROBJ)\extras\extras.obj \
+ $(DIROBJ)\extras\quality_estimate.obj \
+
+IMAGEIO_UTIL_OBJS = \
+ $(DIROBJ)\imageio\imageio_util.obj \
+
+MUX_OBJS = \
+ $(DIROBJ)\mux\anim_encode.obj \
+ $(DIROBJ)\mux\muxedit.obj \
+ $(DIROBJ)\mux\muxinternal.obj \
+ $(DIROBJ)\mux\muxread.obj \
+
+UTILS_DEC_OBJS = \
+ $(DIROBJ)\utils\bit_reader_utils.obj \
+ $(DIROBJ)\utils\color_cache_utils.obj \
+ $(DIROBJ)\utils\filters_utils.obj \
+ $(DIROBJ)\utils\huffman_utils.obj \
+ $(DIROBJ)\utils\quant_levels_dec_utils.obj \
+ $(DIROBJ)\utils\rescaler_utils.obj \
+ $(DIROBJ)\utils\random_utils.obj \
+ $(DIROBJ)\utils\thread_utils.obj \
+ $(DIROBJ)\utils\utils.obj \
+
+UTILS_ENC_OBJS = \
+ $(DIROBJ)\utils\bit_writer_utils.obj \
+ $(DIROBJ)\utils\huffman_encode_utils.obj \
+ $(DIROBJ)\utils\quant_levels_utils.obj \
+
+LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
+LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
+ $(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_OBJS)
+LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
+LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
+LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
+
+OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) $(LIBSHARPYUV)
+!IF "$(ARCH)" == "ARM"
+ex: $(OUT_LIBS)
+all: ex
+!ELSE
+OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
+EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \
+ $(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \
+ $(DIRBIN)\webp_quality.exe $(DIRBIN)\vwebp_sdl.exe \
+ $(DIRBIN)\webpinfo.exe
+
+ex: $(OUT_LIBS) $(OUT_EXAMPLES)
+all: ex $(EXTRA_EXAMPLES)
+# NB: gif2webp.exe and anim_diff.exe are excluded from 'all' as libgif requires
+# C99 support which is only available from VS2013 onward.
+gif2webp: $(DIRBIN)\gif2webp.exe
+anim_diff: $(DIRBIN)\anim_diff.exe
+anim_dump: $(DIRBIN)\anim_dump.exe
+
+$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
+$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS)
+$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
+$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
+$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX) $(LIBSHARPYUV)
+$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
+$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
+$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
+$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
+$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
+$(DIRBIN)\gif2webp.exe: $(LIBWEBP)
+$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
+$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
+$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\webp_to_sdl.obj
+$(DIRBIN)\vwebp_sdl.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
+$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
+$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
+$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
+$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
+$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
+$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj
+$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS)
+# EXTRA_OBJS requires private symbols from dsp. Explicitly add those when
+# building libwebp as a dll.
+!IF "$(DLLBUILD)" == "TRUE"
+$(DIRBIN)\webp_quality.exe: $(DSP_DEC_OBJS)
+!ENDIF
+$(DIRBIN)\webp_quality.exe: $(LIBWEBP)
+$(DIRBIN)\webpinfo.exe: $(DIROBJ)\examples\webpinfo.obj
+$(DIRBIN)\webpinfo.exe: $(IMAGEIO_DEC_OBJS)
+$(DIRBIN)\webpinfo.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
+$(DIRBIN)\webpinfo.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
+
+$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
+$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS)
+$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
+!ENDIF # ARCH == ARM
+
+$(LIBSHARPYUV): $(LIBSHARPYUV_OBJS)
+$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
+$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBSHARPYUV)
+$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
+$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
+
+$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \
+ $(OUTPUT_DIRS)
+
+!IF "$(DLLBUILD)" == "TRUE"
+{$(DIROBJ)}.c{$(DIROBJ)}.obj:
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
+
+{src}.rc{$(DIROBJ)}.res:
+ $(RC) /fo$@ $<
+{src\demux}.rc{$(DIROBJ)\demux}.res:
+ $(RC) /fo$@ $<
+{src\mux}.rc{$(DIROBJ)\mux}.res:
+ $(RC) /fo$@ $<
+{sharpyuv}.rc{$(DIROBJ)\sharpyuv}.res:
+ $(RC) /fo$@ $<
+
+$(LIBSHARPYUV): $(DIROBJ)\sharpyuv\$(LIBSHARPYUV_BASENAME:_debug=).res
+$(LIBWEBP): $(LIBSHARPYUV) $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
+$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
+$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
+$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
+
+$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
+ $(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
+ -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
+!ELSE
+$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
+ $(LNKLIB) /out:$@ $**
+ -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
+!ENDIF
+
+$(OUTPUT_DIRS):
+ @if not exist "$(@)" mkdir "$(@)"
+
+.SUFFIXES: .c .obj .res .exe
+# File-specific flag builds. Note batch rules take precedence over wildcards,
+# so for now name each file individually.
+$(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c
+ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
+ /Fo$(DIROBJ)\examples\ examples\$(@B).c
+$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c
+ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
+ /Fo$(DIROBJ)\examples\ examples\$(@B).c
+$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c
+ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
+ /Fo$(DIROBJ)\examples\ examples\$(@B).c
+$(DIROBJ)\examples\gif2webp.obj: examples\gif2webp.c
+ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
+ /Fo$(DIROBJ)\examples\ examples\$(@B).c
+$(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
+ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
+ /Fo$(DIROBJ)\examples\ examples\$(@B).c
+# Batch rules
+{examples}.c{$(DIROBJ)\examples}.obj::
+ $(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $<
+{extras}.c{$(DIROBJ)\extras}.obj::
+ $(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
+{imageio}.c{$(DIROBJ)\imageio}.obj::
+ $(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $<
+{sharpyuv}.c{$(DIROBJ)\sharpyuv}.obj::
+ $(CC) $(CFLAGS) /Fd$(DIROBJ)\sharpyuv\ /Fo$(DIROBJ)\sharpyuv\ $<
+{src\dec}.c{$(DIROBJ)\dec}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
+{src\demux}.c{$(DIROBJ)\demux}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\demux\ $<
+{src\dsp}.c{$(DIROBJ)\dsp}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ $<
+{src\enc}.c{$(DIROBJ)\enc}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\enc\ $<
+{src\mux}.c{$(DIROBJ)\mux}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\mux\ $<
+{src\utils}.c{$(DIROBJ)\utils}.obj::
+ $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
+
+LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib
+!IF "$(UNICODE)" == "1"
+LNKLIBS = $(LNKLIBS) Shell32.lib
+!ENDIF
+
+{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
+ $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
+
+{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
+ $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
+
+clean::
+ @-erase /s $(DIROBJ)\*.dll 2> NUL
+ @-erase /s $(DIROBJ)\*.exp 2> NUL
+ @-erase /s $(DIROBJ)\*.idb 2> NUL
+ @-erase /s $(DIROBJ)\*.lib 2> NUL
+ @-erase /s $(DIROBJ)\*.obj 2> NUL
+ @-erase /s $(DIROBJ)\*.pch 2> NUL
+ @-erase /s $(DIROBJ)\*.pdb 2> NUL
+ @-erase /s $(DIROBJ)\*.res 2> NUL
+
+!ENDIF # End of case where a config was provided.
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..c4f8ef7
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,296 @@
+- 12/16/2022: version 1.3.0
+ This is a binary compatible release.
+ * add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
+ functionality to other libraries; libwebp now depends on this library
+ * major updates to the container and lossless bitstream docs (#448, #546,
+ #551)
+ * miscellaneous warning, bug & build fixes (#576, #583, #584)
+
+- 8/4/2022: version 1.2.4
+ This is a binary compatible release.
+ * restore CMake libwebpmux target name for compatibility with 1.2.2 (#575)
+ * fix lossless crunch mode encoding with WEBP_REDUCE_SIZE
+ (chromium: #1345547, #1345595, #1345772, #1345804)
+
+- 6/30/2022: version 1.2.3
+ This is a binary compatible release.
+ * security fix for lossless encoder (#565, chromium:1313709)
+ * improved progress granularity in WebPReportProgress() when using lossless
+ * improved precision in Sharp YUV (-sharp_yuv) conversion
+ * many corrections to webp-lossless-bitstream-spec.txt (#551)
+ * crash/leak fixes on error/OOM and other bug fixes (#558, #563, #569, #573)
+
+- 1/11/2022: version 1.2.2
+ This is a binary compatible release.
+ * webpmux: add "-set bgcolor A,R,G,B"
+ * add ARM64 NEON support for MSVC builds (#539)
+ * fix duplicate include error in Xcode when using multiple XCFrameworks in a
+ project (#542)
+ * doc updates and bug fixes (#538, #544, #548, #550)
+
+- 7/20/2021: version 1.2.1
+ This is a binary compatible release.
+ * minor lossless encoder improvements and x86 color conversion speed up
+ * add ARM64 simulator support to xcframeworkbuild.sh (#510)
+ * further security related hardening in libwebp & examples
+ (issues: #497, #508, #518)
+ (chromium: #1196480, #1196773, #1196775, #1196777, #1196778, #1196850)
+ (oss-fuzz: #28658, #28978)
+ * toolchain updates and bug fixes (#498, #501, #502, #504, #505, #506, #509,
+ #533)
+ * use more inclusive language within the source (#507)
+
+- 12/23/2020: version 1.2.0
+ * API changes:
+ - libwebp:
+ encode.h: add a qmin / qmax range for quality factor (cwebp adds -qrange)
+ * lossless encoder improvements
+ * SIMD support for Wasm builds
+ * add xcframeworkbuild.sh, supports Mac Catalyst builds
+ * import fuzzers from oss-fuzz & chromium (#409)
+ * webpmux: add an '-set loop <value>' option (#494)
+ * toolchain updates and bug fixes (#449, #463, #470, #475, #477, #478, #479,
+ #488, #491)
+
+- 12/18/2019: version 1.1.0
+ * API changes:
+ - libwebp:
+ WebPMalloc (issue #442)
+ - extras:
+ WebPUnmultiplyARGB
+ * alpha decode fix (issue #439)
+ * toolchain updates and bug fixes
+ (chromium: #1026858, #1027136, #1027409, #1028620, #1028716, #995200)
+ (oss-fuzz: #19430, #19447)
+
+- 7/4/2019: version 1.0.3
+ This is a binary compatible release.
+ * resize fixes for Nx1 sizes and the addition of non-opaque alpha values for
+ odd sizes (issues #418, #434)
+ * lossless encode/decode performance improvements
+ * lossy compression performance improvement at low quality levels with flat
+ content (issue #432)
+ * python swig files updated to support python 3
+ Tool updates:
+ vwebp will now preserve the aspect ratio of images that exceed monitor
+ resolution by scaling the image to fit (issue #433)
+
+- 1/14/2019: version 1.0.2
+ This is a binary compatible release.
+ * (Windows) unicode file support in the tools (linux and mac already had
+ support, issue #398)
+ * lossless encoder speedups
+ * lossy encoder speedup on ARM
+ * lossless multi-threaded security fix (chromium:917029)
+
+- 11/2/2018: version 1.0.1
+ This is a binary compatible release.
+ * lossless encoder speedups
+ * big-endian fix for alpha decoding (issue #393)
+ * gif2webp fix for loop count=65535 transcode (issue #382)
+ * further security related hardening in libwebp & libwebpmux
+ (issues #383, #385, #386, #387, #388, #391)
+ (oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170,
+ #9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349,
+ #10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152)
+ * miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400)
+
+- 4/2/2018: version 1.0.0
+ This is a binary compatible release.
+ * lossy encoder improvements to avoid chroma shifts in various circumstances
+ (issues #308, #340)
+ * big-endian fixes for decode, RGBA import and WebPPictureDistortion
+ Tool updates:
+ gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
+ web browsers, transcoding tools (issue #379)
+ img2webp, webpmux - allow options to be passed in via a file (issue #355)
+
+- 11/24/2017: version 0.6.1
+ This is a binary compatible release.
+ * lossless performance and compression improvements + a new 'cruncher' mode
+ (-m 6 -q 100)
+ * ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
+ * webp-js: emscripten/webassembly based javascript decoder
+ * miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
+ #363)
+ Tool updates / additions:
+ added webpinfo - prints file format information (issue #330)
+ gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
+ '-loop_compatibility' can be used for the old behavior
+
+- 1/26/2017: version 0.6.0
+ * lossless performance and compression improvements
+ * miscellaneous performance improvements (SSE2, NEON, MSA)
+ * webpmux gained a -duration option allowing for frame timing modification
+ * new img2webp utility allowing a sequence of images to be converted to
+ animated webp
+ * API changes:
+ - libwebp:
+ WebPPictureSharpARGBToYUVA
+ WebPPlaneDistortion
+ - libwebpmux / gif2webp:
+ WebPAnimEncoderOptions: kmax <= 0 now disables keyframes, kmax == 1
+ forces all keyframes. See mux.h and the gif2webp
+ manpage for details.
+
+- 12/13/2016: version 0.5.2
+ This is a binary compatible release.
+ This release covers CVE-2016-8888 and CVE-2016-9085.
+ * further security related hardening in the tools; fixes to
+ gif2webp/AnimEncoder (issues #310, #314, #316, #322), cwebp/libwebp (issue
+ #312)
+ * full libwebp (encoder & decoder) iOS framework; libwebpdecoder
+ WebP.framework renamed to WebPDecoder.framework (issue #307)
+ * CMake support for Android Studio (2.2)
+ * miscellaneous build related fixes (issue #306, #313)
+ * miscellaneous documentation improvements (issue #225)
+ * minor lossy encoder fixes and improvements
+
+- 6/14/2016: version 0.5.1
+ This is a binary compatible release.
+ * miscellaneous bug fixes (issues #280, #289)
+ * reverted alpha plane encoding with color cache for compatibility with
+ libwebp 0.4.0->0.4.3 (issues #291, #298)
+ * lossless encoding performance improvements
+ * memory reduction in both lossless encoding and decoding
+ * force mux output to be in the extended format (VP8X) when undefined chunks
+ are present (issue #294)
+ * gradle, cmake build support
+ * workaround for compiler bug causing 64-bit decode failures on android
+ devices using clang-3.8 in the r11c NDK
+ * various WebPAnimEncoder improvements
+
+- 12/17/2015: version 0.5.0
+ * miscellaneous bug & build fixes (issues #234, #258, #274, #275, #278)
+ * encoder & decoder speed-ups on x86/ARM/MIPS for lossy & lossless
+ - note! YUV->RGB conversion was sped-up, but the results will be slightly
+ different from previous releases
+ * various lossless encoder improvements
+ * gif2webp improvements, -min_size option added
+ * tools fully support input from stdin and output to stdout (issue #168)
+ * New WebPAnimEncoder API for creating animations
+ * New WebPAnimDecoder API for decoding animations
+ * other API changes:
+ - libwebp:
+ WebPPictureSmartARGBToYUVA() (-pre 4 in cwebp)
+ WebPConfig::exact (-exact in cwebp; -alpha_cleanup is now the default)
+ WebPConfig::near_lossless (-near_lossless in cwebp)
+ WebPFree() (free'ing webp allocated memory in other languages)
+ WebPConfigLosslessPreset()
+ WebPMemoryWriterClear()
+ - libwebpdemux: removed experimental fragment related fields and functions
+ - libwebpmux: WebPMuxSetCanvasSize()
+ * new libwebpextras library with some uncommon import functions:
+ WebPImportGray/WebPImportRGB565/WebPImportRGB4444
+
+- 10/15/15: version 0.4.4
+ This is a binary compatible release.
+ * rescaling out-of-bounds read fix (issue #254)
+ * various build fixes and improvements (issues #253, #259, #262, #267, #268)
+ * container documentation update
+ * gif2webp transparency fix (issue #245)
+
+- 3/3/15: version 0.4.3
+ This is a binary compatible release.
+ * Android / gcc / iOS / MSVS build fixes and improvements
+ * lossless decode fix (issue #239 -- since 0.4.0)
+ * documentation / vwebp updates for animation
+ * multi-threading fix (issue #234)
+
+- 10/13/14: version 0.4.2
+ This is a binary compatible release.
+ * Android / gcc build fixes
+ * (Windows) fix reading from stdin and writing to stdout
+ * gif2webp: miscellaneous fixes
+ * fix 'alpha-leak' with lossy compression (issue #220)
+ * the lossless bitstream spec has been amended to reflect the current code
+
+- 7/24/14: version 0.4.1
+ This is a binary compatible release.
+ * AArch64 (arm64) & MIPS support/optimizations
+ * NEON assembly additions:
+ - ~25% faster lossy decode / encode (-m 4)
+ - ~10% faster lossless decode
+ - ~5-10% faster lossless encode (-m 3/4)
+ * dwebp/vwebp can read from stdin
+ * cwebp/gif2webp can write to stdout
+ * cwebp can read webp files; useful if storing sources as webp lossless
+
+- 12/19/13: version 0.4.0
+ * improved gif2webp tool
+ * numerous fixes, compression improvement and speed-up
+ * dither option added to decoder (dwebp -dither 50 ...)
+ * improved multi-threaded modes (-mt option)
+ * improved filtering strength determination
+ * New function: WebPMuxGetCanvasSize
+ * BMP and TIFF format output added to 'dwebp'
+ * Significant memory reduction for decoding lossy images with alpha.
+ * Intertwined decoding of RGB and alpha for a shorter
+ time-to-first-decoded-pixel.
+ * WebPIterator has a new member 'has_alpha' denoting whether the frame
+ contains transparency.
+ * Container spec amended with new 'blending method' for animation.
+
+- 6/13/13: version 0.3.1
+ This is a binary compatible release.
+ * Add incremental decoding support for images containing ALPH and ICCP chunks.
+ * Python bindings via swig for the simple encode/decode interfaces similar to
+ Java.
+
+- 3/20/13: version 0.3.0
+ This is a binary compatible release.
+ * WebPINewRGB/WebPINewYUVA accept being passed a NULL output buffer
+ and will perform auto-allocation.
+ * default filter option is now '-strong -f 60'
+ * encoding speed-up for lossy methods 3 to 6
+ * alpha encoding can be done in parallel to lossy using 'cwebp -mt ...'
+ * color profile, metadata (XMP/EXIF) and animation support finalized in the
+ container.
+ * various NEON assembly additions
+ Tool updates / additions:
+ * gif2webp added
+ * vwebp given color profile & animation support
+ * cwebp can preserve color profile / metadata with '-metadata'
+
+- 10/30/12: version 0.2.1
+ * Various security related fixes
+ * cwebp.exe: fix import errors on Windows XP
+ * enable DLL builds for mingw targets
+
+- 8/3/12: version 0.2.0
+ * Add support for ARGB -> YUVA conversion for lossless decoder
+ New functions: WebPINewYUVA, WebPIDecGetYUVA
+ * Add stats for lossless and alpha encoding
+ * Security related hardening: allocation and size checks
+ * Add PAM output support to dwebp
+
+- 7/19/12: version 0.1.99
+ * This is a pre-release of 0.2.0, not an rc to allow for further
+ incompatible changes based on user feedback.
+ * Alpha channel encode/decode support.
+ * Lossless encoder/decoder.
+ * Add TIFF input support to cwebp.
+ Incompatible changes:
+ * The encode ABI has been modified to support alpha encoding.
+ * Deprecated function WebPINew() has been removed.
+ * Decode function signatures have changed to consistently use size_t over
+ int/uint32_t.
+ * decode_vp8.h is no longer installed system-wide.
+ * cwebp will encode the alpha channel if present.
+
+- 9/19/11: version 0.1.3
+ * Advanced decoding APIs.
+ * On-the-fly cropping and rescaling of images.
+ * SSE2 instructions for decoding performance optimizations on x86 based
+ platforms.
+ * Support Multi-threaded decoding.
+ * 40% improvement in Decoding performance.
+ * Add support for RGB565, RGBA4444 & ARGB image colorspace.
+ * Better handling of large picture encoding.
+
+- 3/25/11: version 0.1.2
+ * Incremental decoding: picture can be decoded byte-by-byte if needs be.
+ * lot of bug-fixes, consolidation and stabilization
+
+- 2/23/11: initial release of version 0.1, with the new encoder
+- 9/30/10: initial release version with only the lightweight decoder
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
new file mode 100644
index 0000000..91ad12e
--- /dev/null
+++ b/PRESUBMIT.py
@@ -0,0 +1,245 @@
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Top-level presubmit script for libwebp.
+
+See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
+details on the presubmit API built into depot_tools.
+"""
+
+import re
+import subprocess2
+
+USE_PYTHON3 = True
+_BASH_INDENTATION = "2"
+_GIT_COMMIT_SUBJECT_LENGTH = 65
+_INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"]
+_INCLUDE_MAN_FILES_ONLY = [r"man/.+\.1$"]
+_INCLUDE_SOURCE_FILES_ONLY = [r".*\.[ch]$"]
+_LIBWEBP_MAX_LINE_LENGTH = 80
+
+
+def _CheckCommitSubjectLength(input_api, output_api):
+ """Ensures commit's subject length is no longer than 65 chars."""
+ name = "git-commit subject"
+ cmd = ["git", "log", "-1", "--pretty=%s"]
+ start = input_api.time.time()
+ proc = subprocess2.Popen(
+ cmd,
+ stderr=subprocess2.PIPE,
+ stdout=subprocess2.PIPE,
+ universal_newlines=True)
+
+ stdout, _ = proc.communicate()
+ duration = input_api.time.time() - start
+
+ if not re.match(r"^Revert",
+ stdout) and (len(stdout) - 1) > _GIT_COMMIT_SUBJECT_LENGTH:
+ failure_msg = (
+ "The commit subject: %s is too long (%d chars)\n"
+ "Try to keep this to 50 or less (up to 65 is permitted for "
+ "non-reverts).\n"
+ "https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-"
+ "Project#_commit_guidelines") % (stdout, len(stdout) - 1)
+ return output_api.PresubmitError("%s\n (%4.2fs) failed\n%s" %
+ (name, duration, failure_msg))
+
+ return output_api.PresubmitResult("%s\n (%4.2fs) success" % (name, duration))
+
+
+def _CheckDuplicateFiles(input_api, output_api):
+ """Ensures there are not repeated filenames."""
+ all_files = []
+ for f in input_api.change.AllFiles():
+ for include_file in _INCLUDE_SOURCE_FILES_ONLY:
+ if re.match(include_file, f):
+ all_files.append(f)
+ break
+
+ basename_to_path = {}
+ for f in all_files:
+ basename_file = input_api.basename(f)
+ if basename_file in basename_to_path:
+ basename_to_path[basename_file].append(f)
+ else:
+ basename_to_path[basename_file] = [f]
+
+ dupes = []
+ for files in basename_to_path.values():
+ if len(files) > 1:
+ dupes.extend(files)
+
+ if dupes:
+ return output_api.PresubmitError(
+ "Duplicate source files, rebase or rename some to make them unique:\n%s"
+ % dupes)
+ return output_api.PresubmitResult("No duplicates, success\n")
+
+
+def _GetFilesToSkip(input_api):
+ return list(input_api.DEFAULT_FILES_TO_SKIP) + [
+ r"swig/.*\.py$",
+ r"\.pylintrc$",
+ ]
+
+
+def _RunManCmd(input_api, output_api, man_file):
+ """man command wrapper."""
+ cmd = ["man", "--warnings", "-EUTF-8", "-l", "-Tutf8", "-Z", man_file]
+ name = "Check %s file." % man_file
+ start = input_api.time.time()
+ output, _ = subprocess2.communicate(
+ cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
+ duration = input_api.time.time() - start
+ if output[1]:
+ return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
+ (name, " ".join(cmd), duration, output[1]))
+ return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
+ (name, " ".join(cmd), duration))
+
+
+def _RunShellCheckCmd(input_api, output_api, bash_file):
+ """shellcheck command wrapper."""
+ cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file]
+ name = "Check %s file." % bash_file
+ start = input_api.time.time()
+ output, rc = subprocess2.communicate(
+ cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
+ duration = input_api.time.time() - start
+ if rc == 0:
+ return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
+ (name, " ".join(cmd), duration))
+ return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
+ (name, " ".join(cmd), duration, output[1]))
+
+
+def _RunShfmtCheckCmd(input_api, output_api, bash_file):
+ """shfmt command wrapper."""
+ cmd = [
+ "shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d",
+ bash_file
+ ]
+ name = "Check %s file." % bash_file
+ start = input_api.time.time()
+ output, rc = subprocess2.communicate(
+ cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
+ duration = input_api.time.time() - start
+ if rc == 0:
+ return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
+ (name, " ".join(cmd), duration))
+ return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
+ (name, " ".join(cmd), duration, output[1]))
+
+
+def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check):
+ """Ensure that libwebp/ files are clean."""
+ file_filter = lambda x: input_api.FilterSourceFile(
+ x, files_to_check=files_to_check, files_to_skip=None)
+
+ affected_files = input_api.change.AffectedFiles(file_filter=file_filter)
+ results = [
+ run_cmd(input_api, output_api, f.AbsoluteLocalPath())
+ for f in affected_files
+ ]
+ return results
+
+
+def _CommonChecks(input_api, output_api):
+ """Ensures this patch does not have trailing spaces, extra EOLs,
+ or long lines.
+ """
+ results = []
+ results.extend(
+ input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
+ input_api, output_api))
+ results.extend(
+ input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api))
+ results.extend(
+ input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
+ input_api, output_api))
+ results.append(_CheckCommitSubjectLength(input_api, output_api))
+ results.append(_CheckDuplicateFiles(input_api, output_api))
+
+ source_file_filter = lambda x: input_api.FilterSourceFile(
+ x, files_to_skip=_GetFilesToSkip(input_api))
+ results.extend(
+ input_api.canned_checks.CheckLongLines(
+ input_api,
+ output_api,
+ maxlen=_LIBWEBP_MAX_LINE_LENGTH,
+ source_file_filter=source_file_filter))
+
+ results.extend(
+ input_api.canned_checks.CheckPatchFormatted(
+ input_api,
+ output_api,
+ check_clang_format=False,
+ check_python=True,
+ result_factory=output_api.PresubmitError))
+ results.extend(
+ _RunCmdOnCheckedFiles(input_api, output_api, _RunManCmd,
+ _INCLUDE_MAN_FILES_ONLY))
+ # Run pylint.
+ results.extend(
+ input_api.canned_checks.RunPylint(
+ input_api,
+ output_api,
+ files_to_skip=_GetFilesToSkip(input_api),
+ pylintrc=".pylintrc",
+ version="2.7"))
+
+ # Binaries shellcheck and shfmt are not installed in depot_tools.
+ # Installation is needed
+ try:
+ subprocess2.communicate(["shellcheck", "--version"])
+ results.extend(
+ _RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd,
+ _INCLUDE_BASH_FILES_ONLY))
+ print("shfmt")
+ subprocess2.communicate(["shfmt", "-version"])
+ results.extend(
+ _RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd,
+ _INCLUDE_BASH_FILES_ONLY))
+ except OSError as os_error:
+ results.append(
+ output_api.PresubmitPromptWarning(
+ "%s\nPlease install missing binaries locally." % os_error.args[0]))
+ return results
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results.extend(_CommonChecks(input_api, output_api))
+ return results
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ results = []
+ results.extend(_CommonChecks(input_api, output_api))
+ return results
diff --git a/README b/README
deleted file mode 100644
index f6eaf2c..0000000
--- a/README
+++ /dev/null
@@ -1,795 +0,0 @@
- __ __ ____ ____ ____
- / \\/ \/ _ \/ _ )/ _ \
- \ / __/ _ \ __/
- \__\__/\____/\_____/__/ ____ ___
- / _/ / \ \ / _ \/ _/
- / \_/ / / \ \ __/ \__
- \____/____/\_____/_____/____/v1.2.2
-
-Description:
-============
-
-WebP codec: library to encode and decode images in WebP format. This package
-contains the library that can be used in other programs to add WebP support,
-as well as the command line tools 'cwebp' and 'dwebp'.
-
-See https://developers.google.com/speed/webp
-
-The latest source tree is available at
-https://chromium.googlesource.com/webm/libwebp
-
-It is released under the same license as the WebM project.
-See https://www.webmproject.org/license/software/ or the
-"COPYING" file for details. An additional intellectual
-property rights grant can be found in the file PATENTS.
-
-Building:
-=========
-
-Windows build:
---------------
-
-By running:
-
- nmake /f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output
-
-the directory output\release-static\(x64|x86)\bin will contain the tools
-cwebp.exe and dwebp.exe. The directory output\release-static\(x64|x86)\lib will
-contain the libwebp static library.
-The target architecture (x86/x64) is detected by Makefile.vc from the Visual
-Studio compiler (cl.exe) available in the system path.
-
-Unix build using makefile.unix:
--------------------------------
-
-On platforms with GNU tools installed (gcc and make), running
-
- make -f makefile.unix
-
-will build the binaries examples/cwebp and examples/dwebp, along
-with the static library src/libwebp.a. No system-wide installation
-is supplied, as this is a simple alternative to the full installation
-system based on the autoconf tools (see below).
-Please refer to makefile.unix for additional details and customizations.
-
-Using autoconf tools:
----------------------
-Prerequisites:
-A compiler (e.g., gcc), make, autoconf, automake, libtool.
-On a Debian-like system the following should install everything you need for a
-minimal build:
-$ sudo apt-get install gcc make autoconf automake libtool
-
-When building from git sources, you will need to run autogen.sh to generate the
-configure script.
-
-./configure
-make
-make install
-
-should be all you need to have the following files
-
-/usr/local/include/webp/decode.h
-/usr/local/include/webp/encode.h
-/usr/local/include/webp/types.h
-/usr/local/lib/libwebp.*
-/usr/local/bin/cwebp
-/usr/local/bin/dwebp
-
-installed.
-
-Note: A decode-only library, libwebpdecoder, is available using the
-'--enable-libwebpdecoder' flag. The encode library is built separately and can
-be installed independently using a minor modification in the corresponding
-Makefile.am configure files (see comments there). See './configure --help' for
-more options.
-
-Building for MIPS Linux:
-------------------------
-MIPS Linux toolchain stable available releases can be found at:
-https://community.imgtec.com/developers/mips/tools/codescape-mips-sdk/available-releases/
-
-# Add toolchain to PATH
-export PATH=$PATH:/path/to/toolchain/bin
-
-# 32-bit build for mips32r5 (p5600)
-HOST=mips-mti-linux-gnu
-MIPS_CFLAGS="-O3 -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64 \
- -msched-weight -mload-store-pairs -fPIE"
-MIPS_LDFLAGS="-mips32r5 -mabi=32 -mmsa -mfp64 -pie"
-
-# 64-bit build for mips64r6 (i6400)
-HOST=mips-img-linux-gnu
-MIPS_CFLAGS="-O3 -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64 \
- -msched-weight -mload-store-pairs -fPIE"
-MIPS_LDFLAGS="-mips64r6 -mabi=64 -mmsa -mfp64 -pie"
-
-./configure --host=${HOST} --build=`config.guess` \
- CC="${HOST}-gcc -EL" \
- CFLAGS="$MIPS_CFLAGS" \
- LDFLAGS="$MIPS_LDFLAGS"
-make
-make install
-
-CMake:
-------
-With CMake, you can compile libwebp, cwebp, dwebp, gif2webp, img2webp, webpinfo
-and the JS bindings.
-
-Prerequisites:
-A compiler (e.g., gcc with autotools) and CMake.
-On a Debian-like system the following should install everything you need for a
-minimal build:
-$ sudo apt-get install build-essential cmake
-
-When building from git sources, you will need to run cmake to generate the
-makefiles.
-
-mkdir build && cd build && cmake ../
-make
-make install
-
-If you also want any of the executables, you will need to enable them through
-CMake, e.g.:
-
-cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
-
-or through your favorite interface (like ccmake or cmake-qt-gui).
-
-Use option -DWEBP_UNICODE=ON for Unicode support on Windows (with chcp 65001).
-
-Finally, once installed, you can also use WebP in your CMake project by doing:
-
-find_package(WebP)
-
-which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
-
-Gradle:
--------
-The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
-dwebp and webpmux_example.
-
-Prerequisites:
-A compiler (e.g., gcc with autotools) and gradle.
-On a Debian-like system the following should install everything you need for a
-minimal build:
-$ sudo apt-get install build-essential gradle
-
-When building from git sources, you will need to run the Gradle wrapper with the
-appropriate target, e.g. :
-
-./gradlew buildAllExecutables
-
-SWIG bindings:
---------------
-
-To generate language bindings from swig/libwebp.swig at least swig-1.3
-(http://www.swig.org) is required.
-
-Currently the following functions are mapped:
-Decode:
- WebPGetDecoderVersion
- WebPGetInfo
- WebPDecodeRGBA
- WebPDecodeARGB
- WebPDecodeBGRA
- WebPDecodeBGR
- WebPDecodeRGB
-
-Encode:
- WebPGetEncoderVersion
- WebPEncodeRGBA
- WebPEncodeBGRA
- WebPEncodeRGB
- WebPEncodeBGR
- WebPEncodeLosslessRGBA
- WebPEncodeLosslessBGRA
- WebPEncodeLosslessRGB
- WebPEncodeLosslessBGR
-
-See swig/README for more detailed build instructions.
-
-Java bindings:
-
-To build the swig-generated JNI wrapper code at least JDK-1.5 (or equivalent)
-is necessary for enum support. The output is intended to be a shared object /
-DLL that can be loaded via System.loadLibrary("webp_jni").
-
-Python bindings:
-
-To build the swig-generated Python extension code at least Python 2.6 is
-required. Python < 2.6 may build with some minor changes to libwebp.swig or the
-generated code, but is untested.
-
-Encoding tool:
-==============
-
-The examples/ directory contains tools for encoding (cwebp) and
-decoding (dwebp) images.
-
-The easiest use should look like:
- cwebp input.png -q 80 -o output.webp
-which will convert the input file to a WebP file using a quality factor of 80
-on a 0->100 scale (0 being the lowest quality, 100 being the best. Default
-value is 75).
-You might want to try the -lossless flag too, which will compress the source
-(in RGBA format) without any loss. The -q quality parameter will in this case
-control the amount of processing time spent trying to make the output file as
-small as possible.
-
-A longer list of options is available using the -longhelp command line flag:
-
-> cwebp -longhelp
-Usage:
- cwebp [-preset <...>] [options] in_file [-o out_file]
-
-If input size (-s) for an image is not specified, it is
-assumed to be a PNG, JPEG, TIFF or WebP file.
-Note: Animated PNG and WebP files are not supported.
-
-Options:
- -h / -help ............. short help
- -H / -longhelp ......... long help
- -q <float> ............. quality factor (0:small..100:big), default=75
- -alpha_q <int> ......... transparency-compression quality (0..100),
- default=100
- -preset <string> ....... preset setting, one of:
- default, photo, picture,
- drawing, icon, text
- -preset must come first, as it overwrites other parameters
- -z <int> ............... activates lossless preset with given
- level in [0:fast, ..., 9:slowest]
-
- -m <int> ............... compression method (0=fast, 6=slowest), default=4
- -segments <int> ........ number of segments to use (1..4), default=4
- -size <int> ............ target size (in bytes)
- -psnr <float> .......... target PSNR (in dB. typically: 42)
-
- -s <int> <int> ......... input size (width x height) for YUV
- -sns <int> ............. spatial noise shaping (0:off, 100:max), default=50
- -f <int> ............... filter strength (0=off..100), default=60
- -sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0
- -strong ................ use strong filter instead of simple (default)
- -nostrong .............. use simple filter instead of strong
- -sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
- -partition_limit <int> . limit quality to fit the 512k limit on
- the first partition (0=no degradation ... 100=full)
- -pass <int> ............ analysis pass number (1..10)
- -qrange <min> <max> .... specifies the permissible quality range
- (default: 0 100)
- -crop <x> <y> <w> <h> .. crop picture with the given rectangle
- -resize <w> <h> ........ resize picture (after any cropping)
- -mt .................... use multi-threading if available
- -low_memory ............ reduce memory usage (slower encoding)
- -map <int> ............. print map of extra info
- -print_psnr ............ prints averaged PSNR distortion
- -print_ssim ............ prints averaged SSIM distortion
- -print_lsim ............ prints local-similarity distortion
- -d <file.pgm> .......... dump the compressed output (PGM file)
- -alpha_method <int> .... transparency-compression method (0..1), default=1
- -alpha_filter <string> . predictive filtering for alpha plane,
- one of: none, fast (default) or best
- -exact ................. preserve RGB values in transparent area, default=off
- -blend_alpha <hex> ..... blend colors against background color
- expressed as RGB values written in
- hexadecimal, e.g. 0xc0e0d0 for red=0xc0
- green=0xe0 and blue=0xd0
- -noalpha ............... discard any transparency information
- -lossless .............. encode image losslessly, default=off
- -near_lossless <int> ... use near-lossless image
- preprocessing (0..100=off), default=100
- -hint <string> ......... specify image characteristics hint,
- one of: photo, picture or graph
-
- -metadata <string> ..... comma separated list of metadata to
- copy from the input to the output if present.
- Valid values: all, none (default), exif, icc, xmp
-
- -short ................. condense printed message
- -quiet ................. don't print anything
- -version ............... print version number and exit
- -noasm ................. disable all assembly optimizations
- -v ..................... verbose, e.g. print encoding/decoding times
- -progress .............. report encoding progress
-
-Experimental Options:
- -jpeg_like ............. roughly match expected JPEG size
- -af .................... auto-adjust filter strength
- -pre <int> ............. pre-processing filter
-
-
-The main options you might want to try in order to further tune the
-visual quality are:
- -preset
- -sns
- -f
- -m
-
-Namely:
- * 'preset' will set up a default encoding configuration targeting a
- particular type of input. It should appear first in the list of options,
- so that subsequent options can take effect on top of this preset.
- Default value is 'default'.
- * 'sns' will progressively turn on (when going from 0 to 100) some additional
- visual optimizations (like: segmentation map re-enforcement). This option
- will balance the bit allocation differently. It tries to take bits from the
- "easy" parts of the picture and use them in the "difficult" ones instead.
- Usually, raising the sns value (at fixed -q value) leads to larger files,
- but with better quality.
- Typical value is around '75'.
- * 'f' option directly links to the filtering strength used by the codec's
- in-loop processing. The higher the value, the smoother the
- highly-compressed area will look. This is particularly useful when aiming
- at very small files. Typical values are around 20-30. Note that using the
- option -strong/-nostrong will change the type of filtering. Use "-f 0" to
- turn filtering off.
- * 'm' controls the trade-off between encoding speed and quality. Default is 4.
- You can try -m 5 or -m 6 to explore more (time-consuming) encoding
- possibilities. A lower value will result in faster encoding at the expense
- of quality.
-
-Decoding tool:
-==============
-
-There is a decoding sample in examples/dwebp.c which will take
-a .webp file and decode it to a PNG image file (amongst other formats).
-This is simply to demonstrate the use of the API. You can verify the
-file test.webp decodes to exactly the same as test_ref.ppm by using:
-
- cd examples
- ./dwebp test.webp -ppm -o test.ppm
- diff test.ppm test_ref.ppm
-
-The full list of options is available using -h:
-
-> dwebp -h
-Usage: dwebp in_file [options] [-o out_file]
-
-Decodes the WebP image file to PNG format [Default].
-Note: Animated WebP files are not supported.
-
-Use following options to convert into alternate image formats:
- -pam ......... save the raw RGBA samples as a color PAM
- -ppm ......... save the raw RGB samples as a color PPM
- -bmp ......... save as uncompressed BMP format
- -tiff ........ save as uncompressed TIFF format
- -pgm ......... save the raw YUV samples as a grayscale PGM
- file with IMC4 layout
- -yuv ......... save the raw YUV samples in flat layout
-
- Other options are:
- -version ..... print version number and exit
- -nofancy ..... don't use the fancy YUV420 upscaler
- -nofilter .... disable in-loop filtering
- -nodither .... disable dithering
- -dither <d> .. dithering strength (in 0..100)
- -alpha_dither use alpha-plane dithering if needed
- -mt .......... use multi-threading
- -crop <x> <y> <w> <h> ... crop output with the given rectangle
- -resize <w> <h> ......... scale the output (*after* any cropping)
- -flip ........ flip the output vertically
- -alpha ....... only save the alpha plane
- -incremental . use incremental decoding (useful for tests)
- -h ........... this help message
- -v ........... verbose (e.g. print encoding/decoding times)
- -quiet ....... quiet mode, don't print anything
- -noasm ....... disable all assembly optimizations
-
-WebP file analysis tool:
-========================
-
-'webpinfo' can be used to print out the chunk level structure and bitstream
-header information of WebP files. It can also check if the files are of valid
-WebP format.
-
-Usage: webpinfo [options] in_files
-Note: there could be multiple input files;
- options must come before input files.
-Options:
- -version ........... Print version number and exit.
- -quiet ............. Do not show chunk parsing information.
- -diag .............. Show parsing error diagnosis.
- -summary ........... Show chunk stats summary.
- -bitstream_info .... Parse bitstream header.
-
-Visualization tool:
-===================
-
-There's a little self-serve visualization tool called 'vwebp' under the
-examples/ directory. It uses OpenGL to open a simple drawing window and show
-a decoded WebP file. It's not yet integrated in the automake build system, but
-you can try to manually compile it using the recommendations below.
-
-Usage: vwebp in_file [options]
-
-Decodes the WebP image file and visualize it using OpenGL
-Options are:
- -version ..... print version number and exit
- -noicc ....... don't use the icc profile if present
- -nofancy ..... don't use the fancy YUV420 upscaler
- -nofilter .... disable in-loop filtering
- -dither <int> dithering strength (0..100), default=50
- -noalphadither disable alpha plane dithering
- -usebgcolor .. display background color
- -mt .......... use multi-threading
- -info ........ print info
- -h ........... this help message
-
-Keyboard shortcuts:
- 'c' ................ toggle use of color profile
- 'b' ................ toggle background color display
- 'i' ................ overlay file information
- 'd' ................ disable blending & disposal (debug)
- 'q' / 'Q' / ESC .... quit
-
-Building:
----------
-
-Prerequisites:
-1) OpenGL & OpenGL Utility Toolkit (GLUT)
- Linux:
- $ sudo apt-get install freeglut3-dev mesa-common-dev
- Mac + Xcode:
- - These libraries should be available in the OpenGL / GLUT frameworks.
- Windows:
- http://freeglut.sourceforge.net/index.php#download
-
-2) (Optional) qcms (Quick Color Management System)
- i. Download qcms from Mozilla / Chromium:
- https://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/qcms/;drc=d4a2f8e1ed461d8fc05ed88d1ae2dc94c9773825
- ii. Build and archive the source files as libqcms.a / qcms.lib
- iii. Update makefile.unix / Makefile.vc
- a) Define WEBP_HAVE_QCMS
- b) Update include / library paths to reference the qcms directory.
-
-Build using makefile.unix / Makefile.vc:
-$ make -f makefile.unix examples/vwebp
-> nmake /f Makefile.vc CFG=release-static \
- ../obj/x64/release-static/bin/vwebp.exe
-
-Animation creation tool:
-========================
-The utility 'img2webp' can turn a sequence of input images (PNG, JPEG, ...)
-into an animated WebP file. It offers fine control over duration, encoding
-modes, etc.
-
-Usage:
-
- img2webp [file_options] [[frame_options] frame_file]...
-
-File-level options (only used at the start of compression):
- -min_size ............ minimize size
- -loop <int> .......... loop count (default: 0, = infinite loop)
- -kmax <int> .......... maximum number of frame between key-frames
- (0=only keyframes)
- -kmin <int> .......... minimum number of frame between key-frames
- (0=disable key-frames altogether)
- -mixed ............... use mixed lossy/lossless automatic mode
- -v ................... verbose mode
- -h ................... this help
- -version ............. print version number and exit
-
-Per-frame options (only used for subsequent images input):
- -d <int> ............. frame duration in ms (default: 100)
- -lossless ........... use lossless mode (default)
- -lossy ... ........... use lossy mode
- -q <float> ........... quality
- -m <int> ............. method to use
-
-example: img2webp -loop 2 in0.png -lossy in1.jpg
- -d 80 in2.tiff -o out.webp
-
-Note: if a single file name is passed as the argument, the arguments will be
-tokenized from this file. The file name must not start with the character '-'.
-
-Animated GIF conversion:
-========================
-Animated GIF files can be converted to WebP files with animation using the
-gif2webp utility available under examples/. The files can then be viewed using
-vwebp.
-
-Usage:
- gif2webp [options] gif_file -o webp_file
-Options:
- -h / -help ............. this help
- -lossy ................. encode image using lossy compression
- -mixed ................. for each frame in the image, pick lossy
- or lossless compression heuristically
- -q <float> ............. quality factor (0:small..100:big)
- -m <int> ............... compression method (0=fast, 6=slowest)
- -min_size .............. minimize output size (default:off)
- lossless compression by default; can be
- combined with -q, -m, -lossy or -mixed
- options
- -kmin <int> ............ min distance between key frames
- -kmax <int> ............ max distance between key frames
- -f <int> ............... filter strength (0=off..100)
- -metadata <string> ..... comma separated list of metadata to
- copy from the input to the output if present
- Valid values: all, none, icc, xmp (default)
- -loop_compatibility .... use compatibility mode for Chrome
- version prior to M62 (inclusive)
- -mt .................... use multi-threading if available
-
- -version ............... print version number and exit
- -v ..................... verbose
- -quiet ................. don't print anything
-
-Building:
----------
-With the libgif development files installed, gif2webp can be built using
-makefile.unix:
-$ make -f makefile.unix examples/gif2webp
-
-or using autoconf:
-$ ./configure --enable-everything
-$ make
-
-Comparison of animated images:
-==============================
-Test utility anim_diff under examples/ can be used to compare two animated
-images (each can be GIF or WebP).
-
-Usage: anim_diff <image1> <image2> [options]
-
-Options:
- -dump_frames <folder> dump decoded frames in PAM format
- -min_psnr <float> ... minimum per-frame PSNR
- -raw_comparison ..... if this flag is not used, RGB is
- premultiplied before comparison
- -max_diff <int> ..... maximum allowed difference per channel
- between corresponding pixels in subsequent
- frames
- -h .................. this help
- -version ............ print version number and exit
-
-Building:
----------
-With the libgif development files and a C++ compiler installed, anim_diff can
-be built using makefile.unix:
-$ make -f makefile.unix examples/anim_diff
-
-or using autoconf:
-$ ./configure --enable-everything
-$ make
-
-Encoding API:
-=============
-
-The main encoding functions are available in the header src/webp/encode.h
-The ready-to-use ones are:
-size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride,
- float quality_factor, uint8_t** output);
-size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride,
- float quality_factor, uint8_t** output);
-size_t WebPEncodeRGBA(const uint8_t* rgba, int width, int height, int stride,
- float quality_factor, uint8_t** output);
-size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride,
- float quality_factor, uint8_t** output);
-
-They will convert raw RGB samples to a WebP data. The only control supplied
-is the quality factor.
-
-There are some variants for using the lossless format:
-
-size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height,
- int stride, uint8_t** output);
-size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height,
- int stride, uint8_t** output);
-size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height,
- int stride, uint8_t** output);
-size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height,
- int stride, uint8_t** output);
-
-Of course in this case, no quality factor is needed since the compression
-occurs without loss of the input values, at the expense of larger output sizes.
-
-Advanced encoding API:
-----------------------
-
-A more advanced API is based on the WebPConfig and WebPPicture structures.
-
-WebPConfig contains the encoding settings and is not tied to a particular
-picture.
-WebPPicture contains input data, on which some WebPConfig will be used for
-compression.
-The encoding flow looks like:
-
--------------------------------------- BEGIN PSEUDO EXAMPLE
-
-#include <webp/encode.h>
-
- // Setup a config, starting form a preset and tuning some additional
- // parameters
- WebPConfig config;
- if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) {
- return 0; // version error
- }
- // ... additional tuning
- config.sns_strength = 90;
- config.filter_sharpness = 6;
- config_error = WebPValidateConfig(&config); // not mandatory, but useful
-
- // Setup the input data
- WebPPicture pic;
- if (!WebPPictureInit(&pic)) {
- return 0; // version error
- }
- pic.width = width;
- pic.height = height;
- // allocated picture of dimension width x height
- if (!WebPPictureAlloc(&pic)) {
- return 0; // memory error
- }
- // at this point, 'pic' has been initialized as a container,
- // and can receive the Y/U/V samples.
- // Alternatively, one could use ready-made import functions like
- // WebPPictureImportRGB(), which will take care of memory allocation.
- // In any case, past this point, one will have to call
- // WebPPictureFree(&pic) to reclaim memory.
-
- // Set up a byte-output write method. WebPMemoryWriter, for instance.
- WebPMemoryWriter wrt;
- WebPMemoryWriterInit(&wrt); // initialize 'wrt'
-
- pic.writer = MyFileWriter;
- pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work;
-
- // Compress!
- int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred!
- WebPPictureFree(&pic); // must be called independently of the 'ok' result.
-
- // output data should have been handled by the writer at that point.
- // -> compressed data is the memory buffer described by wrt.mem / wrt.size
-
- // deallocate the memory used by compressed data
- WebPMemoryWriterClear(&wrt);
-
--------------------------------------- END PSEUDO EXAMPLE
-
-Decoding API:
-=============
-
-This is mainly just one function to call:
-
-#include "webp/decode.h"
-uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-Please have a look at the file src/webp/decode.h for the details.
-There are variants for decoding in BGR/RGBA/ARGB/BGRA order, along with
-decoding to raw Y'CbCr samples. One can also decode the image directly into a
-pre-allocated buffer.
-
-To detect a WebP file and gather the picture's dimensions, the function:
- int WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height);
-is supplied. No decoding is involved when using it.
-
-Incremental decoding API:
-=========================
-
-In the case when data is being progressively transmitted, pictures can still
-be incrementally decoded using a slightly more complicated API. Decoder state
-is stored into an instance of the WebPIDecoder object. This object can be
-created with the purpose of decoding either RGB or Y'CbCr samples.
-For instance:
-
- WebPDecBuffer buffer;
- WebPInitDecBuffer(&buffer);
- buffer.colorspace = MODE_BGR;
- ...
- WebPIDecoder* idec = WebPINewDecoder(&buffer);
-
-As data is made progressively available, this incremental-decoder object
-can be used to decode the picture further. There are two (mutually exclusive)
-ways to pass freshly arrived data:
-
-either by appending the fresh bytes:
-
- WebPIAppend(idec, fresh_data, size_of_fresh_data);
-
-or by just mentioning the new size of the transmitted data:
-
- WebPIUpdate(idec, buffer, size_of_transmitted_buffer);
-
-Note that 'buffer' can be modified between each call to WebPIUpdate, in
-particular when the buffer is resized to accommodate larger data.
-
-These functions will return the decoding status: either VP8_STATUS_SUSPENDED if
-decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other
-status is an error condition.
-
-The 'idec' object must always be released (even upon an error condition) by
-calling: WebPDelete(idec).
-
-To retrieve partially decoded picture samples, one must use the corresponding
-method: WebPIDecGetRGB or WebPIDecGetYUVA.
-It will return the last displayable pixel row.
-
-Lastly, note that decoding can also be performed into a pre-allocated pixel
-buffer. This buffer must be passed when creating a WebPIDecoder, calling
-WebPINewRGB() or WebPINewYUVA().
-
-Please have a look at the src/webp/decode.h header for further details.
-
-Advanced Decoding API:
-======================
-
-WebP decoding supports an advanced API which provides on-the-fly cropping and
-rescaling, something of great usefulness on memory-constrained environments like
-mobile phones. Basically, the memory usage will scale with the output's size,
-not the input's, when one only needs a quick preview or a zoomed in portion of
-an otherwise too-large picture. Some CPU can be saved too, incidentally.
-
--------------------------------------- BEGIN PSEUDO EXAMPLE
- // A) Init a configuration object
- WebPDecoderConfig config;
- CHECK(WebPInitDecoderConfig(&config));
-
- // B) optional: retrieve the bitstream's features.
- CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
-
- // C) Adjust 'config' options, if needed
- config.options.no_fancy_upsampling = 1;
- config.options.use_scaling = 1;
- config.options.scaled_width = scaledWidth();
- config.options.scaled_height = scaledHeight();
- // etc.
-
- // D) Specify 'config' output options for specifying output colorspace.
- // Optionally the external image decode buffer can also be specified.
- config.output.colorspace = MODE_BGRA;
- // Optionally, the config.output can be pointed to an external buffer as
- // well for decoding the image. This externally supplied memory buffer
- // should be big enough to store the decoded picture.
- config.output.u.RGBA.rgba = (uint8_t*) memory_buffer;
- config.output.u.RGBA.stride = scanline_stride;
- config.output.u.RGBA.size = total_size_of_the_memory_buffer;
- config.output.is_external_memory = 1;
-
- // E) Decode the WebP image. There are two variants w.r.t decoding image.
- // The first one (E.1) decodes the full image and the second one (E.2) is
- // used to incrementally decode the image using small input buffers.
- // Any one of these steps can be used to decode the WebP image.
-
- // E.1) Decode full image.
- CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);
-
- // E.2) Decode image incrementally.
- WebPIDecoder* const idec = WebPIDecode(NULL, NULL, &config);
- CHECK(idec != NULL);
- while (bytes_remaining > 0) {
- VP8StatusCode status = WebPIAppend(idec, input, bytes_read);
- if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
- bytes_remaining -= bytes_read;
- } else {
- break;
- }
- }
- WebPIDelete(idec);
-
- // F) Decoded image is now in config.output (and config.output.u.RGBA).
- // It can be saved, displayed or otherwise processed.
-
- // G) Reclaim memory allocated in config's object. It's safe to call
- // this function even if the memory is external and wasn't allocated
- // by WebPDecode().
- WebPFreeDecBuffer(&config.output);
-
--------------------------------------- END PSEUDO EXAMPLE
-
-Bugs:
-=====
-
-Please report all bugs to the issue tracker:
- https://bugs.chromium.org/p/webp
-Patches welcome! See this page to get started:
- https://www.webmproject.org/code/contribute/submitting-patches/
-
-Discuss:
-========
-
-Email: webp-discuss@webmproject.org
-Web: https://groups.google.com/a/webmproject.org/group/webp-discuss
diff --git a/README.android b/README.android
index 4f445bb..8e5fca2 100644
--- a/README.android
+++ b/README.android
@@ -1,13 +1,9 @@
URL: https://chromium.googlesource.com/webm/libwebp
-Version: 1.2.2
+Version: 1.3.0
License: Google BSD like
Local modifications:
-- Copy public headers from src/webp to include/webp, so path to headers
- may be appended into CFLAGS without risk for other private headers
- (e.g. bits.h) to leak into
-- Removed build files necessary for building via autoconf/automake tools
- These files are not required to build via Android.bp
+- LOCAL_LICENSE_KINDS and related variables added to **/Android.mk
The Android.bp file creates WebP decoder and encoder static libraries which
can be added to any application by adding libwebp-decode and libwebp-encode to
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4e201d3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,53 @@
+# WebP Codec
+
+```
+ __ __ ____ ____ ____
+ / \\/ \/ _ \/ _ )/ _ \
+ \ / __/ _ \ __/
+ \__\__/\____/\_____/__/ ____ ___
+ / _/ / \ \ / _ \/ _/
+ / \_/ / / \ \ __/ \__
+ \____/____/\_____/_____/____/v1.3.0
+```
+
+WebP codec is a library to encode and decode images in WebP format. This package
+contains the library that can be used in other programs to add WebP support, as
+well as the command line tools 'cwebp' and 'dwebp' to compress and decompress
+images respectively.
+
+See https://developers.google.com/speed/webp for details on the image format.
+
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+
+It is released under the same license as the WebM project. See
+https://www.webmproject.org/license/software/ or the "COPYING" file for details.
+An additional intellectual property rights grant can be found in the file
+PATENTS.
+
+## Building
+
+See the [building documentation](doc/building.md).
+
+## Encoding and Decoding Tools
+
+The examples/ directory contains tools to encode and decode images and
+animations, view information about WebP images, and more. See the
+[tools documentation](doc/tools.md).
+
+## APIs
+
+See the [APIs documentation](doc/api.md), and API usage examples in the
+`examples/` directory.
+
+## Bugs
+
+Please report all bugs to the issue tracker: https://bugs.chromium.org/p/webp
+
+Patches welcome! See [how to contribute](CONTRIBUTING.md).
+
+## Discuss
+
+Email: webp-discuss@webmproject.org
+
+Web: https://groups.google.com/a/webmproject.org/group/webp-discuss
diff --git a/README.version b/README.version
index 873040b..9189f43 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: https://chromium.googlesource.com/webm/libwebp/+archive/20ef03ee351d4ff03fc5ff3ec4804a879d1b9d5c.tar.gz
-Version: 1.2.2
+URL: https://chromium.googlesource.com/webm/libwebp
+Version: v1.3.0
BugComponent: 20174
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..8ef9bab
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,2 @@
+#! /bin/sh -e
+exec autoreconf -fi
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..c25314c
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,443 @@
+// Define dependencies.
+buildscript {
+ repositories {
+ maven {
+ url "https://jcenter.bintray.com"
+ }
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:${ANDROID_GRADLE_PLUGIN_VERSION}"
+ }
+}
+
+// Define versions in the project.
+project.ext {
+ buildToolsVersion = "${BUILD_TOOLS_VERSION}"
+ compileSdkVersion = COMPILE_SDK_VERSION.toInteger()
+}
+
+// Core libraries and executables.
+apply plugin: "c"
+def NEON
+model {
+ buildTypes {
+ debug
+ release
+ }
+ platforms {
+ arm {
+ architecture "arm"
+ }
+ arm64 {
+ architecture "arm64"
+ }
+ x86 {
+ architecture "x86"
+ }
+ x64 {
+ architecture "x86_64"
+ }
+ mips32r2
+ mips32r5
+ mips64r6
+ }
+ toolChains {
+ gcc(Gcc) {
+ target("mips32r2") {
+ cCompiler.args "-mips32r2"
+ }
+ target("mips32r5") {
+ cCompiler.args "-mips32r5"
+ }
+ target("mips64r6") {
+ cCompiler.args "-mips64r6"
+ }
+ }
+ }
+ binaries {
+ all {
+ if (toolChain in Gcc) {
+ cCompiler.args "-fPIC"
+ cCompiler.args "-Wall"
+ cCompiler.define "ANDROID"
+ cCompiler.define "HAVE_MALLOC_H"
+ }
+ // Optimizations.
+ if (buildType == buildTypes.release) {
+ if (toolChain in Gcc) {
+ cCompiler.args "-finline-functions"
+ cCompiler.args "-ffast-math"
+ cCompiler.args "-ffunction-sections"
+ cCompiler.args "-fdata-sections"
+ }
+ if (toolChain in Clang) {
+ cCompiler.args "-frename-registers -s"
+ }
+ }
+ // mips32 fails to build with clang from r14b
+ // https://bugs.chromium.org/p/webp/issues/detail?id=343
+ if (toolChain in Clang) {
+ if (getTargetPlatform() == "mips") {
+ cCompiler.args "-no-integrated-as"
+ }
+ }
+ // Check for NEON usage.
+ if (getTargetPlatform() == "arm") {
+ NEON = "c.neon"
+ cCompiler.define "HAVE_CPU_FEATURES_H"
+ } else {
+ NEON = "c"
+ }
+
+ cCompiler.args "-I" + file(".").absolutePath
+ }
+ // Link to pthread for shared libraries.
+ withType(SharedLibraryBinarySpec) {
+ if (toolChain in Gcc) {
+ cCompiler.define "HAVE_PTHREAD"
+ cCompiler.define "WEBP_USE_THREAD"
+ linker.args "-pthread"
+ }
+ }
+ }
+ components {
+ webp(NativeLibrarySpec) {
+ sources {
+ c {
+ source {
+ srcDir "sharpyuv"
+ include "sharpyuv.c"
+ include "sharpyuv_cpu.c"
+ include "sharpyuv_csp.c"
+ include "sharpyuv_dsp.c"
+ include "sharpyuv_gamma.c"
+ include "sharpyuv_neon.c"
+ include "sharpyuv_sse2.c"
+ srcDir "src/dec"
+ include "alpha_dec.c"
+ include "buffer_dec.c"
+ include "frame_dec.c"
+ include "idec_dec.c"
+ include "io_dec.c"
+ include "quant_dec.c"
+ include "tree_dec.c"
+ include "vp8_dec.c"
+ include "vp8l_dec.c"
+ include "webp_dec.c"
+ srcDir "src/dsp"
+ include "alpha_processing.c"
+ include "alpha_processing_mips_dsp_r2.c"
+ include "alpha_processing_neon.$NEON"
+ include "alpha_processing_sse2.c"
+ include "alpha_processing_sse41.c"
+ include "cpu.c"
+ include "dec.c"
+ include "dec_clip_tables.c"
+ include "dec_mips32.c"
+ include "dec_mips_dsp_r2.c"
+ include "dec_msa.c"
+ include "dec_neon.$NEON"
+ include "dec_sse2.c"
+ include "dec_sse41.c"
+ include "filters.c"
+ include "filters_mips_dsp_r2.c"
+ include "filters_msa.c"
+ include "filters_neon.$NEON"
+ include "filters_sse2.c"
+ include "lossless.c"
+ include "lossless_mips_dsp_r2.c"
+ include "lossless_msa.c"
+ include "lossless_neon.$NEON"
+ include "lossless_sse2.c"
+ include "lossless_sse41.c"
+ include "rescaler.c"
+ include "rescaler_mips32.c"
+ include "rescaler_mips_dsp_r2.c"
+ include "rescaler_msa.c"
+ include "rescaler_neon.$NEON"
+ include "rescaler_sse2.c"
+ include "upsampling.c"
+ include "upsampling_mips_dsp_r2.c"
+ include "upsampling_msa.c"
+ include "upsampling_neon.$NEON"
+ include "upsampling_sse2.c"
+ include "upsampling_sse41.c"
+ include "yuv.c"
+ include "yuv_mips32.c"
+ include "yuv_mips_dsp_r2.c"
+ include "yuv_neon.$NEON"
+ include "yuv_sse2.c"
+ include "yuv_sse41.c"
+ srcDir "src/utils"
+ include "bit_reader_utils.c"
+ include "color_cache_utils.c"
+ include "filters_utils.c"
+ include "huffman_utils.c"
+ include "quant_levels_dec_utils.c"
+ include "random_utils.c"
+ include "rescaler_utils.c"
+ include "thread_utils.c"
+ include "utils.c"
+ srcDir "src/dsp"
+ include "cost.c"
+ include "cost_mips32.c"
+ include "cost_mips_dsp_r2.c"
+ include "cost_neon.$NEON"
+ include "cost_sse2.c"
+ include "enc.c"
+ include "enc_mips32.c"
+ include "enc_mips_dsp_r2.c"
+ include "enc_msa.c"
+ include "enc_neon.$NEON"
+ include "enc_sse2.c"
+ include "enc_sse41.c"
+ include "lossless_enc.c"
+ include "lossless_enc_mips32.c"
+ include "lossless_enc_mips_dsp_r2.c"
+ include "lossless_enc_msa.c"
+ include "lossless_enc_neon.$NEON"
+ include "lossless_enc_sse2.c"
+ include "lossless_enc_sse41.c"
+ include "ssim.c"
+ include "ssim_sse2.c"
+ srcDir "src/enc"
+ include "alpha_enc.c"
+ include "analysis_enc.c"
+ include "backward_references_cost_enc.c"
+ include "backward_references_enc.c"
+ include "config_enc.c"
+ include "cost_enc.c"
+ include "filter_enc.c"
+ include "frame_enc.c"
+ include "histogram_enc.c"
+ include "iterator_enc.c"
+ include "near_lossless_enc.c"
+ include "picture_enc.c"
+ include "picture_csp_enc.c"
+ include "picture_psnr_enc.c"
+ include "picture_rescale_enc.c"
+ include "picture_tools_enc.c"
+ include "predictor_enc.c"
+ include "quant_enc.c"
+ include "syntax_enc.c"
+ include "token_enc.c"
+ include "tree_enc.c"
+ include "vp8l_enc.c"
+ include "webp_enc.c"
+ srcDir "src/utils"
+ include "bit_writer_utils.c"
+ include "huffman_encode_utils.c"
+ include "quant_levels_utils.c"
+ }
+ exportedHeaders {
+ srcDir "src"
+ }
+ }
+ }
+ }
+
+ webpdemux(NativeLibrarySpec) {
+ sources {
+ c {
+ source {
+ srcDir "src/demux"
+ include "anim_decode.c"
+ include "demux.c"
+ }
+ }
+ }
+ }
+
+ webpmux(NativeLibrarySpec) {
+ sources {
+ c {
+ source {
+ srcDir "src/mux/"
+ include "anim_encode.c"
+ include "muxedit.c"
+ include "muxinternal.c"
+ include "muxread.c"
+ }
+ }
+ }
+ }
+
+ // Executables from examples.
+ example_util(NativeLibrarySpec) {
+ binaries {
+ all {
+ lib library: "webp", linkage: "static"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "example_util.c"
+ }
+ }
+ }
+ }
+
+ imageio_util(NativeLibrarySpec) {
+ binaries {
+ all {
+ lib library: "webp", linkage: "static"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./imageio"
+ include "imageio_util.c"
+ }
+ }
+ }
+ }
+
+ imagedec(NativeLibrarySpec) {
+ binaries {
+ all {
+ lib library: "webpdemux", linkage: "static"
+ lib library: "webp", linkage: "static"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./imageio"
+ include "image_dec.c"
+ include "jpegdec.c"
+ include "metadata.c"
+ include "pngdec.c"
+ include "pnmdec.c"
+ include "tiffdec.c"
+ include "webpdec.c"
+ }
+ }
+ }
+ }
+
+ imageenc(NativeLibrarySpec) {
+ binaries {
+ all {
+ lib library: "webp", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./imageio"
+ include "image_enc.c"
+ }
+ }
+ }
+ }
+
+ cwebp(NativeExecutableSpec) {
+ binaries {
+ all {
+ lib library: "example_util", linkage: "static"
+ lib library: "imagedec", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ lib library: "webpdemux", linkage: "static"
+ lib library: "webp", linkage: "static"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "cwebp.c"
+ }
+ }
+ }
+ }
+
+ dwebp(NativeExecutableSpec) {
+ binaries {
+ all {
+ lib library: "example_util", linkage: "static"
+ lib library: "imagedec", linkage: "static"
+ lib library: "imageenc", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ lib library: "webpdemux", linkage: "static"
+ lib library: "webp"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "dwebp.c"
+ }
+ }
+ }
+ }
+
+ webpmux_example(NativeExecutableSpec) {
+ binaries {
+ all {
+ lib library: "example_util", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ lib library: "webpmux", linkage: "static"
+ lib library: "webp"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "webpmux.c"
+ }
+ }
+ }
+ }
+
+ img2webp_example(NativeExecutableSpec) {
+ binaries {
+ all {
+ lib library: "example_util", linkage: "static"
+ lib library: "imagedec", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ lib library: "webpmux", linkage: "static"
+ lib library: "webpdemux", linkage: "static"
+ lib library: "webp"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "img2webp.c"
+ }
+ }
+ }
+ }
+
+ webpinfo_example(NativeExecutableSpec) {
+ binaries {
+ all {
+ lib library: "example_util", linkage: "static"
+ lib library: "imageio_util", linkage: "static"
+ lib library: "webp"
+ }
+ }
+ sources {
+ c {
+ source {
+ srcDir "./examples"
+ include "webpinfo.c"
+ }
+ }
+ }
+ }
+ }
+ tasks {
+ // Task to test all possible configurations.
+ buildAllExecutables(Task) {
+ dependsOn $.binaries.findAll { it.buildable }
+ }
+ }
+}
diff --git a/cmake/WebPConfig.cmake.in b/cmake/WebPConfig.cmake.in
new file mode 100644
index 0000000..f334739
--- /dev/null
+++ b/cmake/WebPConfig.cmake.in
@@ -0,0 +1,16 @@
+set(WebP_VERSION @PROJECT_VERSION@)
+set(WEBP_VERSION ${WebP_VERSION})
+
+@PACKAGE_INIT@
+
+if(@WEBP_USE_THREAD@)
+ include(CMakeFindDependencyMacro)
+ find_dependency(Threads REQUIRED)
+endif()
+
+include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
+set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
+set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
+set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
diff --git a/cmake/config.h.in b/cmake/config.h.in
new file mode 100644
index 0000000..3770935
--- /dev/null
+++ b/cmake/config.h.in
@@ -0,0 +1,149 @@
+/* Adapted from the autotools src/webp/config.h.in. */
+
+/* Define if building universal (internal helper macro) */
+/* TODO: handle properly in CMake */
+#cmakedefine AC_APPLE_UNIVERSAL_BUILD 1
+
+/* Set to 1 if __builtin_bswap16 is available */
+#cmakedefine HAVE_BUILTIN_BSWAP16 1
+
+/* Set to 1 if __builtin_bswap32 is available */
+#cmakedefine HAVE_BUILTIN_BSWAP32 1
+
+/* Set to 1 if __builtin_bswap64 is available */
+#cmakedefine HAVE_BUILTIN_BSWAP64 1
+
+/* Define to 1 if you have the <cpu-features.h> header file. */
+#cmakedefine HAVE_CPU_FEATURES_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <GLUT/glut.h> header file. */
+#cmakedefine HAVE_GLUT_GLUT_H 1
+
+/* Define to 1 if you have the <GL/glut.h> header file. */
+#cmakedefine HAVE_GL_GLUT_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <OpenGL/glut.h> header file. */
+#cmakedefine HAVE_OPENGL_GLUT_H 1
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
+
+/* Define to 1 if you have the <shlwapi.h> header file. */
+#cmakedefine HAVE_SHLWAPI_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <wincodec.h> header file. */
+#cmakedefine HAVE_WINCODEC_H 1
+
+/* Define to 1 if you have the <windows.h> header file. */
+#cmakedefine HAVE_WINDOWS_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+/* TODO: handle properly in CMake */
+#cmakedefine LT_OBJDIR "@LT_OBJDIR@"
+
+/* Name of package */
+#cmakedefine PACKAGE "@PROJECT_NAME@"
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@"
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@"
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@"
+
+/* Define to the home page for this package. */
+#cmakedefine PACKAGE_URL "@PACKAGE_URL@"
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS 1
+
+/* Version number of package */
+#cmakedefine VERSION "@VERSION@"
+
+/* Set to 1 if GIF library is installed */
+#cmakedefine WEBP_HAVE_GIF 1
+
+/* Set to 1 if OpenGL is supported */
+#cmakedefine WEBP_HAVE_GL 1
+
+/* Set to 1 if JPEG library is installed */
+#cmakedefine WEBP_HAVE_JPEG 1
+
+/* Set to 1 if NEON is supported */
+#cmakedefine WEBP_HAVE_NEON
+
+/* Set to 1 if runtime detection of NEON is enabled */
+/* TODO: handle properly in CMake */
+#cmakedefine WEBP_HAVE_NEON_RTCD
+
+/* Set to 1 if PNG library is installed */
+#cmakedefine WEBP_HAVE_PNG 1
+
+/* Set to 1 if SDL library is installed */
+#cmakedefine WEBP_HAVE_SDL 1
+
+/* Set to 1 if SSE2 is supported */
+#cmakedefine WEBP_HAVE_SSE2 1
+
+/* Set to 1 if SSE4.1 is supported */
+#cmakedefine WEBP_HAVE_SSE41 1
+
+/* Set to 1 if TIFF library is installed */
+#cmakedefine WEBP_HAVE_TIFF 1
+
+/* Enable near lossless encoding */
+#cmakedefine WEBP_NEAR_LOSSLESS 1
+
+/* Undefine this to disable thread support. */
+#cmakedefine WEBP_USE_THREAD 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/cmake/cpu.cmake b/cmake/cpu.cmake
new file mode 100644
index 0000000..7513ca8
--- /dev/null
+++ b/cmake/cpu.cmake
@@ -0,0 +1,159 @@
+# Copyright (c) 2021 Google LLC.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE 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.
+
+# Check for SIMD extensions.
+include(CMakePushCheckState)
+
+function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
+ if(NOT ENABLE_SIMD)
+ message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.")
+ set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
+ return()
+ endif()
+ unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
+ check_c_source_compiles(
+ "
+ #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
+ int main(void) {
+ #if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
+ this is not valid code
+ #endif
+ return 0;
+ }
+ "
+ WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
+ cmake_pop_check_state()
+ if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
+ set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
+ else()
+ set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
+ endif()
+endfunction()
+
+# those are included in the names of WEBP_USE_* in c++ code.
+set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
+set(WEBP_SIMD_FILE_EXTENSIONS
+ "_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
+if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ # With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2
+ # or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4
+ # flag, but an AVX one. Using that with SSE4 code risks generating illegal
+ # instructions when used on machines with SSE4 only. The flags are left for
+ # older (untested) versions to avoid any potential compatibility issues.
+ if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:")
+ set(SIMD_ENABLE_FLAGS)
+ else()
+ set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;")
+ endif()
+ set(SIMD_DISABLE_FLAGS)
+else()
+ set(SIMD_ENABLE_FLAGS "-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
+ set(SIMD_DISABLE_FLAGS "-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
+endif()
+
+set(WEBP_SIMD_FILES_TO_INCLUDE)
+set(WEBP_SIMD_FLAGS_TO_INCLUDE)
+
+if(${ANDROID})
+ if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
+ # This is because Android studio uses the configuration "-march=armv7-a
+ # -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
+ # optimizations but should (as this configuration does not exist anymore).
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
+ endif()
+endif()
+
+list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
+math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
+
+foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
+ # With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source
+ # will fail to compile.
+ if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2)
+ break()
+ endif()
+
+ list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
+
+ # First try with no extra flag added as the compiler might have default flags
+ # (especially on Android).
+ unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_FLAGS)
+ webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
+ if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
+ list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
+ if(EMSCRIPTEN)
+ set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}")
+ endif()
+ set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
+ webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
+ else()
+ if(MSVC AND SIMD_ENABLE_FLAGS)
+ # The detection for SSE2/SSE4 support under MSVC is based on the compiler
+ # version so e.g., clang-cl will require flags to enable the assembly.
+ list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
+ else()
+ set(SIMD_COMPILE_FLAG " ")
+ endif()
+ endif()
+ # Check which files we should include or not.
+ list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
+ file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
+ "src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
+ if(WEBP_HAVE_${WEBP_SIMD_FLAG})
+ # Memorize the file and flags.
+ foreach(FILE ${SIMD_FILES})
+ list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
+ list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG})
+ endforeach()
+ else()
+ # Remove the file from the list.
+ foreach(FILE ${SIMD_FILES})
+ list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
+ endforeach()
+ # Explicitly disable SIMD.
+ if(SIMD_DISABLE_FLAGS)
+ list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
+ include(CheckCCompilerFlag)
+ if(SIMD_COMPILE_FLAG)
+ # Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal
+ # variable at parent scope while check_cxx_source_compiles() continues
+ # to set an internal cache variable, so we unset both to avoid the
+ # failure / success state persisting between checks. See
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21207.
+ unset(HAS_COMPILE_FLAG)
+ unset(HAS_COMPILE_FLAG CACHE)
+ check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
+ if(HAS_COMPILE_FLAG)
+ # Do one more check for Clang to circumvent CMake issue 13194.
+ if(COMMAND check_compiler_flag_common_patterns)
+ # Only in CMake 3.0 and above.
+ check_compiler_flag_common_patterns(COMMON_PATTERNS)
+ else()
+ set(COMMON_PATTERNS)
+ endif()
+ set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
+ check_c_source_compiles(
+ "int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX
+ "warning: argument unused during compilation:" ${COMMON_PATTERNS})
+ if(NOT FLAG_${SIMD_COMPILE_FLAG})
+ unset(HAS_COMPILE_FLAG)
+ unset(HAS_COMPILE_FLAG CACHE)
+ endif()
+ endif()
+ if(HAS_COMPILE_FLAG)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
+ endif()
+ endif()
+ endif()
+ endif()
+ cmake_pop_check_state()
+endforeach()
diff --git a/cmake/deps.cmake b/cmake/deps.cmake
new file mode 100644
index 0000000..48c821e
--- /dev/null
+++ b/cmake/deps.cmake
@@ -0,0 +1,190 @@
+# Copyright (c) 2021 Google LLC.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE 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 the config.h to compile with specific intrinsics / libs.
+
+# Check for compiler options.
+include(CheckCSourceCompiles)
+check_c_source_compiles(
+ "
+ int main(void) {
+ (void)__builtin_bswap16(0);
+ return 0;
+ }
+ "
+ HAVE_BUILTIN_BSWAP16)
+check_c_source_compiles(
+ "
+ int main(void) {
+ (void)__builtin_bswap32(0);
+ return 0;
+ }
+ "
+ HAVE_BUILTIN_BSWAP32)
+check_c_source_compiles(
+ "
+ int main(void) {
+ (void)__builtin_bswap64(0);
+ return 0;
+ }
+ "
+ HAVE_BUILTIN_BSWAP64)
+
+# Check for libraries.
+if(WEBP_USE_THREAD)
+ find_package(Threads)
+ if(Threads_FOUND)
+ # work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
+ if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
+ endif()
+ check_c_source_compiles(
+ "
+ #include <pthread.h>
+ int main (void) {
+ int attr = PTHREAD_PRIO_INHERIT;
+ return attr;
+ }
+ "
+ FLAG_HAVE_PTHREAD_PRIO_INHERIT)
+ set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
+ list(APPEND WEBP_DEP_LIBRARIES Threads::Threads)
+ endif()
+ set(WEBP_USE_THREAD ${Threads_FOUND})
+endif()
+
+# TODO: this seems unused, check with autotools.
+set(LT_OBJDIR ".libs/")
+
+# Only useful for vwebp, so useless for now.
+find_package(OpenGL)
+set(WEBP_HAVE_GL ${OPENGL_FOUND})
+
+# Check if we need to link to the C math library. We do not look for it as it is
+# not found when cross-compiling, while it is here.
+check_c_source_compiles(
+ "
+ #include <math.h>
+ int main(int argc, char** argv) {
+ return (int)pow(argc, 2.5);
+ }
+ "
+ HAVE_MATH_LIBRARY)
+if(NOT HAVE_MATH_LIBRARY)
+ message(STATUS "Adding -lm flag.")
+ list(APPEND SHARPYUV_DEP_LIBRARIES m)
+ list(APPEND WEBP_DEP_LIBRARIES m)
+endif()
+
+# Find the standard image libraries.
+set(WEBP_DEP_IMG_LIBRARIES)
+set(WEBP_DEP_IMG_INCLUDE_DIRS)
+foreach(I_LIB PNG JPEG TIFF)
+ # Disable tiff when compiling in static mode as it is failing on Ubuntu.
+ if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF")
+ message("TIFF is disabled when statically linking.")
+ continue()
+ endif()
+ find_package(${I_LIB})
+ set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
+ if(${I_LIB}_FOUND)
+ list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
+ list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
+ ${${I_LIB}_INCLUDE_DIRS})
+ endif()
+endforeach()
+if(WEBP_DEP_IMG_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
+endif()
+
+# GIF detection, gifdec isn't part of the imageio lib.
+include(CMakePushCheckState)
+set(WEBP_DEP_GIF_LIBRARIES)
+set(WEBP_DEP_GIF_INCLUDE_DIRS)
+find_package(GIF)
+set(WEBP_HAVE_GIF ${GIF_FOUND})
+if(GIF_FOUND)
+ # GIF find_package only locates the header and library, it doesn't fail
+ # compile tests when detecting the version, but falls back to 3 (as of at
+ # least cmake 3.7.2). Make sure the library links to avoid incorrect detection
+ # when cross compiling.
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
+ set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
+ check_c_source_compiles(
+ "
+ #include <gif_lib.h>
+ int main(void) {
+ (void)DGifOpenFileHandle;
+ return 0;
+ }
+ "
+ GIF_COMPILES)
+ cmake_pop_check_state()
+ if(GIF_COMPILES)
+ list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
+ list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
+ else()
+ unset(GIF_FOUND)
+ endif()
+endif()
+
+# Check for specific headers.
+include(CheckIncludeFiles)
+check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
+check_include_files(dlfcn.h HAVE_DLFCN_H)
+check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
+check_include_files(GL/glut.h HAVE_GL_GLUT_H)
+check_include_files(inttypes.h HAVE_INTTYPES_H)
+check_include_files(memory.h HAVE_MEMORY_H)
+check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
+check_include_files(shlwapi.h HAVE_SHLWAPI_H)
+check_include_files(stdint.h HAVE_STDINT_H)
+check_include_files(stdlib.h HAVE_STDLIB_H)
+check_include_files(strings.h HAVE_STRINGS_H)
+check_include_files(string.h HAVE_STRING_H)
+check_include_files(sys/stat.h HAVE_SYS_STAT_H)
+check_include_files(sys/types.h HAVE_SYS_TYPES_H)
+check_include_files(unistd.h HAVE_UNISTD_H)
+check_include_files(wincodec.h HAVE_WINCODEC_H)
+check_include_files(windows.h HAVE_WINDOWS_H)
+
+# Windows specifics
+if(HAVE_WINCODEC_H)
+ list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
+endif()
+
+# Check for SIMD extensions.
+include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
+
+# Define extra info.
+set(PACKAGE ${PROJECT_NAME})
+set(PACKAGE_NAME ${PROJECT_NAME})
+
+# Read from configure.ac.
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
+string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]" CONFIGURE_AC_PACKAGE_INFO
+ ${CONFIGURE_AC})
+function(strip_bracket VAR)
+ string(LENGTH ${${VAR}} TMP_LEN)
+ math(EXPR TMP_LEN ${TMP_LEN}-2)
+ string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
+ set(${VAR} ${TMP_SUB} PARENT_SCOPE)
+endfunction()
+
+list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
+strip_bracket(PACKAGE_VERSION)
+list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
+strip_bracket(PACKAGE_BUGREPORT)
+list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
+strip_bracket(PACKAGE_URL)
+
+# Build more info.
+set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+set(PACKAGE_TARNAME ${PACKAGE_NAME})
+set(VERSION ${PACKAGE_VERSION})
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..ccba2ee
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,4 @@
+# This file is used by git cl to get repository specific information.
+GERRIT_HOST: True
+CODE_REVIEW_SERVER: chromium-review.googlesource.com
+GERRIT_SQUASH_UPLOADS: False
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..de5dfe7
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,803 @@
+AC_INIT([libwebp], [1.3.0],
+ [https://bugs.chromium.org/p/webp],,
+ [https://developers.google.com/speed/webp])
+AC_CANONICAL_HOST
+AC_PREREQ([2.60])
+AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
+
+dnl === automake >= 1.12 requires this for 'unusual archivers' support.
+dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+
+dnl === AC_PROG_LIBTOOL is deprecated.
+m4_ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL])
+AC_PROG_SED
+AM_PROG_CC_C_O
+
+dnl === Enable less verbose output when building.
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+dnl == test endianness
+AC_C_BIGENDIAN
+
+dnl === SET_IF_UNSET(shell_var, value)
+dnl === Set the shell variable 'shell_var' to 'value' if it is unset.
+AC_DEFUN([SET_IF_UNSET], [test "${$1+set}" = "set" || $1=$2])
+
+AC_ARG_ENABLE([everything],
+ AS_HELP_STRING([--enable-everything],
+ [Enable all optional targets. These can still be
+ disabled with --disable-target]),
+ [SET_IF_UNSET([enable_libsharpyuv], [$enableval])
+ SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
+ SET_IF_UNSET([enable_libwebpdemux], [$enableval])
+ SET_IF_UNSET([enable_libwebpextras], [$enableval])
+ SET_IF_UNSET([enable_libwebpmux], [$enableval])])
+
+dnl === Check whether libwebpmux should be built
+AC_MSG_CHECKING(whether libwebpmux is to be built)
+AC_ARG_ENABLE([libwebpmux],
+ AS_HELP_STRING([--disable-libwebpmux],
+ [Disable libwebpmux @<:@default=no@:>@]),
+ [], [enable_libwebpmux=yes])
+AC_MSG_RESULT(${enable_libwebpmux-no})
+AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
+
+dnl === Check whether libwebpdemux should be built
+AC_MSG_CHECKING(whether libwebpdemux is to be built)
+AC_ARG_ENABLE([libwebpdemux],
+ AS_HELP_STRING([--disable-libwebpdemux],
+ [Disable libwebpdemux @<:@default=no@:>@]),
+ [], [enable_libwebpdemux=yes])
+AC_MSG_RESULT(${enable_libwebpdemux-no})
+AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
+
+dnl === Check whether decoder library should be built.
+AC_MSG_CHECKING(whether decoder library is to be built)
+AC_ARG_ENABLE([libwebpdecoder],
+ AS_HELP_STRING([--enable-libwebpdecoder],
+ [Build libwebpdecoder @<:@default=no@:>@]))
+AC_MSG_RESULT(${enable_libwebpdecoder-no})
+AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
+
+dnl === Check whether libwebpextras should be built
+AC_MSG_CHECKING(whether libwebpextras is to be built)
+AC_ARG_ENABLE([libwebpextras],
+ AS_HELP_STRING([--enable-libwebpextras],
+ [Build libwebpextras @<:@default=no@:>@]))
+AC_MSG_RESULT(${enable_libwebpextras-no})
+AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
+
+dnl === If --enable-asserts is not defined, define NDEBUG
+
+AC_MSG_CHECKING(whether asserts are enabled)
+AC_ARG_ENABLE([asserts],
+ AS_HELP_STRING([--enable-asserts],
+ [Enable assert checks]))
+if test "x${enable_asserts-no}" = "xno"; then
+ AM_CPPFLAGS="${AM_CPPFLAGS} -DNDEBUG"
+fi
+AC_MSG_RESULT(${enable_asserts-no})
+AC_SUBST([AM_CPPFLAGS])
+
+AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=DIR],
+ [Path to the pkgconfig directory @<:@LIBDIR/pkgconfig@:>@]),
+ [pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
+AC_SUBST([pkgconfigdir])
+
+dnl === TEST_AND_ADD_CFLAGS(var, flag)
+dnl === Checks whether $CC supports 'flag' and adds it to 'var'
+dnl === on success.
+AC_DEFUN([TEST_AND_ADD_CFLAGS],
+ [SAVED_CFLAGS="$CFLAGS"
+ CFLAGS="-Werror $2"
+ AC_MSG_CHECKING([whether $CC supports $2])
+ dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])],
+ [AC_MSG_RESULT([yes])]
+ dnl Simply append the variable avoiding a
+ dnl compatibility ifdef for AS_VAR_APPEND as this
+ dnl variable shouldn't grow all that large.
+ [$1="${$1} $2"],
+ [AC_MSG_RESULT([no])])
+ CFLAGS="$SAVED_CFLAGS"])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-nonliteral])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code-aggressive])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wvla])
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62040
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61622
+AS_IF([test "$GCC" = "yes" ], [
+ gcc_version=`$CC -dumpversion`
+ gcc_wht_bug=""
+ case "$host_cpu" in
+ aarch64|arm64)
+ case "$gcc_version" in
+ 4.9|4.9.0|4.9.1) gcc_wht_bug=yes ;;
+ esac
+ esac
+ AS_IF([test "$gcc_wht_bug" = "yes"], [
+ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-frename-registers])])])
+# Use -flax-vector-conversions, if available, when building intrinsics with
+# older versions of gcc. The flag appeared in 4.3.x, but if backported, and
+# -fno-lax-vector-conversions is set, errors may occur with the intrinsics
+# files along with the older system includes, e.g., emmintrin.h.
+# Originally observed with cc (GCC) 4.2.1 20070831 patched [FreeBSD] (9.3).
+# https://bugs.chromium.org/p/webp/issues/detail?id=274
+AS_IF([test "$GCC" = "yes" ], [
+ case "$host_cpu" in
+ amd64|i?86|x86_64)
+ AC_COMPILE_IFELSE(
+ dnl only check for -flax-vector-conversions with older gcc, skip
+ dnl clang as it reports itself as 4.2.1, but the flag isn't needed.
+ [AC_LANG_SOURCE([#if !defined(__clang__) && defined(__GNUC__) && \
+ ((__GNUC__ << 8) | __GNUC_MINOR__) < 0x403
+ #error old gcc
+ #endif
+ int main(void) { return 0; }
+ ])],,
+ [TEST_AND_ADD_CFLAGS([INTRINSICS_CFLAGS],
+ [-flax-vector-conversions])])
+ ;;
+ esac])
+AC_SUBST([AM_CFLAGS])
+
+dnl === Check for machine specific flags
+AC_ARG_ENABLE([sse4.1],
+ AS_HELP_STRING([--disable-sse4.1],
+ [Disable detection of SSE4.1 support
+ @<:@default=auto@:>@]))
+
+AS_IF([test "x$enable_sse4_1" != "xno" -a "x$enable_sse2" != "xno"], [
+ SSE41_FLAGS="$INTRINSICS_CFLAGS $SSE41_FLAGS"
+ TEST_AND_ADD_CFLAGS([SSE41_FLAGS], [-msse4.1])
+ AS_IF([test -n "$SSE41_FLAGS"], [
+ SAVED_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $SSE41_FLAGS"
+ AC_CHECK_HEADER([smmintrin.h],
+ [AC_DEFINE(WEBP_HAVE_SSE41, [1],
+ [Set to 1 if SSE4.1 is supported])],
+ [SSE41_FLAGS=""])
+ CFLAGS=$SAVED_CFLAGS])
+ AC_SUBST([SSE41_FLAGS])])
+
+AC_ARG_ENABLE([sse2],
+ AS_HELP_STRING([--disable-sse2],
+ [Disable detection of SSE2 support
+ @<:@default=auto@:>@]))
+
+AS_IF([test "x$enable_sse2" != "xno"], [
+ SSE2_FLAGS="$INTRINSICS_CFLAGS $SSE2_FLAGS"
+ TEST_AND_ADD_CFLAGS([SSE2_FLAGS], [-msse2])
+ AS_IF([test -n "$SSE2_FLAGS"], [
+ SAVED_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $SSE2_FLAGS"
+ AC_CHECK_HEADER([emmintrin.h],
+ [AC_DEFINE(WEBP_HAVE_SSE2, [1],
+ [Set to 1 if SSE2 is supported])],
+ [SSE2_FLAGS=""])
+ CFLAGS=$SAVED_CFLAGS])
+ AC_SUBST([SSE2_FLAGS])])
+
+AC_ARG_ENABLE([neon],
+ AS_HELP_STRING([--disable-neon],
+ [Disable detection of NEON support
+ @<:@default=auto@:>@]))
+
+AC_ARG_ENABLE([neon_rtcd],
+ AS_HELP_STRING([--disable-neon-rtcd],
+ [Disable runtime detection of NEON support via
+ /proc/cpuinfo on Linux hosts
+ @<:@default=auto@:>@]))
+# For ARM(7) hosts:
+# Both NEON flags unset and NEON support detected = build all modules with NEON
+# NEON detected with the use of -mfpu=neon = build only NEON modules with NEON
+AS_IF([test "x$enable_neon" != "xno"], [
+ case "$host_cpu" in
+ arm|armv7*)
+ # Test for NEON support without flags before falling back to -mfpu=neon
+ for flag in '' '-mfpu=neon'; do
+ LOCAL_NEON_FLAGS="$INTRINSICS_CFLAGS $NEON_FLAGS"
+ TEST_AND_ADD_CFLAGS([LOCAL_NEON_FLAGS], [$flag])
+ SAVED_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $LOCAL_NEON_FLAGS"
+
+ dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ #include <arm_neon.h>
+ int main(void) {
+ int8x8_t v = vdup_n_s8(0);
+ (void)v;
+ return 0;
+ }])],
+ [NEON_FLAGS="$(echo $LOCAL_NEON_FLAGS | $SED 's/^ *//')"
+ AS_IF([test -n "$NEON_FLAGS"], [
+ AS_IF([test "${host_os%%-*}" = "linux" -o \
+ "x$enable_neon_rtcd" = "xno"], [
+ CFLAGS=$SAVED_CFLAGS
+ AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
+ break
+ ],[
+ AC_MSG_WARN(m4_normalize([NEON runtime cpu-detection is
+ unavailable for ${host_os%%-*}. Force
+ with CFLAGS=-mfpu=neon or
+ --disable-neon-rtcd.]))
+ enable_neon_rtcd=no
+ NEON_FLAGS=""
+ ])
+ ],[
+ CFLAGS=$SAVED_CFLAGS
+ AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
+ break
+ ])])
+ CFLAGS=$SAVED_CFLAGS
+ done
+
+ AS_IF([test -n "$NEON_FLAGS"], [
+ # If NEON is available and rtcd is disabled apply NEON_FLAGS globally.
+ AS_IF([test "x$enable_neon_rtcd" = "xno"], [
+ AM_CFLAGS="$AM_CFLAGS $NEON_FLAGS"
+ NEON_FLAGS=""],
+ [AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
+ [Set to 1 if runtime detection of NEON is enabled])])])
+
+ case "$host_os" in
+ *android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
+ esac
+ ;;
+ aarch64*|arm64*)
+ AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
+ ;;
+ esac
+ AC_SUBST([NEON_FLAGS])])
+
+dnl === CLEAR_LIBVARS([var_pfx])
+dnl === Clears <var_pfx>_{INCLUDES,LIBS}.
+AC_DEFUN([CLEAR_LIBVARS], [$1_INCLUDES=""; $1_LIBS=""])
+
+dnl === WITHLIB_OPTION([opt_pfx], [outvar_pfx])
+dnl === Defines --with-<opt_pfx>{include,lib}dir options which set
+dnl === the variables <outvar_pfx>_{INCLUDES,LIBS}.
+AC_DEFUN([WITHLIB_OPTION],
+ [AC_ARG_WITH([$1includedir],
+ AS_HELP_STRING([--with-$1includedir=DIR],
+ [use $2 includes from DIR]),
+ $2_INCLUDES="-I$withval")
+ AC_ARG_WITH([$1libdir],
+ AS_HELP_STRING([--with-$1libdir=DIR],
+ [use $2 libraries from DIR]),
+ [$2_LIBS="-L$withval"])])
+
+dnl === LIBCHECK_PROLOGUE([var_pfx])
+dnl === Caches the current values of CPPFLAGS/LIBS in SAVED_* then
+dnl === prepends the current values with <var_pfx>_{INCLUDES,LIBS}.
+AC_DEFUN([LIBCHECK_PROLOGUE],
+ [SAVED_CPPFLAGS=$CPPFLAGS
+ SAVED_LIBS=$LIBS
+ CPPFLAGS="$$1_INCLUDES $CPPFLAGS"
+ LIBS="$$1_LIBS $LIBS"])
+
+dnl === LIBCHECK_EPILOGUE([var_pfx])
+dnl === Restores the values of CPPFLAGS/LIBS from SAVED_* and exports
+dnl === <var_pfx>_{INCLUDES,LIBS} with AC_SUBST.
+AC_DEFUN([LIBCHECK_EPILOGUE],
+ [AC_SUBST($1_LIBS)
+ AC_SUBST($1_INCLUDES)
+ CPPFLAGS=$SAVED_CPPFLAGS
+ LIBS=$SAVED_LIBS])
+
+dnl === Check for gcc builtins
+
+dnl === CHECK_FOR_BUILTIN([builtin], [param], [define])
+dnl === links a C AC_LANG_PROGRAM, with <builtin>(<param>)
+dnl === AC_DEFINE'ing <define> if successful.
+AC_DEFUN([CHECK_FOR_BUILTIN],
+ [AC_LANG_PUSH([C])
+ AC_MSG_CHECKING([for $1])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [(void)$1($2)])],
+ [AC_MSG_RESULT([yes])
+ AC_DEFINE([$3], [1],
+ [Set to 1 if $1 is available])],
+ [AC_MSG_RESULT([no])]),
+ AC_LANG_POP])
+
+dnl AC_CHECK_FUNC doesn't work with builtin's.
+CHECK_FOR_BUILTIN([__builtin_bswap16], [1u << 15], [HAVE_BUILTIN_BSWAP16])
+CHECK_FOR_BUILTIN([__builtin_bswap32], [1u << 31], [HAVE_BUILTIN_BSWAP32])
+CHECK_FOR_BUILTIN([__builtin_bswap64], [1ull << 63], [HAVE_BUILTIN_BSWAP64])
+
+dnl === Check for pthread support
+AC_ARG_ENABLE([threading],
+ AS_HELP_STRING([--disable-threading],
+ [Disable detection of thread support]),,
+ [enable_threading=yes])
+if test "$enable_threading" = "yes"; then
+ AC_MSG_NOTICE([checking for threading support...])
+ AX_PTHREAD([AC_DEFINE([WEBP_USE_THREAD], [1],
+ [Undefine this to disable thread support.])
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ CC="$PTHREAD_CC"
+ ],
+ [AC_CHECK_FUNC([_beginthreadex],
+ [AC_DEFINE([WEBP_USE_THREAD], [1],
+ [Undefine this to disable thread
+ support.])],
+ [enable_threading=no])])
+fi
+AC_MSG_NOTICE([checking if threading is enabled... ${enable_threading-no}])
+
+dnl === check for OpenGL/GLUT support ===
+
+AC_ARG_ENABLE([gl], AS_HELP_STRING([--disable-gl],
+ [Disable detection of OpenGL support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_gl" != "xno"], [
+ CLEAR_LIBVARS([GL])
+ WITHLIB_OPTION([gl], [GL])
+
+ LIBCHECK_PROLOGUE([GL])
+
+ glut_cflags="none"
+ glut_ldflags="none"
+ case $host_os in
+ darwin*)
+ # Special case for OSX builds. Append these to give the user a chance to
+ # override with --with-gl*
+ glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL"
+ glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL"
+ # quiet deprecation warnings for glut
+ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wno-deprecated-declarations])
+ ;;
+ esac
+
+ GLUT_SAVED_CPPFLAGS="$CPPFLAGS"
+ SAVED_IFS="$IFS"
+ IFS="|"
+ for flag in $glut_cflags; do
+ # restore IFS immediately as the autoconf macros may need the default.
+ IFS="$SAVED_IFS"
+ unset ac_cv_header_GL_glut_h
+ unset ac_cv_header_OpenGL_glut_h
+
+ case $flag in
+ none) ;;
+ *) CPPFLAGS="$flag $CPPFLAGS";;
+ esac
+ AC_CHECK_HEADERS([GL/glut.h GLUT/glut.h OpenGL/glut.h],
+ [glut_headers=yes;
+ test "$flag" = "none" || GL_INCLUDES="$CPPFLAGS";
+ break])
+ CPPFLAGS="$GLUT_SAVED_CPPFLAGS"
+ test "$glut_headers" = "yes" && break
+ done
+ IFS="$SAVED_IFS"
+
+ if test "$glut_headers" = "yes"; then
+ AC_LANG_PUSH([C])
+ GLUT_SAVED_LDFLAGS="$LDFLAGS"
+ SAVED_IFS="$IFS"
+ IFS="|"
+ for flag in $glut_ldflags; do
+ # restore IFS immediately as the autoconf macros may need the default.
+ IFS="$SAVED_IFS"
+ unset ac_cv_search_glBegin
+
+ case $flag in
+ none) ;;
+ *) LDFLAGS="$flag $LDFLAGS";;
+ esac
+
+ # find libGL
+ GL_SAVED_LIBS="$LIBS"
+ AC_SEARCH_LIBS([glBegin], [GL OpenGL opengl32])
+ LIBS="$GL_SAVED_LIBS"
+
+ # A direct link to libGL may not be necessary on e.g., linux.
+ GLUT_SAVED_LIBS="$LIBS"
+ for lib in "" "-lglut" "-lglut $ac_cv_search_glBegin"; do
+ LIBS="$lib"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([
+ #ifdef __cplusplus
+ # define EXTERN_C extern "C"
+ #else
+ # define EXTERN_C
+ #endif
+ EXTERN_C char glOrtho();
+ EXTERN_C char glutMainLoop();
+ ],[
+ glOrtho();
+ glutMainLoop();
+ ])
+ ],
+ AC_DEFINE(WEBP_HAVE_GL, [1],
+ [Set to 1 if OpenGL is supported])
+ [glut_support=yes], []
+ )
+ if test "$glut_support" = "yes"; then
+ GL_LIBS="$LDFLAGS $lib"
+ break
+ fi
+ done
+ LIBS="$GLUT_SAVED_LIBS"
+ LDFLAGS="$GLUT_SAVED_LDFLAGS"
+ test "$glut_support" = "yes" && break
+ done
+ IFS="$SAVED_IFS"
+ AC_LANG_POP
+ fi
+
+ LIBCHECK_EPILOGUE([GL])
+
+ if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
+ build_vwebp=yes
+ else
+ AC_MSG_NOTICE(
+ m4_normalize([Not building vwebp.
+ OpenGL libraries and --enable-libwebpdemux are required.]))
+ fi
+])
+AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
+
+dnl === check for SDL support ===
+
+AC_ARG_ENABLE([sdl],
+ AS_HELP_STRING([--disable-sdl],
+ [Disable detection of SDL support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_sdl" != "xno"], [
+ CLEAR_LIBVARS([SDL])
+ AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
+ if test -n "$LIBSDL_CONFIG"; then
+ SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
+ SDL_LIBS="`$LIBSDL_CONFIG --libs`"
+ fi
+
+ WITHLIB_OPTION([sdl], [SDL])
+
+ sdl_header="no"
+ LIBCHECK_PROLOGUE([SDL])
+ AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
+ [AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
+ [AC_MSG_WARN(SDL library not available - no sdl.h)])])
+ if test x"$sdl_header" != "xno"; then
+ AC_LANG_PUSH(C)
+ SDL_SAVED_LIBS="$LIBS"
+ for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
+ LIBS="$SDL_SAVED_LIBS $lib"
+ # Perform a full link to ensure SDL_main is resolved if needed.
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE([
+ #include <$sdl_header>
+ int main(int argc, char** argv) {
+ SDL_Init(0);
+ return 0;
+ }])],
+ [SDL_LIBS="$LDFLAGS $LIBS"
+ SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_SDL"
+ AC_DEFINE(WEBP_HAVE_SDL, [1],
+ [Set to 1 if SDL library is installed])
+ sdl_support=yes]
+ )
+ if test x"$sdl_support" = "xyes"; then
+ break
+ fi
+ done
+ # LIBS is restored by LIBCHECK_EPILOGUE
+ AC_LANG_POP
+ if test x"$sdl_header" = "xSDL.h"; then
+ SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_JUST_SDL_H"
+ fi
+ fi
+ LIBCHECK_EPILOGUE([SDL])
+
+ if test x"$sdl_support" = "xyes"; then
+ build_vwebp_sdl=yes
+ else
+ AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
+ fi
+])
+
+AM_CONDITIONAL([BUILD_VWEBP_SDL], [test "$build_vwebp_sdl" = "yes"])
+
+dnl === check for PNG support ===
+
+AC_ARG_ENABLE([png], AS_HELP_STRING([--disable-png],
+ [Disable detection of PNG format support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_png" != "xno"], [
+ CLEAR_LIBVARS([PNG])
+ AC_PATH_PROGS([LIBPNG_CONFIG],
+ [libpng-config libpng16-config libpng15-config libpng14-config \
+ libpng12-config])
+ if test -n "$LIBPNG_CONFIG"; then
+ PNG_INCLUDES=`$LIBPNG_CONFIG --cflags`
+ PNG_LIBS="`$LIBPNG_CONFIG --ldflags`"
+ fi
+
+ WITHLIB_OPTION([png], [PNG])
+
+ LIBCHECK_PROLOGUE([PNG])
+ AC_CHECK_HEADER(png.h,
+ AC_SEARCH_LIBS(png_get_libpng_ver, [png],
+ [test "$ac_cv_search_png_get_libpng_ver" = "none required" \
+ || PNG_LIBS="$PNG_LIBS $ac_cv_search_png_get_libpng_ver"
+ PNG_INCLUDES="$PNG_INCLUDES -DWEBP_HAVE_PNG"
+ AC_DEFINE(WEBP_HAVE_PNG, [1],
+ [Set to 1 if PNG library is installed])
+ png_support=yes
+ ],
+ [AC_MSG_WARN(Optional png library not found)
+ PNG_LIBS=""
+ PNG_INCLUDES=""
+ ],
+ [$MATH_LIBS]),
+ [AC_MSG_WARN(png library not available - no png.h)
+ PNG_LIBS=""
+ PNG_INCLUDES=""
+ ],
+ )
+ LIBCHECK_EPILOGUE([PNG])
+])
+
+dnl === check for JPEG support ===
+
+AC_ARG_ENABLE([jpeg],
+ AS_HELP_STRING([--disable-jpeg],
+ [Disable detection of JPEG format support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_jpeg" != "xno"], [
+ CLEAR_LIBVARS([JPEG])
+ WITHLIB_OPTION([jpeg], [JPEG])
+
+ LIBCHECK_PROLOGUE([JPEG])
+ AC_CHECK_HEADER(jpeglib.h,
+ AC_CHECK_LIB(jpeg, jpeg_set_defaults,
+ [JPEG_LIBS="$JPEG_LIBS -ljpeg"
+ JPEG_INCLUDES="$JPEG_INCLUDES -DWEBP_HAVE_JPEG"
+ AC_DEFINE(WEBP_HAVE_JPEG, [1],
+ [Set to 1 if JPEG library is installed])
+ jpeg_support=yes
+ ],
+ AC_MSG_WARN(Optional jpeg library not found),
+ [$MATH_LIBS]),
+ AC_MSG_WARN(jpeg library not available - no jpeglib.h)
+ )
+ LIBCHECK_EPILOGUE([JPEG])
+])
+
+dnl === check for TIFF support ===
+
+AC_ARG_ENABLE([tiff],
+ AS_HELP_STRING([--disable-tiff],
+ [Disable detection of TIFF format support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_tiff" != "xno"], [
+ CLEAR_LIBVARS([TIFF])
+ WITHLIB_OPTION([tiff], [TIFF])
+
+ LIBCHECK_PROLOGUE([TIFF])
+ AC_CHECK_HEADER(tiffio.h,
+ AC_CHECK_LIB(tiff, TIFFGetVersion,
+ [TIFF_LIBS="$TIFF_LIBS -ltiff"
+ TIFF_INCLUDES="$TIFF_INCLUDES -DWEBP_HAVE_TIFF"
+ AC_DEFINE(WEBP_HAVE_TIFF, [1],
+ [Set to 1 if TIFF library is installed])
+ tiff_support=yes
+ ],
+ AC_MSG_WARN(Optional tiff library not found),
+ [$MATH_LIBS]),
+ AC_MSG_WARN(tiff library not available - no tiffio.h)
+ )
+ LIBCHECK_EPILOGUE([TIFF])
+])
+
+dnl === check for GIF support ===
+
+AC_ARG_ENABLE([gif], AS_HELP_STRING([--disable-gif],
+ [Disable detection of GIF format support
+ @<:@default=auto@:>@]))
+AS_IF([test "x$enable_gif" != "xno"], [
+ CLEAR_LIBVARS([GIF])
+ WITHLIB_OPTION([gif], [GIF])
+
+ LIBCHECK_PROLOGUE([GIF])
+ AC_CHECK_HEADER(gif_lib.h,
+ AC_CHECK_LIB([gif], [DGifOpenFileHandle],
+ [GIF_LIBS="$GIF_LIBS -lgif"
+ AC_DEFINE(WEBP_HAVE_GIF, [1],
+ [Set to 1 if GIF library is installed])
+ gif_support=yes
+ ],
+ AC_MSG_WARN(Optional gif library not found),
+ [$MATH_LIBS]),
+ AC_MSG_WARN(gif library not available - no gif_lib.h)
+ )
+ LIBCHECK_EPILOGUE([GIF])
+
+ if test "$gif_support" = "yes" -a \
+ "$enable_libwebpdemux" = "yes"; then
+ build_anim_diff=yes
+ else
+ AC_MSG_NOTICE(
+ [Not building anim_diff. libgif and --enable-libwebpdemux are required.])
+ fi
+
+ if test "$gif_support" = "yes" -a \
+ "$enable_libwebpmux" = "yes"; then
+ build_gif2webp=yes
+ else
+ AC_MSG_NOTICE(
+ [Not building gif2webp. libgif and --enable-libwebpmux are required.])
+ fi
+])
+AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
+AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
+
+if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
+ build_img2webp=yes
+else
+ AC_MSG_NOTICE(
+ m4_normalize([Not building img2webp.
+ --enable-libwebpdemux & --enable-libwebpmux are required.]))
+fi
+AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
+
+if test "$enable_libwebpmux" = "yes"; then
+ build_webpinfo=yes
+else
+ AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
+fi
+AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
+
+dnl === check for WIC support ===
+
+AC_ARG_ENABLE([wic],
+ AS_HELP_STRING([--disable-wic],
+ [Disable Windows Imaging Component (WIC) detection.
+ @<:@default=auto@:>@]),,
+ [enable_wic=yes])
+
+case $host_os in
+mingw*)
+if test "$enable_wic" = "yes"; then
+ AC_CHECK_HEADERS([wincodec.h shlwapi.h windows.h])
+ if test "$ac_cv_header_wincodec_h" = "yes"; then
+ AC_MSG_CHECKING(for Windows Imaging Component support)
+ SAVED_LIBS=$LIBS
+ LIBS="-lshlwapi -lole32 $LIBS"
+ # match include structure from [cd]webp.c
+ wic_headers="
+ #define INITGUID
+ #define CINTERFACE
+ #define COBJMACROS
+ #define _WIN32_IE 0x500
+
+ #include <shlwapi.h>
+ #include <windows.h>
+ #include <wincodec.h>
+ "
+ # test for functions from each lib and the GUID is created properly
+ wic_main="
+ int main(void) {
+ CLSID_WICImagingFactory;
+ CoInitialize(NULL);
+ SHCreateStreamOnFile(NULL, 0, NULL);
+ return 0;
+ }
+ "
+ AC_LANG_PUSH(C)
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE([
+ $wic_headers
+ $wic_main])],
+ [wic_support=yes],
+ [wic_support=no]
+ )
+ AC_LANG_POP
+
+ test "$wic_support" = "yes" || LIBS=$SAVED_LIBS
+ AC_MSG_RESULT(${wic_support-no})
+ fi
+fi
+esac
+
+dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP=1
+
+USE_SWAP_16BIT_CSP=""
+AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified)
+AC_ARG_ENABLE([swap-16bit-csp],
+ AS_HELP_STRING([--enable-swap-16bit-csp],
+ [Enable byte swap for 16 bit colorspaces]))
+if test "$enable_swap_16bit_csp" = "yes"; then
+ USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP=1"
+fi
+AC_MSG_RESULT(${enable_swap_16bit_csp-no})
+AC_SUBST(USE_SWAP_16BIT_CSP)
+
+dnl === If --disable-near-lossless is defined, add -DWEBP_NEAR_LOSSLESS=0
+
+AC_DEFINE(WEBP_NEAR_LOSSLESS, [1], [Enable near lossless encoding])
+AC_MSG_CHECKING(if --disable-near-lossless option is specified)
+AC_ARG_ENABLE([near_lossless],
+ AS_HELP_STRING([--disable-near-lossless],
+ [Disable near lossless encoding]),
+ [], [enable_near_lossless=yes])
+if test "$enable_near_lossless" = "no"; then
+ AC_DEFINE(WEBP_NEAR_LOSSLESS, [0], [Enable near lossless encoding])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+dnl =========================
+
+dnl Add an empty webp_libname_prefix variable for use in *.pc.in.
+AC_SUBST([webp_libname_prefix])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([src/webp/config.h])
+AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
+ examples/Makefile extras/Makefile imageio/Makefile \
+ sharpyuv/Makefile sharpyuv/libsharpyuv.pc \
+ src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
+ src/demux/Makefile src/mux/Makefile \
+ src/utils/Makefile \
+ src/libwebp.pc src/libwebpdecoder.pc \
+ src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
+
+
+AC_OUTPUT
+
+AC_MSG_NOTICE([
+WebP Configuration Summary
+--------------------------
+
+Shared libraries: ${enable_shared}
+Static libraries: ${enable_static}
+Threading support: ${enable_threading-no}
+libwebp: yes
+libwebpdecoder: ${enable_libwebpdecoder-no}
+libwebpdemux: ${enable_libwebpdemux-no}
+libwebpmux: ${enable_libwebpmux-no}
+libwebpextras: ${enable_libwebpextras-no}
+
+Tools:
+cwebp : ${enable_libwebpdemux-no}
+ Input format support
+ ====================
+ JPEG : ${jpeg_support-no}
+ PNG : ${png_support-no}
+ TIFF : ${tiff_support-no}
+ WIC : ${wic_support-no}
+dwebp : ${enable_libwebpdemux-no}
+ Output format support
+ =====================
+ PNG : ${png_support-no}
+ WIC : ${wic_support-no}
+GIF support : ${gif_support-no}
+anim_diff : ${build_anim_diff-no}
+gif2webp : ${build_gif2webp-no}
+img2webp : ${build_img2webp-no}
+webpmux : ${enable_libwebpmux-no}
+vwebp : ${build_vwebp-no}
+webpinfo : ${build_webpinfo-no}
+SDL support : ${sdl_support-no}
+vwebp_sdl : ${build_vwebp_sdl-no}
+])
diff --git a/doc/TODO b/doc/TODO
new file mode 100644
index 0000000..b0a9382
--- /dev/null
+++ b/doc/TODO
@@ -0,0 +1,13 @@
+<louquillio@google.com>, 20111004
+
+* Determine that normative RFC 2119 terms (MUST, SHOULD, MAY, etc.) are
+ truly intended in all cases where capitalized.
+
+* Several passages could be made clearer.
+
+ * Overall edit for scope. Portions are phrased as an introduction to
+ the 0.1.3 RIFF container additions, rather than a holistic guide to
+ WebP.
+
+ * To wit, suggest s/[spec|specification]/guide/g . "Spec" can imply a
+ standards track; in any case it's too formal for a work in progress.
diff --git a/doc/api.md b/doc/api.md
new file mode 100644
index 0000000..c613ed3
--- /dev/null
+++ b/doc/api.md
@@ -0,0 +1,385 @@
+# WebP APIs
+
+## Encoding API
+
+The main encoding functions are available in the header src/webp/encode.h
+
+The ready-to-use ones are:
+
+```c
+size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+size_t WebPEncodeRGBA(const uint8_t* rgba, int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+```
+
+They will convert raw RGB samples to a WebP data. The only control supplied is
+the quality factor.
+
+There are some variants for using the lossless format:
+
+```c
+size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height,
+ int stride, uint8_t** output);
+size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height,
+ int stride, uint8_t** output);
+size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height,
+ int stride, uint8_t** output);
+size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height,
+ int stride, uint8_t** output);
+```
+
+Of course in this case, no quality factor is needed since the compression occurs
+without loss of the input values, at the expense of larger output sizes.
+
+### Advanced encoding API
+
+A more advanced API is based on the WebPConfig and WebPPicture structures.
+
+WebPConfig contains the encoding settings and is not tied to a particular
+picture. WebPPicture contains input data, on which some WebPConfig will be used
+for compression. The encoding flow looks like:
+
+```c
+#include <webp/encode.h>
+
+// Setup a config, starting form a preset and tuning some additional
+// parameters
+WebPConfig config;
+if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) {
+ return 0; // version error
+}
+// ... additional tuning
+config.sns_strength = 90;
+config.filter_sharpness = 6;
+config_error = WebPValidateConfig(&config); // not mandatory, but useful
+
+// Setup the input data
+WebPPicture pic;
+if (!WebPPictureInit(&pic)) {
+ return 0; // version error
+}
+pic.width = width;
+pic.height = height;
+// allocated picture of dimension width x height
+if (!WebPPictureAlloc(&pic)) {
+ return 0; // memory error
+}
+// at this point, 'pic' has been initialized as a container,
+// and can receive the Y/U/V samples.
+// Alternatively, one could use ready-made import functions like
+// WebPPictureImportRGB(), which will take care of memory allocation.
+// In any case, past this point, one will have to call
+// WebPPictureFree(&pic) to reclaim memory.
+
+// Set up a byte-output write method. WebPMemoryWriter, for instance.
+WebPMemoryWriter wrt;
+WebPMemoryWriterInit(&wrt); // initialize 'wrt'
+
+pic.writer = MyFileWriter;
+pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work;
+
+// Compress!
+int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred!
+WebPPictureFree(&pic); // must be called independently of the 'ok' result.
+
+// output data should have been handled by the writer at that point.
+// -> compressed data is the memory buffer described by wrt.mem / wrt.size
+
+// deallocate the memory used by compressed data
+WebPMemoryWriterClear(&wrt);
+```
+
+## Decoding API
+
+This is mainly just one function to call:
+
+```c
+#include "webp/decode.h"
+uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+```
+
+Please have a look at the file src/webp/decode.h for the details. There are
+variants for decoding in BGR/RGBA/ARGB/BGRA order, along with decoding to raw
+Y'CbCr samples. One can also decode the image directly into a pre-allocated
+buffer.
+
+To detect a WebP file and gather the picture's dimensions, the function:
+
+```c
+int WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+```
+
+is supplied. No decoding is involved when using it.
+
+### Incremental decoding API
+
+In the case when data is being progressively transmitted, pictures can still be
+incrementally decoded using a slightly more complicated API. Decoder state is
+stored into an instance of the WebPIDecoder object. This object can be created
+with the purpose of decoding either RGB or Y'CbCr samples. For instance:
+
+```c
+WebPDecBuffer buffer;
+WebPInitDecBuffer(&buffer);
+buffer.colorspace = MODE_BGR;
+...
+WebPIDecoder* idec = WebPINewDecoder(&buffer);
+```
+
+As data is made progressively available, this incremental-decoder object can be
+used to decode the picture further. There are two (mutually exclusive) ways to
+pass freshly arrived data:
+
+either by appending the fresh bytes:
+
+```c
+WebPIAppend(idec, fresh_data, size_of_fresh_data);
+```
+
+or by just mentioning the new size of the transmitted data:
+
+```c
+WebPIUpdate(idec, buffer, size_of_transmitted_buffer);
+```
+
+Note that 'buffer' can be modified between each call to WebPIUpdate, in
+particular when the buffer is resized to accommodate larger data.
+
+These functions will return the decoding status: either VP8_STATUS_SUSPENDED if
+decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other
+status is an error condition.
+
+The 'idec' object must always be released (even upon an error condition) by
+calling: WebPDelete(idec).
+
+To retrieve partially decoded picture samples, one must use the corresponding
+method: WebPIDecGetRGB or WebPIDecGetYUVA. It will return the last displayable
+pixel row.
+
+Lastly, note that decoding can also be performed into a pre-allocated pixel
+buffer. This buffer must be passed when creating a WebPIDecoder, calling
+WebPINewRGB() or WebPINewYUVA().
+
+Please have a look at the src/webp/decode.h header for further details.
+
+### Advanced Decoding API
+
+WebP decoding supports an advanced API which provides on-the-fly cropping and
+rescaling, something of great usefulness on memory-constrained environments like
+mobile phones. Basically, the memory usage will scale with the output's size,
+not the input's, when one only needs a quick preview or a zoomed in portion of
+an otherwise too-large picture. Some CPU can be saved too, incidentally.
+
+```c
+// A) Init a configuration object
+WebPDecoderConfig config;
+CHECK(WebPInitDecoderConfig(&config));
+
+// B) optional: retrieve the bitstream's features.
+CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
+
+// C) Adjust 'config' options, if needed
+config.options.no_fancy_upsampling = 1;
+config.options.use_scaling = 1;
+config.options.scaled_width = scaledWidth();
+config.options.scaled_height = scaledHeight();
+// etc.
+
+// D) Specify 'config' output options for specifying output colorspace.
+// Optionally the external image decode buffer can also be specified.
+config.output.colorspace = MODE_BGRA;
+// Optionally, the config.output can be pointed to an external buffer as
+// well for decoding the image. This externally supplied memory buffer
+// should be big enough to store the decoded picture.
+config.output.u.RGBA.rgba = (uint8_t*) memory_buffer;
+config.output.u.RGBA.stride = scanline_stride;
+config.output.u.RGBA.size = total_size_of_the_memory_buffer;
+config.output.is_external_memory = 1;
+
+// E) Decode the WebP image. There are two variants w.r.t decoding image.
+// The first one (E.1) decodes the full image and the second one (E.2) is
+// used to incrementally decode the image using small input buffers.
+// Any one of these steps can be used to decode the WebP image.
+
+// E.1) Decode full image.
+CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);
+
+// E.2) Decode image incrementally.
+WebPIDecoder* const idec = WebPIDecode(NULL, NULL, &config);
+CHECK(idec != NULL);
+while (bytes_remaining > 0) {
+ VP8StatusCode status = WebPIAppend(idec, input, bytes_read);
+ if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
+ bytes_remaining -= bytes_read;
+ } else {
+ break;
+ }
+}
+WebPIDelete(idec);
+
+// F) Decoded image is now in config.output (and config.output.u.RGBA).
+// It can be saved, displayed or otherwise processed.
+
+// G) Reclaim memory allocated in config's object. It's safe to call
+// this function even if the memory is external and wasn't allocated
+// by WebPDecode().
+WebPFreeDecBuffer(&config.output);
+```
+
+## WebP Mux
+
+WebPMux is a set of two libraries 'Mux' and 'Demux' for creation, extraction and
+manipulation of an extended format WebP file, which can have features like color
+profile, metadata and animation. Reference command-line tools `webpmux` and
+`vwebp` as well as the WebP container specification
+'doc/webp-container-spec.txt' are also provided in this package, see the
+[tools documentation](tools.md).
+
+### Mux API
+
+The Mux API contains methods for adding data to and reading data from WebP
+files. This API currently supports XMP/EXIF metadata, ICC profile and animation.
+Other features may be added in subsequent releases.
+
+Example#1 (pseudo code): Creating a WebPMux object with image data, color
+profile and XMP metadata.
+
+```c
+int copy_data = 0;
+WebPMux* mux = WebPMuxNew();
+// ... (Prepare image data).
+WebPMuxSetImage(mux, &image, copy_data);
+// ... (Prepare ICC profile data).
+WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
+// ... (Prepare XMP metadata).
+WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
+// Get data from mux in WebP RIFF format.
+WebPMuxAssemble(mux, &output_data);
+WebPMuxDelete(mux);
+// ... (Consume output_data; e.g. write output_data.bytes to file).
+WebPDataClear(&output_data);
+```
+
+Example#2 (pseudo code): Get image and color profile data from a WebP file.
+
+```c
+int copy_data = 0;
+// ... (Read data from file).
+WebPMux* mux = WebPMuxCreate(&data, copy_data);
+WebPMuxGetFrame(mux, 1, &image);
+// ... (Consume image; e.g. call WebPDecode() to decode the data).
+WebPMuxGetChunk(mux, "ICCP", &icc_profile);
+// ... (Consume icc_profile).
+WebPMuxDelete(mux);
+free(data);
+```
+
+For a detailed Mux API reference, please refer to the header file
+(src/webp/mux.h).
+
+### Demux API
+
+The Demux API enables extraction of images and extended format data from WebP
+files. This API currently supports reading of XMP/EXIF metadata, ICC profile and
+animated images. Other features may be added in subsequent releases.
+
+Code example: Demuxing WebP data to extract all the frames, ICC profile and
+EXIF/XMP metadata.
+
+```c
+WebPDemuxer* demux = WebPDemux(&webp_data);
+uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
+uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
+// ... (Get information about the features present in the WebP file).
+uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
+
+// ... (Iterate over all frames).
+WebPIterator iter;
+if (WebPDemuxGetFrame(demux, 1, &iter)) {
+ do {
+ // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(),
+ // ... and get other frame properties like width, height, offsets etc.
+ // ... see 'struct WebPIterator' below for more info).
+ } while (WebPDemuxNextFrame(&iter));
+ WebPDemuxReleaseIterator(&iter);
+}
+
+// ... (Extract metadata).
+WebPChunkIterator chunk_iter;
+if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter);
+// ... (Consume the ICC profile in 'chunk_iter.chunk').
+WebPDemuxReleaseChunkIterator(&chunk_iter);
+if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter);
+// ... (Consume the EXIF metadata in 'chunk_iter.chunk').
+WebPDemuxReleaseChunkIterator(&chunk_iter);
+if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter);
+// ... (Consume the XMP metadata in 'chunk_iter.chunk').
+WebPDemuxReleaseChunkIterator(&chunk_iter);
+WebPDemuxDelete(demux);
+```
+
+For a detailed Demux API reference, please refer to the header file
+(src/webp/demux.h).
+
+## AnimEncoder API
+
+The AnimEncoder API can be used to create animated WebP images.
+
+Code example:
+
+```c
+WebPAnimEncoderOptions enc_options;
+WebPAnimEncoderOptionsInit(&enc_options);
+// ... (Tune 'enc_options' as needed).
+WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
+while(<there are more frames>) {
+ WebPConfig config;
+ WebPConfigInit(&config);
+ // ... (Tune 'config' as needed).
+ WebPAnimEncoderAdd(enc, frame, duration, &config);
+}
+WebPAnimEncoderAssemble(enc, webp_data);
+WebPAnimEncoderDelete(enc);
+// ... (Write the 'webp_data' to a file, or re-mux it further).
+```
+
+For a detailed AnimEncoder API reference, please refer to the header file
+(src/webp/mux.h).
+
+## AnimDecoder API
+
+This AnimDecoder API allows decoding (possibly) animated WebP images.
+
+Code Example:
+
+```c
+WebPAnimDecoderOptions dec_options;
+WebPAnimDecoderOptionsInit(&dec_options);
+// Tune 'dec_options' as needed.
+WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
+WebPAnimInfo anim_info;
+WebPAnimDecoderGetInfo(dec, &anim_info);
+for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
+ while (WebPAnimDecoderHasMoreFrames(dec)) {
+ uint8_t* buf;
+ int timestamp;
+ WebPAnimDecoderGetNext(dec, &buf, ×tamp);
+ // ... (Render 'buf' based on 'timestamp').
+ // ... (Do NOT free 'buf', as it is owned by 'dec').
+ }
+ WebPAnimDecoderReset(dec);
+}
+const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
+// ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
+WebPAnimDecoderDelete(dec);
+```
+
+For a detailed AnimDecoder API reference, please refer to the header file
+(src/webp/demux.h).
diff --git a/doc/building.md b/doc/building.md
new file mode 100644
index 0000000..5efeab9
--- /dev/null
+++ b/doc/building.md
@@ -0,0 +1,213 @@
+# Building
+
+## Windows build
+
+By running:
+
+```batch
+nmake /f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output
+```
+
+the directory `output\release-static\(x64|x86)\bin` will contain the tools
+cwebp.exe and dwebp.exe. The directory `output\release-static\(x64|x86)\lib`
+will contain the libwebp static library. The target architecture (x86/x64) is
+detected by Makefile.vc from the Visual Studio compiler (cl.exe) available in
+the system path.
+
+## Unix build using makefile.unix
+
+On platforms with GNU tools installed (gcc and make), running
+
+```shell
+make -f makefile.unix
+```
+
+will build the binaries examples/cwebp and examples/dwebp, along with the static
+library src/libwebp.a. No system-wide installation is supplied, as this is a
+simple alternative to the full installation system based on the autoconf tools
+(see below). Please refer to makefile.unix for additional details and
+customizations.
+
+## Using autoconf tools
+
+Prerequisites: a compiler (e.g., gcc), make, autoconf, automake, libtool.
+
+On a Debian-like system the following should install everything you need for a
+minimal build:
+
+```shell
+$ sudo apt-get install gcc make autoconf automake libtool
+```
+
+When building from git sources, you will need to run autogen.sh to generate the
+configure script.
+
+```shell
+./configure
+make
+make install
+```
+
+should be all you need to have the following files
+
+```
+/usr/local/include/webp/decode.h
+/usr/local/include/webp/encode.h
+/usr/local/include/webp/types.h
+/usr/local/lib/libwebp.*
+/usr/local/bin/cwebp
+/usr/local/bin/dwebp
+```
+
+installed.
+
+Note: A decode-only library, libwebpdecoder, is available using the
+`--enable-libwebpdecoder` flag. The encode library is built separately and can
+be installed independently using a minor modification in the corresponding
+Makefile.am configure files (see comments there). See `./configure --help` for
+more options.
+
+## Building for MIPS Linux
+
+MIPS Linux toolchain stable available releases can be found at:
+https://community.imgtec.com/developers/mips/tools/codescape-mips-sdk/available-releases/
+
+```shell
+# Add toolchain to PATH
+export PATH=$PATH:/path/to/toolchain/bin
+
+# 32-bit build for mips32r5 (p5600)
+HOST=mips-mti-linux-gnu
+MIPS_CFLAGS="-O3 -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64 \
+ -msched-weight -mload-store-pairs -fPIE"
+MIPS_LDFLAGS="-mips32r5 -mabi=32 -mmsa -mfp64 -pie"
+
+# 64-bit build for mips64r6 (i6400)
+HOST=mips-img-linux-gnu
+MIPS_CFLAGS="-O3 -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64 \
+ -msched-weight -mload-store-pairs -fPIE"
+MIPS_LDFLAGS="-mips64r6 -mabi=64 -mmsa -mfp64 -pie"
+
+./configure --host=${HOST} --build=`config.guess` \
+ CC="${HOST}-gcc -EL" \
+ CFLAGS="$MIPS_CFLAGS" \
+ LDFLAGS="$MIPS_LDFLAGS"
+make
+make install
+```
+
+## CMake
+
+With CMake, you can compile libwebp, cwebp, dwebp, gif2webp, img2webp, webpinfo
+and the JS bindings.
+
+Prerequisites: a compiler (e.g., gcc with autotools) and CMake.
+
+On a Debian-like system the following should install everything you need for a
+minimal build:
+
+```shell
+$ sudo apt-get install build-essential cmake
+```
+
+When building from git sources, you will need to run cmake to generate the
+makefiles.
+
+```shell
+mkdir build && cd build && cmake ../
+make
+make install
+```
+
+If you also want any of the executables, you will need to enable them through
+CMake, e.g.:
+
+```shell
+cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
+```
+
+or through your favorite interface (like ccmake or cmake-qt-gui).
+
+Use option `-DWEBP_UNICODE=ON` for Unicode support on Windows (with chcp 65001).
+
+Finally, once installed, you can also use WebP in your CMake project by doing:
+
+```cmake
+find_package(WebP)
+```
+
+which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
+
+## Gradle
+
+The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
+dwebp and webpmux_example.
+
+Prerequisites: a compiler (e.g., gcc with autotools) and gradle.
+
+On a Debian-like system the following should install everything you need for a
+minimal build:
+
+```shell
+$ sudo apt-get install build-essential gradle
+```
+
+When building from git sources, you will need to run the Gradle wrapper with the
+appropriate target, e.g. :
+
+```shell
+./gradlew buildAllExecutables
+```
+
+## SWIG bindings
+
+To generate language bindings from swig/libwebp.swig at least swig-1.3
+(http://www.swig.org) is required.
+
+Currently the following functions are mapped:
+
+Decode:
+
+```
+WebPGetDecoderVersion
+WebPGetInfo
+WebPDecodeRGBA
+WebPDecodeARGB
+WebPDecodeBGRA
+WebPDecodeBGR
+WebPDecodeRGB
+```
+
+Encode:
+
+```
+WebPGetEncoderVersion
+WebPEncodeRGBA
+WebPEncodeBGRA
+WebPEncodeRGB
+WebPEncodeBGR
+WebPEncodeLosslessRGBA
+WebPEncodeLosslessBGRA
+WebPEncodeLosslessRGB
+WebPEncodeLosslessBGR
+```
+
+See also the [swig documentation](../swig/README.md) for more detailed build
+instructions and usage examples.
+
+### Java bindings
+
+To build the swig-generated JNI wrapper code at least JDK-1.5 (or equivalent) is
+necessary for enum support. The output is intended to be a shared object / DLL
+that can be loaded via `System.loadLibrary("webp_jni")`.
+
+### Python bindings
+
+To build the swig-generated Python extension code at least Python 2.6 is
+required. Python < 2.6 may build with some minor changes to libwebp.swig or the
+generated code, but is untested.
+
+## Javascript decoder
+
+Libwebp can be compiled into a JavaScript decoder using Emscripten and CMake.
+See the [corresponding documentation](../README.md)
diff --git a/doc/specs_generation.md b/doc/specs_generation.md
new file mode 100644
index 0000000..0380d66
--- /dev/null
+++ b/doc/specs_generation.md
@@ -0,0 +1,26 @@
+# Generate libwebp Container Spec Docs from Text Source
+
+HTML generation requires [kramdown](https://kramdown.gettalong.org/), easily
+installed as a [rubygem](https://rubygems.org/). Rubygems installation should
+satisfy dependencies automatically.
+
+HTML generation can then be done from the project root:
+
+```shell
+$ kramdown doc/webp-container-spec.txt --template doc/template.html > \
+ doc/output/webp-container-spec.html
+```
+
+kramdown can optionally syntax highlight code blocks, using
+[CodeRay](https://github.com/rubychan/coderay), a dependency of kramdown that
+rubygems will install automatically. The following will apply inline CSS
+styling; an external stylesheet is not needed.
+
+```shell
+$ kramdown doc/webp-lossless-bitstream-spec.txt --template \
+ doc/template.html --coderay-css style --coderay-line-numbers ' ' \
+ --coderay-default-lang c > \
+ doc/output/webp-lossless-bitstream-spec.html
+```
+
+Optimally, use kramdown 0.13.7 or newer if syntax highlighting desired.
diff --git a/doc/template.html b/doc/template.html
new file mode 100644
index 0000000..5dbc289
--- /dev/null
+++ b/doc/template.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>WebP Container Specification</title>
+ <meta name="generator" content="kramdown <%= ::Kramdown::VERSION %>" />
+ <style type="text/css">
+ body {
+ color: #000;
+ background-color: #fff;
+ margin: 10%;
+ font-family: "Liberation Sans", "DejaVu Sans", "Bitstream Vera Sans", Arial, sans-serif;
+ line-height: 1.4;
+ }
+ h2 {
+ border-bottom: 1px solid #ccc;
+ padding-bottom: 0;
+ }
+ table {
+ border-collapse: collapse;
+ }
+ th, td {
+ border: 1px solid #999;
+ padding: .5em .7em;;
+ }
+ th {
+ color: #fff;
+ background-color: #000;
+ }
+ td {
+ }
+ hr {
+ }
+ code {
+ color: #000;
+ background-color: #f7f7f7;
+ padding: 0 3px;
+ font-family: "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Consolata, monospace;
+ }
+ pre {
+ background-color: #f7f7f7;
+ padding: 1em;
+ border: 1px solid #ccc;
+ width: 42em;
+ overflow: auto;
+ font-family: "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Consolata, monospace;
+ }
+ pre code {
+ background-color: #f7f7f7;
+ padding: 0; /* Only want padding on inline code, not blocks */
+ }
+ pre.terminal {
+ color: #fff;
+ background-color: #000;
+ border: 1px solid #ccc;
+ max-height: 30em;
+ }
+ pre.terminal code {
+ color: #fff;
+ background-color: #000;
+ font-size: smaller;
+ }
+ #markdown-toc ul {
+ list-style-type: disc;
+ }
+ ul#markdown-toc {
+ margin-top: -1em;
+ visibility: hidden;
+ -webkit-padding-start: 0;
+ }
+ ul#markdown-toc ul {
+ visibility: visible;
+ }
+ ul#markdown-toc ul ul{
+ visibility: visible;
+ }
+ ul#markdown-toc + hr {
+ margin-bottom: 4em;
+ }
+ ol ol { /* Format nested ordered lists */
+ list-style-type: lower-alpha;
+ }
+ dt {
+ font-style: italic;
+ font-weight: bold;
+ }
+ .caption {
+ }
+ </style>
+</head>
+<body>
+<%= @body %>
+</body>
+</html>
diff --git a/doc/tools.md b/doc/tools.md
new file mode 100644
index 0000000..853af81
--- /dev/null
+++ b/doc/tools.md
@@ -0,0 +1,512 @@
+# WebP tools
+
+## Encoding tool
+
+The examples/ directory contains tools for encoding (cwebp) and decoding (dwebp)
+images.
+
+The easiest use should look like:
+
+```shell
+cwebp input.png -q 80 -o output.webp
+```
+
+which will convert the input file to a WebP file using a quality factor of 80 on
+a 0->100 scale (0 being the lowest quality, 100 being the best. Default value is
+75).
+
+You might want to try the `-lossless` flag too, which will compress the source
+(in RGBA format) without any loss. The `-q` quality parameter will in this case
+control the amount of processing time spent trying to make the output file as
+small as possible.
+
+A longer list of options is available using the `-longhelp` command line flag:
+
+```shell
+> cwebp -longhelp
+Usage:
+ cwebp [-preset <...>] [options] in_file [-o out_file]
+```
+
+If input size (-s) for an image is not specified, it is assumed to be a PNG,
+JPEG, TIFF or WebP file. Note: Animated PNG and WebP files are not supported.
+
+Options:
+
+```
+-h / -help ............. short help
+-H / -longhelp ......... long help
+-q <float> ............. quality factor (0:small..100:big), default=75
+-alpha_q <int> ......... transparency-compression quality (0..100),
+ default=100
+-preset <string> ....... preset setting, one of:
+ default, photo, picture,
+ drawing, icon, text
+ -preset must come first, as it overwrites other parameters
+-z <int> ............... activates lossless preset with given
+ level in [0:fast, ..., 9:slowest]
+
+-m <int> ............... compression method (0=fast, 6=slowest), default=4
+-segments <int> ........ number of segments to use (1..4), default=4
+-size <int> ............ target size (in bytes)
+-psnr <float> .......... target PSNR (in dB. typically: 42)
+
+-s <int> <int> ......... input size (width x height) for YUV
+-sns <int> ............. spatial noise shaping (0:off, 100:max), default=50
+-f <int> ............... filter strength (0=off..100), default=60
+-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0
+-strong ................ use strong filter instead of simple (default)
+-nostrong .............. use simple filter instead of strong
+-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
+-partition_limit <int> . limit quality to fit the 512k limit on
+ the first partition (0=no degradation ... 100=full)
+-pass <int> ............ analysis pass number (1..10)
+-qrange <min> <max> .... specifies the permissible quality range
+ (default: 0 100)
+-crop <x> <y> <w> <h> .. crop picture with the given rectangle
+-resize <w> <h> ........ resize picture (*after* any cropping)
+-mt .................... use multi-threading if available
+-low_memory ............ reduce memory usage (slower encoding)
+-map <int> ............. print map of extra info
+-print_psnr ............ prints averaged PSNR distortion
+-print_ssim ............ prints averaged SSIM distortion
+-print_lsim ............ prints local-similarity distortion
+-d <file.pgm> .......... dump the compressed output (PGM file)
+-alpha_method <int> .... transparency-compression method (0..1), default=1
+-alpha_filter <string> . predictive filtering for alpha plane,
+ one of: none, fast (default) or best
+-exact ................. preserve RGB values in transparent area, default=off
+-blend_alpha <hex> ..... blend colors against background color
+ expressed as RGB values written in
+ hexadecimal, e.g. 0xc0e0d0 for red=0xc0
+ green=0xe0 and blue=0xd0
+-noalpha ............... discard any transparency information
+-lossless .............. encode image losslessly, default=off
+-near_lossless <int> ... use near-lossless image
+ preprocessing (0..100=off), default=100
+-hint <string> ......... specify image characteristics hint,
+ one of: photo, picture or graph
+
+-metadata <string> ..... comma separated list of metadata to
+ copy from the input to the output if present.
+ Valid values: all, none (default), exif, icc, xmp
+
+-short ................. condense printed message
+-quiet ................. don't print anything
+-version ............... print version number and exit
+-noasm ................. disable all assembly optimizations
+-v ..................... verbose, e.g. print encoding/decoding times
+-progress .............. report encoding progress
+```
+
+Experimental Options:
+
+```
+-jpeg_like ............. roughly match expected JPEG size
+-af .................... auto-adjust filter strength
+-pre <int> ............. pre-processing filter
+```
+
+The main options you might want to try in order to further tune the visual
+quality are:
+
+-preset -sns -f -m
+
+Namely:
+
+* `preset` will set up a default encoding configuration targeting a particular
+ type of input. It should appear first in the list of options, so that
+ subsequent options can take effect on top of this preset. Default value is
+ 'default'.
+* `sns` will progressively turn on (when going from 0 to 100) some additional
+ visual optimizations (like: segmentation map re-enforcement). This option
+ will balance the bit allocation differently. It tries to take bits from the
+ "easy" parts of the picture and use them in the "difficult" ones instead.
+ Usually, raising the sns value (at fixed -q value) leads to larger files,
+ but with better quality. Typical value is around '75'.
+* `f` option directly links to the filtering strength used by the codec's
+ in-loop processing. The higher the value, the smoother the highly-compressed
+ area will look. This is particularly useful when aiming at very small files.
+ Typical values are around 20-30. Note that using the option
+ -strong/-nostrong will change the type of filtering. Use "-f 0" to turn
+ filtering off.
+* `m` controls the trade-off between encoding speed and quality. Default is 4.
+ You can try -m 5 or -m 6 to explore more (time-consuming) encoding
+ possibilities. A lower value will result in faster encoding at the expense
+ of quality.
+
+## Decoding tool
+
+There is a decoding sample in examples/dwebp.c which will take a .webp file and
+decode it to a PNG image file (amongst other formats). This is simply to
+demonstrate the use of the API. You can verify the file test.webp decodes to
+exactly the same as test_ref.ppm by using:
+
+```shell
+cd examples
+./dwebp test.webp -ppm -o test.ppm
+diff test.ppm test_ref.ppm
+```
+
+The full list of options is available using -h:
+
+```shell
+> dwebp -h
+Usage: dwebp in_file [options] [-o out_file]
+```
+
+Decodes the WebP image file to PNG format [Default]. Note: Animated WebP files
+are not supported.
+
+Use following options to convert into alternate image formats:
+
+```
+-pam ......... save the raw RGBA samples as a color PAM
+-ppm ......... save the raw RGB samples as a color PPM
+-bmp ......... save as uncompressed BMP format
+-tiff ........ save as uncompressed TIFF format
+-pgm ......... save the raw YUV samples as a grayscale PGM
+ file with IMC4 layout
+-yuv ......... save the raw YUV samples in flat layout
+```
+
+Other options are:
+
+```
+-version ..... print version number and exit
+-nofancy ..... don't use the fancy YUV420 upscaler
+-nofilter .... disable in-loop filtering
+-nodither .... disable dithering
+-dither <d> .. dithering strength (in 0..100)
+-alpha_dither use alpha-plane dithering if needed
+-mt .......... use multi-threading
+-crop <x> <y> <w> <h> ... crop output with the given rectangle
+-resize <w> <h> ......... resize output (*after* any cropping)
+-flip ........ flip the output vertically
+-alpha ....... only save the alpha plane
+-incremental . use incremental decoding (useful for tests)
+-h ........... this help message
+-v ........... verbose (e.g. print encoding/decoding times)
+-quiet ....... quiet mode, don't print anything
+-noasm ....... disable all assembly optimizations
+```
+
+## WebP file analysis tool
+
+`webpinfo` can be used to print out the chunk level structure and bitstream
+header information of WebP files. It can also check if the files are of valid
+WebP format.
+
+Usage:
+
+```shell
+webpinfo [options] in_files
+```
+
+Note: there could be multiple input files; options must come before input files.
+
+Options:
+
+```
+-version ........... Print version number and exit.
+-quiet ............. Do not show chunk parsing information.
+-diag .............. Show parsing error diagnosis.
+-summary ........... Show chunk stats summary.
+-bitstream_info .... Parse bitstream header.
+```
+
+## Visualization tool
+
+There's a little self-serve visualization tool called 'vwebp' under the
+examples/ directory. It uses OpenGL to open a simple drawing window and show a
+decoded WebP file. It's not yet integrated in the automake build system, but you
+can try to manually compile it using the recommendations below.
+
+Usage:
+
+```shell
+vwebp in_file [options]
+```
+
+Decodes the WebP image file and visualize it using OpenGL
+
+Options are:
+
+```
+-version ..... print version number and exit
+-noicc ....... don't use the icc profile if present
+-nofancy ..... don't use the fancy YUV420 upscaler
+-nofilter .... disable in-loop filtering
+-dither <int> dithering strength (0..100), default=50
+-noalphadither disable alpha plane dithering
+-usebgcolor .. display background color
+-mt .......... use multi-threading
+-info ........ print info
+-h ........... this help message
+```
+
+Keyboard shortcuts:
+
+```
+'c' ................ toggle use of color profile
+'b' ................ toggle background color display
+'i' ................ overlay file information
+'d' ................ disable blending & disposal (debug)
+'q' / 'Q' / ESC .... quit
+```
+
+### Building
+
+Prerequisites:
+
+1. OpenGL & OpenGL Utility Toolkit (GLUT)
+
+ Linux: `sudo apt-get install freeglut3-dev mesa-common-dev`
+
+ Mac + Xcode: These libraries should be available in the OpenGL / GLUT
+ frameworks.
+
+ Windows: http://freeglut.sourceforge.net/index.php#download
+
+2. (Optional) qcms (Quick Color Management System)
+
+ 1. Download qcms from Mozilla / Chromium:
+ https://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
+ https://source.chromium.org/chromium/chromium/src/+/main:third_party/qcms/;drc=d4a2f8e1ed461d8fc05ed88d1ae2dc94c9773825
+ 2. Build and archive the source files as libqcms.a / qcms.lib
+ 3. Update makefile.unix / Makefile.vc
+ 1. Define WEBP_HAVE_QCMS
+ 2. Update include / library paths to reference the qcms directory.
+
+Build using makefile.unix / Makefile.vc:
+
+```shell
+$ make -f makefile.unix examples/vwebp
+> nmake /f Makefile.vc CFG=release-static \
+ ../obj/x64/release-static/bin/vwebp.exe
+```
+
+## Animation creation tool
+
+The utility `img2webp` can turn a sequence of input images (PNG, JPEG, ...) into
+an animated WebP file. It offers fine control over duration, encoding modes,
+etc.
+
+Usage:
+
+```shell
+img2webp [file_options] [[frame_options] frame_file]...
+```
+
+File-level options (only used at the start of compression):
+
+```
+-min_size ............ minimize size
+-loop <int> .......... loop count (default: 0, = infinite loop)
+-kmax <int> .......... maximum number of frame between key-frames
+ (0=only keyframes)
+-kmin <int> .......... minimum number of frame between key-frames
+ (0=disable key-frames altogether)
+-mixed ............... use mixed lossy/lossless automatic mode
+-v ................... verbose mode
+-h ................... this help
+-version ............. print version number and exit
+```
+
+Per-frame options (only used for subsequent images input):
+
+```
+-d <int> ............. frame duration in ms (default: 100)
+-lossless ........... use lossless mode (default)
+-lossy ... ........... use lossy mode
+-q <float> ........... quality
+-m <int> ............. method to use
+```
+
+example: `img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp`
+
+Note: if a single file name is passed as the argument, the arguments will be
+tokenized from this file. The file name must not start with the character '-'.
+
+## Animated GIF conversion
+
+Animated GIF files can be converted to WebP files with animation using the
+gif2webp utility available under examples/. The files can then be viewed using
+vwebp.
+
+Usage:
+
+```shell
+gif2webp [options] gif_file -o webp_file
+```
+
+Options:
+
+```
+-h / -help ............. this help
+-lossy ................. encode image using lossy compression
+-mixed ................. for each frame in the image, pick lossy
+ or lossless compression heuristically
+-q <float> ............. quality factor (0:small..100:big)
+-m <int> ............... compression method (0=fast, 6=slowest)
+-min_size .............. minimize output size (default:off)
+ lossless compression by default; can be
+ combined with -q, -m, -lossy or -mixed
+ options
+-kmin <int> ............ min distance between key frames
+-kmax <int> ............ max distance between key frames
+-f <int> ............... filter strength (0=off..100)
+-metadata <string> ..... comma separated list of metadata to
+ copy from the input to the output if present
+ Valid values: all, none, icc, xmp (default)
+-loop_compatibility .... use compatibility mode for Chrome
+ version prior to M62 (inclusive)
+-mt .................... use multi-threading if available
+
+-version ............... print version number and exit
+-v ..................... verbose
+-quiet ................. don't print anything
+```
+
+### Building
+
+With the libgif development files installed, gif2webp can be built using
+makefile.unix:
+
+```shell
+$ make -f makefile.unix examples/gif2webp
+```
+
+or using autoconf:
+
+```shell
+$ ./configure --enable-everything
+$ make
+```
+
+## Comparison of animated images
+
+Test utility anim_diff under examples/ can be used to compare two animated
+images (each can be GIF or WebP).
+
+Usage:
+
+```shell
+anim_diff <image1> <image2> [options]
+```
+
+Options:
+
+```
+-dump_frames <folder> dump decoded frames in PAM format
+-min_psnr <float> ... minimum per-frame PSNR
+-raw_comparison ..... if this flag is not used, RGB is
+ premultiplied before comparison
+-max_diff <int> ..... maximum allowed difference per channel
+ between corresponding pixels in subsequent
+ frames
+-h .................. this help
+-version ............ print version number and exit
+```
+
+### Building
+
+With the libgif development files installed, anim_diff can be built using
+makefile.unix:
+
+```shell
+$ make -f makefile.unix examples/anim_diff
+```
+
+or using autoconf:
+
+```shell
+$ ./configure --enable-everything
+$ make
+```
+
+## WebP Mux tool
+
+The examples/ directory contains a tool (webpmux) for manipulating WebP files.
+The webpmux tool can be used to create an extended format WebP file and also to
+extract or strip relevant data from such a file.
+
+A list of options is available using the -help command line flag:
+
+```shell
+> webpmux -help
+Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
+ webpmux -set SET_OPTIONS INPUT -o OUTPUT
+ webpmux -duration DURATION_OPTIONS [-duration ...]
+ INPUT -o OUTPUT
+ webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
+ webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
+ [-bgcolor BACKGROUND_COLOR] -o OUTPUT
+ webpmux -info INPUT
+ webpmux [-h|-help]
+ webpmux -version
+ webpmux argument_file_name
+
+GET_OPTIONS:
+ Extract relevant data:
+ icc get ICC profile
+ exif get EXIF metadata
+ xmp get XMP metadata
+ frame n get nth frame
+
+SET_OPTIONS:
+ Set color profile/metadata/parameters:
+ loop LOOP_COUNT set the loop count
+ bgcolor BACKGROUND_COLOR set the animation background color
+ icc file.icc set ICC profile
+ exif file.exif set EXIF metadata
+ xmp file.xmp set XMP metadata
+ where: 'file.icc' contains the ICC profile to be set,
+ 'file.exif' contains the EXIF metadata to be set
+ 'file.xmp' contains the XMP metadata to be set
+
+DURATION_OPTIONS:
+ Set duration of selected frames:
+ duration set duration for all frames
+ duration,frame set duration of a particular frame
+ duration,start,end set duration of frames in the
+ interval [start,end])
+ where: 'duration' is the duration in milliseconds
+ 'start' is the start frame index
+ 'end' is the inclusive end frame index
+ The special 'end' value '0' means: last frame.
+
+STRIP_OPTIONS:
+ Strip color profile/metadata:
+ icc strip ICC profile
+ exif strip EXIF metadata
+ xmp strip XMP metadata
+
+FRAME_OPTIONS(i):
+ Create animation:
+ file_i +di[+xi+yi[+mi[bi]]]
+ where: 'file_i' is the i'th animation frame (WebP format),
+ 'di' is the pause duration before next frame,
+ 'xi','yi' specify the image offset for this frame,
+ 'mi' is the dispose method for this frame (0 or 1),
+ 'bi' is the blending method for this frame (+b or -b)
+
+LOOP_COUNT:
+ Number of times to repeat the animation.
+ Valid range is 0 to 65535 [Default: 0 (infinite)].
+
+BACKGROUND_COLOR:
+ Background color of the canvas.
+ A,R,G,B
+ where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying
+ the Alpha, Red, Green and Blue component values respectively
+ [Default: 255,255,255,255]
+
+INPUT & OUTPUT are in WebP format.
+
+Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
+valid.
+
+Note: if a single file name is passed as the argument, the arguments will be
+tokenized from this file. The file name must not start with the character '-'.
+```
diff --git a/doc/webp-container-spec.txt b/doc/webp-container-spec.txt
new file mode 100644
index 0000000..ffa919e
--- /dev/null
+++ b/doc/webp-container-spec.txt
@@ -0,0 +1,868 @@
+<!--
+
+Although you may be viewing an alternate representation, this document
+is sourced in Markdown, a light-duty markup scheme, and is optimized for
+the [kramdown](https://kramdown.gettalong.org/) transformer.
+
+See the accompanying specs_generation.md. External link targets are referenced
+at the end of this file.
+
+-->
+
+
+WebP Container Specification
+============================
+
+* TOC placeholder
+{:toc}
+
+
+Introduction
+------------
+
+WebP is an image format that uses either (i) the VP8 key frame encoding
+to compress image data in a lossy way, or (ii) the WebP lossless encoding
+(and possibly other encodings in the future). These encoding schemes should
+make it more efficient than currently used formats. It is optimized for fast
+image transfer over the network (e.g., for websites). The WebP format has
+feature parity (color profile, metadata, animation, etc.) with other formats as
+well. This document describes the structure of a WebP file.
+
+The WebP container (i.e., RIFF container for WebP) allows feature support over
+and above the basic use case of WebP (i.e., a file containing a single image
+encoded as a VP8 key frame). The WebP container provides additional support
+for:
+
+ * **Lossless compression.** An image can be losslessly compressed, using the
+ WebP Lossless Format.
+
+ * **Metadata.** An image may have metadata stored in Exif or XMP formats.
+
+ * **Transparency.** An image may have transparency, i.e., an alpha channel.
+
+ * **Color Profile.** An image may have an embedded ICC profile as described
+ by the [International Color Consortium][iccspec].
+
+ * **Animation.** An image may have multiple frames with pauses between them,
+ making it an animation.
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
+"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
+document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][]
+when, and only when, they appear in all capitals, as shown here.
+
+Bit numbering in chunk diagrams starts at `0` for the most significant bit
+('MSB 0') as described in [RFC 1166][].
+
+Terminology & Basics
+--------------------
+
+A WebP file contains either a still image (i.e., an encoded matrix of pixels)
+or an [animation](#animation). Optionally, it can also contain transparency
+information, color profile and metadata. In case we need to refer only to the
+matrix of pixels, we will call it the _canvas_ of the image.
+
+Below are additional terms used throughout this document:
+
+_Reader/Writer_
+
+: Code that reads WebP files is referred to as a _reader_, while code that
+ writes them is referred to as a _writer_.
+
+_uint16_
+
+: A 16-bit, little-endian, unsigned integer.
+
+_uint24_
+
+: A 24-bit, little-endian, unsigned integer.
+
+_uint32_
+
+: A 32-bit, little-endian, unsigned integer.
+
+_FourCC_
+
+: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
+ ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and
+ 'AAAA' (0x41414141) are treated as different _FourCCs_.
+
+_1-based_
+
+: An unsigned integer field storing values offset by `-1`. e.g., Such a field
+ would store value _25_ as _24_.
+
+_ChunkHeader('ABCD')_
+
+: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
+ chunks, where 'ABCD' is the FourCC for the chunk. This element's size is 8
+ bytes.
+
+
+RIFF File Format
+----------------
+
+The WebP file format is based on the RIFF (Resource Interchange File Format)
+document format.
+
+The basic element of a RIFF file is a _chunk_. It consists of:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Chunk FourCC |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Chunk Size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : Chunk Payload :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Chunk FourCC: 32 bits
+
+: ASCII four-character code used for chunk identification.
+
+Chunk Size: 32 bits (_uint32_)
+
+: The size of the chunk in bytes, not including this field, the chunk
+ identifier or padding.
+
+Chunk Payload: _Chunk Size_ bytes
+
+: The data payload. If _Chunk Size_ is odd, a single padding byte -- that MUST
+ be `0` to conform with RIFF -- is added.
+
+**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
+chunks that apply to any RIFF file format, while FourCCs specific to a file
+format are all lowercase. WebP does not follow this convention.
+
+
+WebP File Header
+----------------
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 'R' | 'I' | 'F' | 'F' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | File Size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 'W' | 'E' | 'B' | 'P' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+'RIFF': 32 bits
+
+: The ASCII characters 'R' 'I' 'F' 'F'.
+
+File Size: 32 bits (_uint32_)
+
+: The size of the file in bytes starting at offset 8. The maximum value of
+ this field is 2^32 minus 10 bytes and thus the size of the whole file is at
+ most 4GiB minus 2 bytes.
+
+'WEBP': 32 bits
+
+: The ASCII characters 'W' 'E' 'B' 'P'.
+
+A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
+in the header is the total size of the chunks that follow plus `4` bytes for
+the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data
+specified by _File Size_. Readers MAY parse such files, ignoring the trailing
+data. As the size of any chunk is even, the size given by the RIFF header is
+also even. The contents of individual chunks will be described in the following
+sections.
+
+
+Simple File Format (Lossy)
+--------------------------
+
+This layout SHOULD be used if the image requires _lossy_ encoding and does not
+require transparency or other advanced features provided by the extended format.
+Files with this layout are smaller and supported by older software.
+
+Simple WebP (lossy) file format:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | WebP file header (12 bytes) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : VP8 chunk :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+VP8 chunk:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('VP8 ') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : VP8 data :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+VP8 data: _Chunk Size_ bytes
+
+: VP8 bitstream data.
+
+Note the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
+
+The VP8 bitstream format specification can be found at [VP8 Data Format and
+Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
+width and height. That is assumed to be the width and height of the canvas.
+
+The VP8 specification describes how to decode the image into Y'CbCr format. To
+convert to RGB, Rec. 601 SHOULD be used. Applications MAY use another
+conversion method, but visual results may differ among decoders.
+
+
+Simple File Format (Lossless)
+-----------------------------
+
+**Note:** Older readers may not support files using the lossless format.
+
+This layout SHOULD be used if the image requires _lossless_ encoding (with an
+optional transparency channel) and does not require advanced features provided
+by the extended format.
+
+Simple WebP (lossless) file format:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | WebP file header (12 bytes) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : VP8L chunk :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+VP8L chunk:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('VP8L') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : VP8L data :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+VP8L data: _Chunk Size_ bytes
+
+: VP8L bitstream data.
+
+The current specification of the VP8L bitstream can be found at
+[WebP Lossless Bitstream Format][webpllspec]. Note that the VP8L header
+contains the VP8L image width and height. That is assumed to be the width
+and height of the canvas.
+
+
+Extended File Format
+--------------------
+
+**Note:** Older readers may not support files using the extended format.
+
+An extended format file consists of:
+
+ * A 'VP8X' chunk with information about features used in the file.
+
+ * An optional 'ICCP' chunk with color profile.
+
+ * An optional 'ANIM' chunk with animation control data.
+
+ * Image data.
+
+ * An optional 'EXIF' chunk with Exif metadata.
+
+ * An optional 'XMP ' chunk with XMP metadata.
+
+ * An optional list of [unknown chunks](#unknown-chunks).
+
+For a _still image_, the _image data_ consists of a single frame, which is made
+up of:
+
+ * An optional [alpha subchunk](#alpha).
+
+ * A [bitstream subchunk](#bitstream-vp8vp8l).
+
+For an _animated image_, the _image data_ consists of multiple frames. More
+details about frames can be found in the [Animation](#animation) section.
+
+All chunks SHOULD be placed in the same order as listed above. If a chunk
+appears in the wrong place, the file is invalid, but readers MAY parse the
+file, ignoring the chunks that are out of order.
+
+**Rationale:** Setting the order of chunks should allow quicker file
+parsing. For example, if an 'ALPH' chunk does not appear in its required
+position, a decoder can choose to stop searching for it. The rule of
+ignoring late chunks should make programs that need to do a full search
+give the same results as the ones stopping early.
+
+Extended WebP file header:
+{:#extended_header}
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | WebP file header (12 bytes) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('VP8X') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Rsv|I|L|E|X|A|R| Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Canvas Width Minus One | ...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ... Canvas Height Minus One |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Reserved (Rsv): 2 bits
+
+: MUST be `0`. Readers MUST ignore this field.
+
+ICC profile (I): 1 bit
+
+: Set if the file contains an ICC profile.
+
+Alpha (L): 1 bit
+
+: Set if any of the frames of the image contain transparency information
+ ("alpha").
+
+Exif metadata (E): 1 bit
+
+: Set if the file contains Exif metadata.
+
+XMP metadata (X): 1 bit
+
+: Set if the file contains XMP metadata.
+
+Animation (A): 1 bit
+
+: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
+ used to control the animation.
+
+Reserved (R): 1 bit
+
+: MUST be `0`. Readers MUST ignore this field.
+
+Reserved: 24 bits
+
+: MUST be `0`. Readers MUST ignore this field.
+
+Canvas Width Minus One: 24 bits
+
+: _1-based_ width of the canvas in pixels.
+ The actual canvas width is `1 + Canvas Width Minus One`.
+
+Canvas Height Minus One: 24 bits
+
+: _1-based_ height of the canvas in pixels.
+ The actual canvas height is `1 + Canvas Height Minus One`.
+
+The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`.
+
+Future specifications may add more fields. Unknown fields MUST be ignored.
+
+### Chunks
+
+#### Animation
+
+An animation is controlled by ANIM and ANMF chunks.
+
+ANIM Chunk:
+{:#anim_chunk}
+
+For an animated image, this chunk contains the _global parameters_ of the
+animation.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('ANIM') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Background Color |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Loop Count |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Background Color: 32 bits (_uint32_)
+
+: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
+ byte order. This color MAY be used to fill the unused space on the canvas
+ around the frames, as well as the transparent pixels of the first frame.
+ Background color is also used when disposal method is `1`.
+
+**Note**:
+
+ * Background color MAY contain a non-opaque alpha value, even if the _Alpha_
+ flag in [VP8X chunk](#extended_header) is unset.
+
+ * Viewer applications SHOULD treat the background color value as a hint, and
+ are not required to use it.
+
+ * The canvas is cleared at the start of each loop. The background color MAY be
+ used to achieve this.
+
+Loop Count: 16 bits (_uint16_)
+
+: The number of times to loop the animation. `0` means infinitely.
+
+This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
+If the _Animation_ flag is not set and this chunk is present, it MUST be
+ignored.
+
+ANMF chunk:
+
+For animated images, this chunk contains information about a _single_ frame.
+If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('ANMF') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Frame X | ...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ... Frame Y | Frame Width Minus One ...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ... | Frame Height Minus One |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Frame Duration | Reserved |B|D|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : Frame Data :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Frame X: 24 bits (_uint24_)
+
+: The X coordinate of the upper left corner of the frame is `Frame X * 2`.
+
+Frame Y: 24 bits (_uint24_)
+
+: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`.
+
+Frame Width Minus One: 24 bits (_uint24_)
+
+: The _1-based_ width of the frame.
+ The frame width is `1 + Frame Width Minus One`.
+
+Frame Height Minus One: 24 bits (_uint24_)
+
+: The _1-based_ height of the frame.
+ The frame height is `1 + Frame Height Minus One`.
+
+Frame Duration: 24 bits (_uint24_)
+
+: The time to wait before displaying the next frame, in 1 millisecond units.
+ Note the interpretation of frame duration of 0 (and often <= 10) is
+ implementation defined. Many tools and browsers assign a minimum duration
+ similar to GIF.
+
+Reserved: 6 bits
+
+: MUST be `0`. Readers MUST ignore this field.
+
+Blending method (B): 1 bit
+
+: Indicates how transparent pixels of _the current frame_ are to be blended
+ with corresponding pixels of the previous canvas:
+
+ * `0`: Use alpha blending. After disposing of the previous frame, render the
+ current frame on the canvas using [alpha-blending](#alpha-blending). If
+ the current frame does not have an alpha channel, assume alpha value of
+ 255, effectively replacing the rectangle.
+
+ * `1`: Do not blend. After disposing of the previous frame, render the
+ current frame on the canvas by overwriting the rectangle covered by the
+ current frame.
+
+Disposal method (D): 1 bit
+
+: Indicates how _the current frame_ is to be treated after it has been
+ displayed (before rendering the next frame) on the canvas:
+
+ * `0`: Do not dispose. Leave the canvas as is.
+
+ * `1`: Dispose to background color. Fill the _rectangle_ on the canvas
+ covered by the _current frame_ with background color specified in the
+ [ANIM chunk](#anim_chunk).
+
+**Notes**:
+
+ * The frame disposal only applies to the _frame rectangle_, that is, the
+ rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
+ It may or may not cover the whole canvas.
+
+{:#alpha-blending}
+ * **Alpha-blending**:
+
+ Given that each of the R, G, B and A channels is 8-bit, and the RGB
+ channels are _not premultiplied_ by alpha, the formula for blending
+ 'dst' onto 'src' is:
+
+~~~~~
+ blend.A = src.A + dst.A * (1 - src.A / 255)
+ if blend.A = 0 then
+ blend.RGB = 0
+ else
+ blend.RGB =
+ (src.RGB * src.A +
+ dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
+~~~~~
+
+ * Alpha-blending SHOULD be done in linear color space, by taking into account
+ the [color profile](#color-profile) of the image. If the color profile is
+ not present, sRGB is to be assumed. (Note that sRGB also needs to be
+ linearized due to a gamma of ~2.2).
+
+Frame Data: _Chunk Size_ - `16` bytes
+
+: Consists of:
+
+ * An optional [alpha subchunk](#alpha) for the frame.
+
+ * A [bitstream subchunk](#bitstream-vp8vp8l) for the frame.
+
+ * An optional list of [unknown chunks](#unknown-chunks).
+
+**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
+_padded_ chunks as described by the [RIFF file format](#riff-file-format).
+
+#### Alpha
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('ALPH') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Rsv| P | F | C | Alpha Bitstream... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Reserved (Rsv): 2 bits
+
+: MUST be `0`. Readers MUST ignore this field.
+
+Pre-processing (P): 2 bits
+
+: These _informative_ bits are used to signal the pre-processing that has
+ been performed during compression. The decoder can use this information to
+ e.g. dither the values or smooth the gradients prior to display.
+
+ * `0`: No pre-processing.
+ * `1`: Level reduction.
+
+Filtering method (F): 2 bits
+
+: The filtering method used:
+
+ * `0`: None.
+ * `1`: Horizontal filter.
+ * `2`: Vertical filter.
+ * `3`: Gradient filter.
+
+For each pixel, filtering is performed using the following calculations.
+Assume the alpha values surrounding the current `X` position are labeled as:
+
+ C | B |
+ ---+---+
+ A | X |
+
+We seek to compute the alpha value at position `X`. First, a prediction is
+made depending on the filtering method:
+
+ * Method `0`: predictor = 0
+ * Method `1`: predictor = A
+ * Method `2`: predictor = B
+ * Method `3`: predictor = clip(A + B - C)
+
+where `clip(v)` is equal to:
+
+ * 0 if v < 0
+ * 255 if v > 255
+ * v otherwise
+
+The final value is derived by adding the decompressed value `X` to the
+predictor and using modulo-256 arithmetic to wrap the \[256..511\] range
+into the \[0..255\] one:
+
+`alpha = (predictor + X) % 256`
+
+There are special cases for the left-most and top-most pixel positions:
+
+ * The top-left value at location (0, 0) uses 0 as predictor value. Otherwise,
+ * For horizontal or gradient filtering methods, the left-most pixels at
+ location (0, y) are predicted using the location (0, y-1) just above.
+ * For vertical or gradient filtering methods, the top-most pixels at
+ location (x, 0) are predicted using the location (x-1, 0) on the left.
+
+
+Decoders are not required to use this information in any specified way.
+
+Compression method (C): 2 bits
+
+: The compression method used:
+
+ * `0`: No compression.
+ * `1`: Compressed using the WebP lossless format.
+
+Alpha bitstream: _Chunk Size_ - `1` bytes
+
+: Encoded alpha bitstream.
+
+This optional chunk contains encoded alpha data for this frame. A frame
+containing a 'VP8L' chunk SHOULD NOT contain this chunk.
+
+**Rationale**: The transparency information is already part of the 'VP8L'
+chunk.
+
+The alpha channel data is stored as uncompressed raw data (when
+compression method is '0') or compressed using the lossless format
+(when the compression method is '1').
+
+ * Raw data: consists of a byte sequence of length width * height,
+ containing all the 8-bit transparency values in scan order.
+
+ * Lossless format compression: the byte sequence is a compressed
+ image-stream (as described in the [WebP Lossless Bitstream Format]
+ [webpllspec]) of implicit dimension width x height. That is, this
+ image-stream does NOT contain any headers describing the image dimension.
+
+ **Rationale**: the dimension is already known from other sources,
+ so storing it again would be redundant and error-prone.
+
+ Once the image-stream is decoded into ARGB color values, following
+ the process described in the lossless format specification, the
+ transparency information must be extracted from the *green* channel
+ of the ARGB quadruplet.
+
+ **Rationale**: the green channel is allowed extra transformation
+ steps in the specification -- unlike the other channels -- that can
+ improve compression.
+
+#### Bitstream (VP8/VP8L)
+
+This chunk contains compressed bitstream data for a single frame.
+
+A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
+significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
+"VP8L" as its tag.
+
+The formats of VP8 and VP8L chunks are as described in sections
+[Simple File Format (Lossy)](#simple-file-format-lossy)
+and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively.
+
+#### Color Profile
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('ICCP') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : Color Profile :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Color Profile: _Chunk Size_ bytes
+
+: ICC profile.
+
+This chunk MUST appear before the image data.
+
+There SHOULD be at most one such chunk. If there are more such chunks, readers
+MAY ignore all except the first one.
+See the [ICC Specification][iccspec] for details.
+
+If this chunk is not present, sRGB SHOULD be assumed.
+
+#### Metadata
+
+Metadata can be stored in 'EXIF' or 'XMP ' chunks.
+
+There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there
+are more such chunks, readers MAY ignore all except the first one.
+
+The chunks are defined as follows:
+
+EXIF chunk:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('EXIF') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : Exif Metadata :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Exif Metadata: _Chunk Size_ bytes
+
+: Image metadata in Exif format.
+
+XMP chunk:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ChunkHeader('XMP ') |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : XMP Metadata :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+XMP Metadata: _Chunk Size_ bytes
+
+: Image metadata in XMP format.
+
+Note the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
+
+Additional guidance about handling metadata can be found in the
+Metadata Working Group's [Guidelines for Handling Metadata][metadata].
+
+#### Unknown Chunks
+
+A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
+tag_ is different from any of the chunks described in this document, is
+considered an _unknown chunk_.
+
+**Rationale**: Allowing unknown chunks gives a provision for future extension
+of the format, and also allows storage of any application-specific data.
+
+A file MAY contain unknown chunks:
+
+ * At the end of the file as described in [Extended WebP file
+ header](#extended_header) section.
+ * At the end of ANMF chunks as described in the
+ [Animation](#animation) section.
+
+Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
+original order (unless they specifically intend to modify these chunks).
+
+### Assembling the Canvas From Frames
+
+Here we provide an overview of how a reader MUST assemble a canvas in the case
+of an animated image.
+
+The process begins with creating a canvas using the dimensions given in the
+'VP8X' chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus
+One + 1` pixels high. The `Loop Count` field from the 'ANIM' chunk controls how
+many times the animation process is repeated. This is `Loop Count - 1` for
+non-zero `Loop Count` values or infinitely if `Loop Count` is zero.
+
+At the beginning of each loop iteration the canvas is filled using the
+background color from the 'ANIM' chunk or an application defined color.
+
+'ANMF' chunks contain individual frames given in display order. Before rendering
+each frame, the previous frame's `Disposal method` is applied.
+
+The rendering of the decoded frame begins at the Cartesian coordinates (`2 *
+Frame X`, `2 * Frame Y`) using the top-left corner of the canvas as the origin.
+`Frame Width Minus One + 1` pixels wide by `Frame Height Minus One + 1` pixels
+high are rendered onto the canvas using the `Blending method`.
+
+The canvas is displayed for `Frame Duration` milliseconds. This continues until
+all frames given by 'ANMF' chunks have been displayed. A new loop iteration is
+then begun or the canvas is left in its final state if all iterations have been
+completed.
+
+The following pseudocode illustrates the rendering process. The notation
+_VP8X.field_ means the field in the 'VP8X' chunk with the same description.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+assert VP8X.flags.hasAnimation
+canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
+ background color ANIM.background_color.
+loop_count ← ANIM.loopCount
+dispose_method ← Dispose to background color
+if loop_count == 0:
+ loop_count = ∞
+frame_params ← nil
+assert next chunk in image_data is ANMF
+for loop = 0..loop_count - 1
+ clear canvas to ANIM.background_color or application defined color
+ until eof or non-ANMF chunk
+ frame_params.frameX = Frame X
+ frame_params.frameY = Frame Y
+ frame_params.frameWidth = Frame Width Minus One + 1
+ frame_params.frameHeight = Frame Height Minus One + 1
+ frame_params.frameDuration = Frame Duration
+ frame_right = frame_params.frameX + frame_params.frameWidth
+ frame_bottom = frame_params.frameY + frame_params.frameHeight
+ assert VP8X.canvasWidth >= frame_right
+ assert VP8X.canvasHeight >= frame_bottom
+ for subchunk in 'Frame Data':
+ if subchunk.tag == "ALPH":
+ assert alpha subchunks not found in 'Frame Data' earlier
+ frame_params.alpha = alpha_data
+ else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
+ assert bitstream subchunks not found in 'Frame Data' earlier
+ frame_params.bitstream = bitstream_data
+ render frame with frame_params.alpha and frame_params.bitstream
+ on canvas with top-left corner at (frame_params.frameX,
+ frame_params.frameY), using blending method
+ frame_params.blendingMethod.
+ canvas contains the decoded image.
+ Show the contents of the canvas for
+ frame_params.frameDuration * 1ms.
+ dispose_method = frame_params.disposeMethod
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+Example File Layouts
+--------------------
+
+A lossy encoded image with alpha may look as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RIFF/WEBP
++- VP8X (descriptions of features used)
++- ALPH (alpha bitstream)
++- VP8 (bitstream)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A losslessly encoded image may look as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RIFF/WEBP
++- VP8X (descriptions of features used)
++- XYZW (unknown chunk)
++- VP8L (lossless bitstream)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A lossless image with ICC profile and XMP metadata may
+look as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RIFF/WEBP
++- VP8X (descriptions of features used)
++- ICCP (color profile)
++- VP8L (lossless bitstream)
++- XMP (metadata)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An animated image with Exif metadata may look as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RIFF/WEBP
++- VP8X (descriptions of features used)
++- ANIM (global animation parameters)
++- ANMF (frame1 parameters + data)
++- ANMF (frame2 parameters + data)
++- ANMF (frame3 parameters + data)
++- ANMF (frame4 parameters + data)
++- EXIF (metadata)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[vp8spec]: https://datatracker.ietf.org/doc/html/rfc6386
+[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
+[iccspec]: https://www.color.org/icc_specs2.xalter
+[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
+[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166
+[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119
+[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174
diff --git a/doc/webp-lossless-bitstream-spec.txt b/doc/webp-lossless-bitstream-spec.txt
new file mode 100644
index 0000000..563426d
--- /dev/null
+++ b/doc/webp-lossless-bitstream-spec.txt
@@ -0,0 +1,1139 @@
+<!--
+
+Although you may be viewing an alternate representation, this document is
+sourced in Markdown, a light-duty markup scheme, and is optimized for the
+[kramdown](https://kramdown.gettalong.org/) transformer.
+
+See the accompanying specs_generation.md. External link targets are referenced
+at the end of this file.
+
+-->
+
+Specification for WebP Lossless Bitstream
+=========================================
+
+_Jyrki Alakuijala, Ph.D., Google, Inc., 2012-06-19_
+
+Paragraphs marked as \[AMENDED\] were amended on 2014-09-16.
+
+Paragraphs marked as \[AMENDED2\] were amended on 2022-05-13.
+
+Paragraphs marked as \[AMENDED3\] were amended on 2022-11-21.
+
+Abstract
+--------
+
+WebP lossless is an image format for lossless compression of ARGB images. The
+lossless format stores and restores the pixel values exactly, including the
+color values for pixels whose alpha value is 0. The format uses subresolution
+images, recursively embedded into the format itself, for storing statistical
+data about the images, such as the used entropy codes, spatial predictors, color
+space conversion, and color table. LZ77, prefix coding, and a color cache are
+used for compression of the bulk data. Decoding speeds faster than PNG have been
+demonstrated, as well as 25% denser compression than can be achieved using
+today's PNG format.
+
+
+* TOC placeholder
+{:toc}
+
+
+1 Introduction
+--------------
+
+This document describes the compressed data representation of a WebP lossless
+image. It is intended as a detailed reference for the WebP lossless encoder and
+decoder implementation.
+
+In this document, we extensively use C programming language syntax to describe
+the bitstream, and assume the existence of a function for reading bits,
+`ReadBits(n)`. The bytes are read in the natural order of the stream containing
+them, and bits of each byte are read in least-significant-bit-first order. When
+multiple bits are read at the same time, the integer is constructed from the
+original data in the original order. The most significant bits of the returned
+integer are also the most significant bits of the original data. Thus, the
+statement
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+b = ReadBits(2);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+is equivalent with the two statements below:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+b = ReadBits(1);
+b |= ReadBits(1) << 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We assume that each color component (e.g. alpha, red, blue and green) is
+represented using an 8-bit byte. We define the corresponding type as uint8. A
+whole ARGB pixel is represented by a type called uint32, an unsigned integer
+consisting of 32 bits. In the code showing the behavior of the transformations,
+alpha value is codified in bits 31..24, red in bits 23..16, green in bits 15..8
+and blue in bits 7..0, but implementations of the format are free to use another
+representation internally.
+
+Broadly, a WebP lossless image contains header data, transform information and
+actual image data. Headers contain width and height of the image. A WebP
+lossless image can go through four different types of transformation before
+being entropy encoded. The transform information in the bitstream contains the
+data required to apply the respective inverse transforms.
+
+
+2 Nomenclature
+--------------
+
+ARGB
+: A pixel value consisting of alpha, red, green, and blue values.
+
+ARGB image
+: A two-dimensional array containing ARGB pixels.
+
+color cache
+: A small hash-addressed array to store recently used colors, to be able to
+ recall them with shorter codes.
+
+color indexing image
+: A one-dimensional image of colors that can be indexed using a small integer
+ (up to 256 within WebP lossless).
+
+color transform image
+: A two-dimensional subresolution image containing data about correlations of
+ color components.
+
+distance mapping
+: Changes LZ77 distances to have the smallest values for pixels in 2D
+ proximity.
+
+entropy image
+: A two-dimensional subresolution image indicating which entropy coding should
+ be used in a respective square in the image, i.e., each pixel is a meta
+ prefix code.
+
+prefix code
+: A classic way to do entropy coding where a smaller number of bits are used
+ for more frequent codes.
+
+LZ77
+: Dictionary-based sliding window compression algorithm that either emits
+ symbols or describes them as sequences of past symbols.
+
+meta prefix code
+: A small integer (up to 16 bits) that indexes an element in the meta prefix
+ table.
+
+predictor image
+: A two-dimensional subresolution image indicating which spatial predictor is
+ used for a particular square in the image.
+
+prefix coding
+: A way to entropy code larger integers that codes a few bits of the integer
+ using an entropy code and codifies the remaining bits raw. This allows for
+ the descriptions of the entropy codes to remain relatively small even when
+ the range of symbols is large.
+
+scan-line order
+: A processing order of pixels, left-to-right, top-to-bottom, starting from
+ the left-hand-top pixel, proceeding to the right. Once a row is completed,
+ continue from the left-hand column of the next row.
+
+3 RIFF Header
+-------------
+
+The beginning of the header has the RIFF container. This consists of the
+following 21 bytes:
+
+ 1. String "RIFF"
+ 2. A little-endian 32 bit value of the block length, the whole size
+ of the block controlled by the RIFF header. Normally this equals
+ the payload size (file size minus 8 bytes: 4 bytes for the 'RIFF'
+ identifier and 4 bytes for storing the value itself).
+ 3. String "WEBP" (RIFF container name).
+ 4. String "VP8L" (chunk tag for lossless encoded image data).
+ 5. A little-endian 32-bit value of the number of bytes in the
+ lossless stream.
+ 6. One byte signature 0x2f.
+
+The first 28 bits of the bitstream specify the width and height of the image.
+Width and height are decoded as 14-bit integers as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int image_width = ReadBits(14) + 1;
+int image_height = ReadBits(14) + 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 14-bit dynamics for image size limit the maximum size of a WebP lossless
+image to 16384✕16384 pixels.
+
+The alpha_is_used bit is a hint only, and should not impact decoding. It should
+be set to 0 when all alpha values are 255 in the picture, and 1 otherwise.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int alpha_is_used = ReadBits(1);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The version_number is a 3 bit code that must be set to 0. Any other value should
+be treated as an error. \[AMENDED\]
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int version_number = ReadBits(3);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+4 Transformations
+-----------------
+
+Transformations are reversible manipulations of the image data that can reduce
+the remaining symbolic entropy by modeling spatial and color correlations.
+Transformations can make the final compression more dense.
+
+An image can go through four types of transformation. A 1 bit indicates the
+presence of a transform. Each transform is allowed to be used only once. The
+transformations are used only for the main level ARGB image: the subresolution
+images have no transforms, not even the 0 bit indicating the end-of-transforms.
+
+Typically, an encoder would use these transforms to reduce the Shannon entropy
+in the residual image. Also, the transform data can be decided based on entropy
+minimization.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+while (ReadBits(1)) { // Transform present.
+ // Decode transform type.
+ enum TransformType transform_type = ReadBits(2);
+ // Decode transform data.
+ ...
+}
+
+// Decode actual image data (Section 4).
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a transform is present then the next two bits specify the transform type.
+There are four types of transforms.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+enum TransformType {
+ PREDICTOR_TRANSFORM = 0,
+ COLOR_TRANSFORM = 1,
+ SUBTRACT_GREEN_TRANSFORM = 2,
+ COLOR_INDEXING_TRANSFORM = 3,
+};
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The transform type is followed by the transform data. Transform data contains
+the information required to apply the inverse transform and depends on the
+transform type. Next we describe the transform data for different types.
+
+
+### 4.1 Predictor Transform
+
+The predictor transform can be used to reduce entropy by exploiting the fact
+that neighboring pixels are often correlated. In the predictor transform, the
+current pixel value is predicted from the pixels already decoded (in scan-line
+order) and only the residual value (actual - predicted) is encoded. The
+_prediction mode_ determines the type of prediction to use. We divide the image
+into squares and all the pixels in a square use the same prediction mode.
+
+The first 3 bits of prediction data define the block width and height in number
+of bits. The number of block columns, `block_xsize`, is used in indexing
+two-dimensionally.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int size_bits = ReadBits(3) + 2;
+int block_width = (1 << size_bits);
+int block_height = (1 << size_bits);
+#define DIV_ROUND_UP(num, den) ((num) + (den) - 1) / (den))
+int block_xsize = DIV_ROUND_UP(image_width, 1 << size_bits);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The transform data contains the prediction mode for each block of the image. All
+the `block_width * block_height` pixels of a block use same prediction mode. The
+prediction modes are treated as pixels of an image and encoded using the same
+techniques described in [Chapter 5](#image-data).
+
+For a pixel _x, y_, one can compute the respective filter block address by:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int block_index = (y >> size_bits) * block_xsize +
+ (x >> size_bits);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are 14 different prediction modes. In each prediction mode, the current
+pixel value is predicted from one or more neighboring pixels whose values are
+already known.
+
+We choose the neighboring pixels (TL, T, TR, and L) of the current pixel (P) as
+follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+O O O O O O O O O O O
+O O O O O O O O O O O
+O O O O TL T TR O O O O
+O O O O L P X X X X X
+X X X X X X X X X X X
+X X X X X X X X X X X
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+where TL means top-left, T top, TR top-right, L left pixel. At the time of
+predicting a value for P, all pixels O, TL, T, TR and L have already been
+processed, and pixel P and all pixels X are unknown.
+
+Given the above neighboring pixels, the different prediction modes are defined
+as follows.
+
+| Mode | Predicted value of each channel of the current pixel |
+| ------ | ------------------------------------------------------- |
+| 0 | 0xff000000 (represents solid black color in ARGB) |
+| 1 | L |
+| 2 | T |
+| 3 | TR |
+| 4 | TL |
+| 5 | Average2(Average2(L, TR), T) |
+| 6 | Average2(L, TL) |
+| 7 | Average2(L, T) |
+| 8 | Average2(TL, T) |
+| 9 | Average2(T, TR) |
+| 10 | Average2(Average2(L, TL), Average2(T, TR)) |
+| 11 | Select(L, T, TL) |
+| 12 | ClampAddSubtractFull(L, T, TL) |
+| 13 | ClampAddSubtractHalf(Average2(L, T), TL) |
+
+
+`Average2` is defined as follows for each ARGB component:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+uint8 Average2(uint8 a, uint8 b) {
+ return (a + b) / 2;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Select predictor is defined as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+uint32 Select(uint32 L, uint32 T, uint32 TL) {
+ // L = left pixel, T = top pixel, TL = top left pixel.
+
+ // ARGB component estimates for prediction.
+ int pAlpha = ALPHA(L) + ALPHA(T) - ALPHA(TL);
+ int pRed = RED(L) + RED(T) - RED(TL);
+ int pGreen = GREEN(L) + GREEN(T) - GREEN(TL);
+ int pBlue = BLUE(L) + BLUE(T) - BLUE(TL);
+
+ // Manhattan distances to estimates for left and top pixels.
+ int pL = abs(pAlpha - ALPHA(L)) + abs(pRed - RED(L)) +
+ abs(pGreen - GREEN(L)) + abs(pBlue - BLUE(L));
+ int pT = abs(pAlpha - ALPHA(T)) + abs(pRed - RED(T)) +
+ abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T));
+
+ // Return either left or top, the one closer to the prediction.
+ if (pL < pT) { // \[AMENDED\]
+ return L;
+ } else {
+ return T;
+ }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The functions `ClampAddSubtractFull` and `ClampAddSubtractHalf` are performed
+for each ARGB component as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Clamp the input value between 0 and 255.
+int Clamp(int a) {
+ return (a < 0) ? 0 : (a > 255) ? 255 : a;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int ClampAddSubtractFull(int a, int b, int c) {
+ return Clamp(a + b - c);
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int ClampAddSubtractHalf(int a, int b) {
+ return Clamp(a + (a - b) / 2);
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are special handling rules for some border pixels. If there is a
+prediction transform, regardless of the mode \[0..13\] for these pixels, the
+predicted value for the left-topmost pixel of the image is 0xff000000, L-pixel
+for all pixels on the top row, and T-pixel for all pixels on the leftmost
+column.
+
+\[AMENDED2\] Addressing the TR-pixel for pixels on the rightmost column is
+exceptional. The pixels on the rightmost column are predicted by using the modes
+\[0..13\] just like pixels not on the border, but the leftmost pixel on the same
+row as the current pixel is instead used as the TR-pixel.
+
+
+### 4.2 Color Transform
+
+\[AMENDED2\]
+
+The goal of the color transform is to decorrelate the R, G and B values of each
+pixel. The color transform keeps the green (G) value as it is, transforms red
+(R) based on green and transforms blue (B) based on green and then based on red.
+
+As is the case for the predictor transform, first the image is divided into
+blocks and the same transform mode is used for all the pixels in a block. For
+each block there are three types of color transform elements.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct {
+ uint8 green_to_red;
+ uint8 green_to_blue;
+ uint8 red_to_blue;
+} ColorTransformElement;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The actual color transformation is done by defining a color transform delta. The
+color transform delta depends on the `ColorTransformElement`, which is the same
+for all the pixels in a particular block. The delta is subtracted during the
+color transform. The inverse color transform then is just adding those deltas.
+
+The color transform function is defined as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void ColorTransform(uint8 red, uint8 blue, uint8 green,
+ ColorTransformElement *trans,
+ uint8 *new_red, uint8 *new_blue) {
+ // Transformed values of red and blue components
+ int tmp_red = red;
+ int tmp_blue = blue;
+
+ // Applying the transform is just subtracting the transform deltas
+ tmp_red -= ColorTransformDelta(trans->green_to_red_, green);
+ tmp_blue -= ColorTransformDelta(trans->green_to_blue_, green);
+ tmp_blue -= ColorTransformDelta(trans->red_to_blue_, red);
+
+ *new_red = tmp_red & 0xff;
+ *new_blue = tmp_blue & 0xff;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`ColorTransformDelta` is computed using a signed 8-bit integer representing a
+3.5-fixed-point number, and a signed 8-bit RGB color channel (c) \[-128..127\]
+and is defined as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int8 ColorTransformDelta(int8 t, int8 c) {
+ return (t * c) >> 5;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A conversion from the 8-bit unsigned representation (uint8) to the 8-bit signed
+one (int8) is required before calling `ColorTransformDelta()`. It should be
+performed using 8-bit two's complement (that is: uint8 range \[128..255\] is
+mapped to the \[-128..-1\] range of its converted int8 value).
+
+The multiplication is to be done using more precision (with at least 16-bit
+dynamics). The sign extension property of the shift operation does not matter
+here: only the lowest 8 bits are used from the result, and there the sign
+extension shifting and unsigned shifting are consistent with each other.
+
+Now we describe the contents of color transform data so that decoding can apply
+the inverse color transform and recover the original red and blue values. The
+first 3 bits of the color transform data contain the width and height of the
+image block in number of bits, just like the predictor transform:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int size_bits = ReadBits(3) + 2;
+int block_width = 1 << size_bits;
+int block_height = 1 << size_bits;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The remaining part of the color transform data contains `ColorTransformElement`
+instances corresponding to each block of the image. `ColorTransformElement`
+instances are treated as pixels of an image and encoded using the methods
+described in [Chapter 5](#image-data).
+
+During decoding, `ColorTransformElement` instances of the blocks are decoded and
+the inverse color transform is applied on the ARGB values of the pixels. As
+mentioned earlier, that inverse color transform is just adding
+`ColorTransformElement` values to the red and blue channels. \[AMENDED3\]
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void InverseTransform(uint8 red, uint8 green, uint8 blue,
+ ColorTransformElement *trans,
+ uint8 *new_red, uint8 *new_blue) {
+ // Transformed values of red and blue components
+ int tmp_red = red;
+ int tmp_blue = blue;
+
+ // Applying the inverse transform is just adding the
+ // color transform deltas
+ tmp_red += ColorTransformDelta(trans->green_to_red, green);
+ tmp_blue += ColorTransformDelta(trans->green_to_blue, green);
+ tmp_blue +=
+ ColorTransformDelta(trans->red_to_blue, tmp_red & 0xff);
+
+ *new_red = tmp_red & 0xff;
+ *new_blue = tmp_blue & 0xff;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+### 4.3 Subtract Green Transform
+
+The subtract green transform subtracts green values from red and blue values of
+each pixel. When this transform is present, the decoder needs to add the green
+value to both red and blue. There is no data associated with this transform. The
+decoder applies the inverse transform as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
+ *red = (*red + green) & 0xff;
+ *blue = (*blue + green) & 0xff;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This transform is redundant as it can be modeled using the color transform, but
+it is still often useful. Since it can extend the dynamics of the color
+transform and there is no additional data here, the subtract green transform can
+be coded using fewer bits than a full-blown color transform.
+
+
+### 4.4 Color Indexing Transform
+
+If there are not many unique pixel values, it may be more efficient to create a
+color index array and replace the pixel values by the array's indices. The color
+indexing transform achieves this. (In the context of WebP lossless, we
+specifically do not call this a palette transform because a similar but more
+dynamic concept exists in WebP lossless encoding: color cache).
+
+The color indexing transform checks for the number of unique ARGB values in the
+image. If that number is below a threshold (256), it creates an array of those
+ARGB values, which is then used to replace the pixel values with the
+corresponding index: the green channel of the pixels are replaced with the
+index; all alpha values are set to 255; all red and blue values to 0.
+
+The transform data contains color table size and the entries in the color table.
+The decoder reads the color indexing transform data as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 8 bit value for color table size
+int color_table_size = ReadBits(8) + 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The color table is stored using the image storage format itself. The color table
+can be obtained by reading an image, without the RIFF header, image size, and
+transforms, assuming a height of one pixel and a width of `color_table_size`.
+The color table is always subtraction-coded to reduce image entropy. The deltas
+of palette colors contain typically much less entropy than the colors
+themselves, leading to significant savings for smaller images. In decoding,
+every final color in the color table can be obtained by adding the previous
+color component values by each ARGB component separately, and storing the least
+significant 8 bits of the result.
+
+The inverse transform for the image is simply replacing the pixel values (which
+are indices to the color table) with the actual color table values. The indexing
+is done based on the green component of the ARGB color.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Inverse transform
+argb = color_table[GREEN(argb)];
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the index is equal or larger than `color_table_size`, the argb color value
+should be set to 0x00000000 (transparent black). \[AMENDED\]
+
+When the color table is small (equal to or less than 16 colors), several pixels
+are bundled into a single pixel. The pixel bundling packs several (2, 4, or 8)
+pixels into a single pixel, reducing the image width respectively. Pixel
+bundling allows for a more efficient joint distribution entropy coding of
+neighboring pixels, and gives some arithmetic coding-like benefits to the
+entropy code, but it can only be used when there are 16 or fewer unique values.
+
+`color_table_size` specifies how many pixels are combined:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int width_bits;
+if (color_table_size <= 2) {
+ width_bits = 3;
+} else if (color_table_size <= 4) {
+ width_bits = 2;
+} else if (color_table_size <= 16) {
+ width_bits = 1;
+} else {
+ width_bits = 0;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`width_bits` has a value of 0, 1, 2 or 3. A value of 0 indicates no pixel
+bundling is to be done for the image. A value of 1 indicates that two pixels are
+combined, and each pixel has a range of \[0..15\]. A value of 2 indicates that
+four pixels are combined, and each pixel has a range of \[0..3\]. A value of 3
+indicates that eight pixels are combined and each pixel has a range of \[0..1\],
+i.e., a binary value.
+
+The values are packed into the green component as follows:
+
+ * `width_bits` = 1: for every x value where x ≡ 0 (mod 2), a green
+ value at x is positioned into the 4 least-significant bits of the
+ green value at x / 2, a green value at x + 1 is positioned into the
+ 4 most-significant bits of the green value at x / 2.
+ * `width_bits` = 2: for every x value where x ≡ 0 (mod 4), a green
+ value at x is positioned into the 2 least-significant bits of the
+ green value at x / 4, green values at x + 1 to x + 3 are positioned in order
+ to the more significant bits of the green value at x / 4.
+ * `width_bits` = 3: for every x value where x ≡ 0 (mod 8), a green
+ value at x is positioned into the least-significant bit of the green
+ value at x / 8, green values at x + 1 to x + 7 are positioned in order to
+ the more significant bits of the green value at x / 8.
+
+
+5 Image Data
+------------
+
+Image data is an array of pixel values in scan-line order.
+
+### 5.1 Roles of Image Data
+
+We use image data in five different roles:
+
+ 1. ARGB image: Stores the actual pixels of the image.
+ 1. Entropy image: Stores the
+ [meta prefix codes](#decoding-of-meta-prefix-codes). The red and green
+ components of a pixel define the meta prefix code used in a particular
+ block of the ARGB image.
+ 1. Predictor image: Stores the metadata for
+ [Predictor Transform](#predictor-transform). The green component of a pixel
+ defines which of the 14 predictors is used within a particular block of the
+ ARGB image.
+ 1. Color transform image. It is created by `ColorTransformElement` values
+ (defined in [Color Transform](#color-transform)) for different blocks of
+ the image. Each `ColorTransformElement` `'cte'` is treated as a pixel whose
+ alpha component is `255`, red component is `cte.red_to_blue`, green
+ component is `cte.green_to_blue` and blue component is `cte.green_to_red`.
+ 1. Color indexing image: An array of size `color_table_size` (up to 256
+ ARGB values) storing the metadata for the
+ [Color Indexing Transform](#color-indexing-transform). This is stored as an
+ image of width `color_table_size` and height `1`.
+
+### 5.2 Encoding of Image Data
+
+The encoding of image data is independent of its role.
+
+The image is first divided into a set of fixed-size blocks (typically 16x16
+blocks). Each of these blocks are modeled using their own entropy codes. Also,
+several blocks may share the same entropy codes.
+
+**Rationale:** Storing an entropy code incurs a cost. This cost can be minimized
+if statistically similar blocks share an entropy code, thereby storing that code
+only once. For example, an encoder can find similar blocks by clustering them
+using their statistical properties, or by repeatedly joining a pair of randomly
+selected clusters when it reduces the overall amount of bits needed to encode
+the image.
+
+Each pixel is encoded using one of the three possible methods:
+
+ 1. Prefix coded literal: each channel (green, red, blue and alpha) is
+ entropy-coded independently;
+ 2. LZ77 backward reference: a sequence of pixels are copied from elsewhere
+ in the image; or
+ 3. Color cache code: using a short multiplicative hash code (color cache
+ index) of a recently seen color.
+
+The following subsections describe each of these in detail.
+
+#### 5.2.1 Prefix Coded Literals
+
+The pixel is stored as prefix coded values of green, red, blue and alpha (in
+that order). See [this section](#decoding-entropy-coded-image-data) for details.
+
+#### 5.2.2 LZ77 Backward Reference
+
+Backward references are tuples of _length_ and _distance code_:
+
+ * Length indicates how many pixels in scan-line order are to be copied.
+ * Distance code is a number indicating the position of a previously seen
+ pixel, from which the pixels are to be copied. The exact mapping is
+ described [below](#distance-mapping).
+
+The length and distance values are stored using **LZ77 prefix coding**.
+
+LZ77 prefix coding divides large integer values into two parts: the _prefix
+code_ and the _extra bits_: the prefix code is stored using an entropy code,
+while the extra bits are stored as they are (without an entropy code).
+
+**Rationale**: This approach reduces the storage requirement for the entropy
+code. Also, large values are usually rare, and so extra bits would be used for
+very few values in the image. Thus, this approach results in better compression
+overall.
+
+The following table denotes the prefix codes and extra bits used for storing
+different ranges of values.
+
+Note: The maximum backward reference length is limited to 4096. Hence, only the
+first 24 prefix codes (with the respective extra bits) are meaningful for length
+values. For distance values, however, all the 40 prefix codes are valid.
+
+| Value range | Prefix code | Extra bits |
+| --------------- | ----------- | ---------- |
+| 1 | 0 | 0 |
+| 2 | 1 | 0 |
+| 3 | 2 | 0 |
+| 4 | 3 | 0 |
+| 5..6 | 4 | 1 |
+| 7..8 | 5 | 1 |
+| 9..12 | 6 | 2 |
+| 13..16 | 7 | 2 |
+| ... | ... | ... |
+| 3072..4096 | 23 | 10 |
+| ... | ... | ... |
+| 524289..786432 | 38 | 18 |
+| 786433..1048576 | 39 | 18 |
+
+The pseudocode to obtain a (length or distance) value from the prefix code is as
+follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+if (prefix_code < 4) {
+ return prefix_code + 1;
+}
+int extra_bits = (prefix_code - 2) >> 1;
+int offset = (2 + (prefix_code & 1)) << extra_bits;
+return offset + ReadBits(extra_bits) + 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Distance Mapping:**
+{:#distance-mapping}
+
+As noted previously, a distance code is a number indicating the position of a
+previously seen pixel, from which the pixels are to be copied. This subsection
+defines the mapping between a distance code and the position of a previous
+pixel.
+
+Distance codes larger than 120 denote the pixel-distance in scan-line order,
+offset by 120.
+
+The smallest distance codes \[1..120\] are special, and are reserved for a close
+neighborhood of the current pixel. This neighborhood consists of 120 pixels:
+
+ * Pixels that are 1 to 7 rows above the current pixel, and are up to 8 columns
+ to the left or up to 7 columns to the right of the current pixel. \[Total
+ such pixels = `7 * (8 + 1 + 7) = 112`\].
+ * Pixels that are in same row as the current pixel, and are up to 8 columns to
+ the left of the current pixel. \[`8` such pixels\].
+
+The mapping between distance code `i` and the neighboring pixel offset
+`(xi, yi)` is as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(0, 1), (1, 0), (1, 1), (-1, 1), (0, 2), (2, 0), (1, 2),
+(-1, 2), (2, 1), (-2, 1), (2, 2), (-2, 2), (0, 3), (3, 0),
+(1, 3), (-1, 3), (3, 1), (-3, 1), (2, 3), (-2, 3), (3, 2),
+(-3, 2), (0, 4), (4, 0), (1, 4), (-1, 4), (4, 1), (-4, 1),
+(3, 3), (-3, 3), (2, 4), (-2, 4), (4, 2), (-4, 2), (0, 5),
+(3, 4), (-3, 4), (4, 3), (-4, 3), (5, 0), (1, 5), (-1, 5),
+(5, 1), (-5, 1), (2, 5), (-2, 5), (5, 2), (-5, 2), (4, 4),
+(-4, 4), (3, 5), (-3, 5), (5, 3), (-5, 3), (0, 6), (6, 0),
+(1, 6), (-1, 6), (6, 1), (-6, 1), (2, 6), (-2, 6), (6, 2),
+(-6, 2), (4, 5), (-4, 5), (5, 4), (-5, 4), (3, 6), (-3, 6),
+(6, 3), (-6, 3), (0, 7), (7, 0), (1, 7), (-1, 7), (5, 5),
+(-5, 5), (7, 1), (-7, 1), (4, 6), (-4, 6), (6, 4), (-6, 4),
+(2, 7), (-2, 7), (7, 2), (-7, 2), (3, 7), (-3, 7), (7, 3),
+(-7, 3), (5, 6), (-5, 6), (6, 5), (-6, 5), (8, 0), (4, 7),
+(-4, 7), (7, 4), (-7, 4), (8, 1), (8, 2), (6, 6), (-6, 6),
+(8, 3), (5, 7), (-5, 7), (7, 5), (-7, 5), (8, 4), (6, 7),
+(-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6),
+(8, 7)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For example, the distance code `1` indicates an offset of `(0, 1)` for the
+neighboring pixel, that is, the pixel above the current pixel (0 pixel
+difference in the X-direction and 1 pixel difference in the Y-direction).
+Similarly, the distance code `3` indicates the left-top pixel.
+
+The decoder can convert a distance code `i` to a scan-line order distance `dist`
+as follows:
+
+\[AMENDED3\]
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(xi, yi) = distance_map[i - 1]
+dist = xi + yi * xsize
+if (dist < 1) {
+ dist = 1
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+where `distance_map` is the mapping noted above and `xsize` is the width of the
+image in pixels.
+
+
+#### 5.2.3 Color Cache Coding
+{:#color-cache-code}
+
+Color cache stores a set of colors that have been recently used in the image.
+
+**Rationale:** This way, the recently used colors can sometimes be referred to
+more efficiently than emitting them using the other two methods (described in
+[5.2.1](#prefix-coded-literals) and [5.2.2](#lz77-backward-reference)).
+
+Color cache codes are stored as follows. First, there is a 1-bit value that
+indicates if the color cache is used. If this bit is 0, no color cache codes
+exist, and they are not transmitted in the prefix code that decodes the green
+symbols and the length prefix codes. However, if this bit is 1, the color cache
+size is read next:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int color_cache_code_bits = ReadBits(4);
+int color_cache_size = 1 << color_cache_code_bits;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`color_cache_code_bits` defines the size of the color_cache by (1 <<
+`color_cache_code_bits`). The range of allowed values for
+`color_cache_code_bits` is \[1..11\]. Compliant decoders must indicate a
+corrupted bitstream for other values.
+
+A color cache is an array of size `color_cache_size`. Each entry stores one ARGB
+color. Colors are looked up by indexing them by (0x1e35a7bd * `color`) >> (32 -
+`color_cache_code_bits`). Only one lookup is done in a color cache; there is no
+conflict resolution.
+
+In the beginning of decoding or encoding of an image, all entries in all color
+cache values are set to zero. The color cache code is converted to this color at
+decoding time. The state of the color cache is maintained by inserting every
+pixel, be it produced by backward referencing or as literals, into the cache in
+the order they appear in the stream.
+
+
+6 Entropy Code
+--------------
+
+### 6.1 Overview
+
+Most of the data is coded using a [canonical prefix code][canonical_huff].
+Hence, the codes are transmitted by sending the _prefix code lengths_, as
+opposed to the actual _prefix codes_.
+
+In particular, the format uses **spatially-variant prefix coding**. In other
+words, different blocks of the image can potentially use different entropy
+codes.
+
+**Rationale**: Different areas of the image may have different characteristics.
+So, allowing them to use different entropy codes provides more flexibility and
+potentially better compression.
+
+### 6.2 Details
+
+The encoded image data consists of several parts:
+
+ 1. Decoding and building the prefix codes \[AMENDED2\]
+ 1. Meta prefix codes
+ 1. Entropy-coded image data
+
+#### 6.2.1 Decoding and Building the Prefix Codes
+
+There are several steps in decoding the prefix codes.
+
+**Decoding the Code Lengths:**
+{:#decoding-the-code-lengths}
+
+This section describes how to read the prefix code lengths from the bitstream.
+
+The prefix code lengths can be coded in two ways. The method used is specified
+by a 1-bit value.
+
+ * If this bit is 1, it is a _simple code length code_, and
+ * If this bit is 0, it is a _normal code length code_.
+
+In both cases, there can be unused code lengths that are still part of the
+stream. This may be inefficient, but it is allowed by the format.
+
+**(i) Simple Code Length Code:**
+
+\[AMENDED2\]
+
+This variant is used in the special case when only 1 or 2 prefix symbols are in
+the range \[0..255\] with code length `1`. All other prefix code lengths are
+implicitly zeros.
+
+The first bit indicates the number of symbols:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int num_symbols = ReadBits(1) + 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Following are the symbol values.
+
+This first symbol is coded using 1 or 8 bits depending on the value of
+`is_first_8bits`. The range is \[0..1\] or \[0..255\], respectively. The second
+symbol, if present, is always assumed to be in the range \[0..255\] and coded
+using 8 bits.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int is_first_8bits = ReadBits(1);
+symbol0 = ReadBits(1 + 7 * is_first_8bits);
+code_lengths[symbol0] = 1;
+if (num_symbols == 2) {
+ symbol1 = ReadBits(8);
+ code_lengths[symbol1] = 1;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Note:** Another special case is when _all_ prefix code lengths are _zeros_ (an
+empty prefix code). For example, a prefix code for distance can be empty if
+there are no backward references. Similarly, prefix codes for alpha, red, and
+blue can be empty if all pixels within the same meta prefix code are produced
+using the color cache. However, this case doesn't need special handling, as
+empty prefix codes can be coded as those containing a single symbol `0`.
+
+**(ii) Normal Code Length Code:**
+
+The code lengths of the prefix code fit in 8 bits and are read as follows.
+First, `num_code_lengths` specifies the number of code lengths.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int num_code_lengths = 4 + ReadBits(4);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If `num_code_lengths` is > 19, the bitstream is invalid. \[AMENDED3\]
+
+The code lengths are themselves encoded using prefix codes: lower level code
+lengths, `code_length_code_lengths`, first have to be read. The rest of those
+`code_length_code_lengths` (according to the order in `kCodeLengthCodeOrder`)
+are zeros.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int kCodeLengthCodes = 19;
+int kCodeLengthCodeOrder[kCodeLengthCodes] = {
+ 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+int code_length_code_lengths[kCodeLengthCodes] = { 0 }; // All zeros
+for (i = 0; i < num_code_lengths; ++i) {
+ code_length_code_lengths[kCodeLengthCodeOrder[i]] = ReadBits(3);
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Next, if `ReadBits(1) == 0`, the maximum number of different read symbols is
+`num_code_lengths`. Otherwise, it is defined as:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int length_nbits = 2 + 2 * ReadBits(3);
+int max_symbol = 2 + ReadBits(length_nbits);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A prefix table is then built from `code_length_code_lengths` and used to read up
+to `max_symbol` code lengths.
+
+ * Code \[0..15\] indicates literal code lengths.
+ * Value 0 means no symbols have been coded.
+ * Values \[1..15\] indicate the bit length of the respective code.
+ * Code 16 repeats the previous non-zero value \[3..6\] times, i.e.,
+ `3 + ReadBits(2)` times. If code 16 is used before a non-zero
+ value has been emitted, a value of 8 is repeated.
+ * Code 17 emits a streak of zeros \[3..10\], i.e., `3 + ReadBits(3)`
+ times.
+ * Code 18 emits a streak of zeros of length \[11..138\], i.e.,
+ `11 + ReadBits(7)` times.
+
+Once code lengths are read, a prefix code for each symbol type (A, R, G, B,
+distance) is formed using their respective alphabet sizes:
+
+ * G channel: 256 + 24 + `color_cache_size`
+ * other literals (A,R,B): 256
+ * distance code: 40
+
+#### 6.2.2 Decoding of Meta Prefix Codes
+
+As noted earlier, the format allows the use of different prefix codes for
+different blocks of the image. _Meta prefix codes_ are indexes identifying which
+prefix codes to use in different parts of the image.
+
+Meta prefix codes may be used _only_ when the image is being used in the
+[role](#roles-of-image-data) of an _ARGB image_.
+
+There are two possibilities for the meta prefix codes, indicated by a 1-bit
+value:
+
+ * If this bit is zero, there is only one meta prefix code used everywhere in
+ the image. No more data is stored.
+ * If this bit is one, the image uses multiple meta prefix codes. These meta
+ prefix codes are stored as an _entropy image_ (described below).
+
+**Entropy image:**
+
+The entropy image defines which prefix codes are used in different parts of the
+image, as described below.
+
+The first 3-bits contain the `prefix_bits` value. The dimensions of the entropy
+image are derived from `prefix_bits`.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int prefix_bits = ReadBits(3) + 2;
+int prefix_xsize = DIV_ROUND_UP(xsize, 1 << prefix_bits);
+int prefix_ysize = DIV_ROUND_UP(ysize, 1 << prefix_bits);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+where `DIV_ROUND_UP` is as defined [earlier](#predictor-transform).
+
+The next bits contain an entropy image of width `prefix_xsize` and height
+`prefix_ysize`.
+
+**Interpretation of Meta Prefix Codes:**
+
+For any given pixel (x, y), there is a set of five prefix codes associated with
+it. These codes are (in bitstream order):
+
+ * **Prefix code #1**: used for green channel, backward-reference length and
+ color cache.
+ * **Prefix code #2, #3 and #4**: used for red, blue and alpha channels
+ respectively.
+ * **Prefix code #5**: used for backward-reference distance.
+
+From here on, we refer to this set as a **prefix code group**.
+
+The number of prefix code groups in the ARGB image can be obtained by finding
+the _largest meta prefix code_ from the entropy image:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int num_prefix_groups = max(entropy image) + 1;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+where `max(entropy image)` indicates the largest prefix code stored in the
+entropy image.
+
+As each prefix code group contains five prefix codes, the total number of prefix
+codes is:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int num_prefix_codes = 5 * num_prefix_groups;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Given a pixel (x, y) in the ARGB image, we can obtain the corresponding prefix
+codes to be used as follows:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int position =
+ (y >> prefix_bits) * prefix_xsize + (x >> prefix_bits);
+int meta_prefix_code = (entropy_image[pos] >> 8) & 0xffff;
+PrefixCodeGroup prefix_group = prefix_code_groups[meta_prefix_code];
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+where, we have assumed the existence of `PrefixCodeGroup` structure, which
+represents a set of five prefix codes. Also, `prefix_code_groups` is an array of
+`PrefixCodeGroup` (of size `num_prefix_groups`).
+
+The decoder then uses prefix code group `prefix_group` to decode the pixel
+(x, y) as explained in the [next section](#decoding-entropy-coded-image-data).
+
+#### 6.2.3 Decoding Entropy-coded Image Data
+
+\[AMENDED2\]
+
+For the current position (x, y) in the image, the decoder first identifies the
+corresponding prefix code group (as explained in the last section). Given the
+prefix code group, the pixel is read and decoded as follows:
+
+Read the next symbol S from the bitstream using prefix code #1. Note that S is
+any integer in the range `0` to
+`(256 + 24 + ` [`color_cache_size`](#color-cache-code)` - 1)`.
+
+The interpretation of S depends on its value:
+
+ 1. if S < 256
+ 1. Use S as the green component.
+ 1. Read red from the bitstream using prefix code #2.
+ 1. Read blue from the bitstream using prefix code #3.
+ 1. Read alpha from the bitstream using prefix code #4.
+ 1. if S >= 256 && S < 256 + 24
+ 1. Use S - 256 as a length prefix code.
+ 1. Read extra bits for length from the bitstream.
+ 1. Determine backward-reference length L from length prefix code and the
+ extra bits read.
+ 1. Read distance prefix code from the bitstream using prefix code #5.
+ 1. Read extra bits for distance from the bitstream.
+ 1. Determine backward-reference distance D from distance prefix code and
+ the extra bits read.
+ 1. Copy the L pixels (in scan-line order) from the sequence of pixels
+ prior to them by D pixels.
+ 1. if S >= 256 + 24
+ 1. Use S - (256 + 24) as the index into the color cache.
+ 1. Get ARGB color from the color cache at that index.
+
+
+7 Overall Structure of the Format
+---------------------------------
+
+Below is a view into the format in Augmented Backus-Naur Form ([ABNF]). It does
+not cover all details. End-of-image (EOI) is only implicitly coded into the
+number of pixels (xsize * ysize).
+
+
+#### 7.1 Basic Structure
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+format = RIFF-header image-size image-stream
+RIFF-header = "RIFF" 4OCTET "WEBP" "VP8L" 4OCTET %x2F
+image-size = 14BIT 14BIT ; width - 1, height - 1
+image-stream = optional-transform spatially-coded-image
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+#### 7.2 Structure of Transforms
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+optional-transform = (%b1 transform optional-transform) / %b0
+transform = predictor-tx / color-tx / subtract-green-tx
+transform =/ color-indexing-tx
+
+predictor-tx = %b00 predictor-image
+predictor-image = 3BIT ; sub-pixel code
+ entropy-coded-image
+
+color-tx = %b01 color-image
+color-image = 3BIT ; sub-pixel code
+ entropy-coded-image
+
+subtract-green-tx = %b10
+
+color-indexing-tx = %b11 color-indexing-image
+color-indexing-image = 8BIT ; color count
+ entropy-coded-image
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+#### 7.3 Structure of the Image Data
+
+\[AMENDED2\]
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+spatially-coded-image = color-cache-info meta-prefix data
+entropy-coded-image = color-cache-info data
+
+color-cache-info = %b0
+color-cache-info =/ (%b1 4BIT) ; 1 followed by color cache size
+
+meta-prefix = %b0 / (%b1 entropy-image)
+
+data = prefix-codes lz77-coded-image
+entropy-image = 3BIT ; subsample value
+ entropy-coded-image
+
+prefix-codes = prefix-code-group *prefix-codes
+prefix-code-group =
+ 5prefix-code ; See "Interpretation of Meta Prefix Codes" to
+ ; understand what each of these five prefix
+ ; codes are for.
+
+prefix-code = simple-prefix-code / normal-prefix-code
+simple-prefix-code = ; see "Simple Code Length Code" for details
+normal-prefix-code = code-length-code encoded-code-lengths
+code-length-code = ; see section "Normal Code Length Code"
+
+lz77-coded-image =
+ *((argb-pixel / lz77-copy / color-cache-code) lz77-coded-image)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A possible example sequence:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RIFF-header image-size %b1 subtract-green-tx
+%b1 predictor-tx %b0 color-cache-info
+%b0 prefix-codes lz77-coded-image
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[ABNF]: https://www.rfc-editor.org/rfc/rfc5234
+[canonical_huff]: https://en.wikipedia.org/wiki/Canonical_Huffman_code
diff --git a/examples/Android.mk b/examples/Android.mk
new file mode 100644
index 0000000..ba3c458
--- /dev/null
+++ b/examples/Android.mk
@@ -0,0 +1,114 @@
+# Ignore this file during non-NDK builds.
+ifdef NDK_ROOT
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+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
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+include $(BUILD_EXECUTABLE)
+endif # NDK_ROOT
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..72aa9f9
--- /dev/null
+++ b/examples/Makefile.am
@@ -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) -I$(top_srcdir)
+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
diff --git a/examples/anim_diff.c b/examples/anim_diff.c
new file mode 100644
index 0000000..7ffabc8
--- /dev/null
+++ b/examples/anim_diff.c
@@ -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);
+}
diff --git a/examples/anim_dump.c b/examples/anim_dump.c
new file mode 100644
index 0000000..e447338
--- /dev/null
+++ b/examples/anim_dump.c
@@ -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);
+}
diff --git a/examples/anim_util.c b/examples/anim_util.c
new file mode 100644
index 0000000..cf7da4c
--- /dev/null
+++ b/examples/anim_util.c
@@ -0,0 +1,782 @@
+// 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*)WebPMalloc((size_t)total_size);
+ frames = (DecodedFrame*)WebPMalloc((size_t)total_frame_size);
+
+ if (mem == NULL || frames == NULL) {
+ WebPFree(mem);
+ WebPFree(frames);
+ return 0;
+ }
+ WebPFree(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) {
+ WebPFree(image->raw_mem);
+ WebPFree(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*)WebPMalloc(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);
+ WebPFree(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)) goto End;
+
+ // 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 (0xffu << 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.
+ if (!AllocateFrames(image, frame_count)) {
+ DGifCloseFile(gif, NULL);
+ return 0;
+ }
+
+ 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();
+}
diff --git a/examples/anim_util.h b/examples/anim_util.h
new file mode 100644
index 0000000..574e032
--- /dev/null
+++ b/examples/anim_util.h
@@ -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_
diff --git a/examples/cwebp.c b/examples/cwebp.c
new file mode 100644
index 0000000..9adb31e
--- /dev/null
+++ b/examples/cwebp.c
@@ -0,0 +1,1246 @@
+// 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 command line calling the WebPEncode function.
+// Encodes a raw .YUV into WebP bitstream
+//
+// 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_dec.h"
+#include "../imageio/imageio_util.h"
+#include "../imageio/webpdec.h"
+#include "./stopwatch.h"
+#include "./unicode.h"
+#include "sharpyuv/sharpyuv.h"
+#include "webp/encode.h"
+
+#ifndef WEBP_DLL
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void* VP8GetCPUInfo; // opaque forward declaration.
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // WEBP_DLL
+
+//------------------------------------------------------------------------------
+
+static int verbose = 0;
+
+static int ReadYUV(const uint8_t* const data, size_t data_size,
+ WebPPicture* const pic) {
+ const int use_argb = pic->use_argb;
+ const int uv_width = (pic->width + 1) / 2;
+ const int uv_height = (pic->height + 1) / 2;
+ const int y_plane_size = pic->width * pic->height;
+ const int uv_plane_size = uv_width * uv_height;
+ const size_t expected_data_size = y_plane_size + 2 * uv_plane_size;
+
+ if (data_size != expected_data_size) {
+ fprintf(stderr,
+ "input data doesn't have the expected size (%d instead of %d)\n",
+ (int)data_size, (int)expected_data_size);
+ return 0;
+ }
+
+ pic->use_argb = 0;
+ if (!WebPPictureAlloc(pic)) return 0;
+ ImgIoUtilCopyPlane(data, pic->width, pic->y, pic->y_stride,
+ pic->width, pic->height);
+ ImgIoUtilCopyPlane(data + y_plane_size, uv_width,
+ pic->u, pic->uv_stride, uv_width, uv_height);
+ ImgIoUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width,
+ pic->v, pic->uv_stride, uv_width, uv_height);
+ return use_argb ? WebPPictureYUVAToARGB(pic) : 1;
+}
+
+#ifdef HAVE_WINCODEC_H
+
+static int ReadPicture(const char* const filename, WebPPicture* const pic,
+ int keep_alpha, Metadata* const metadata) {
+ int ok = 0;
+ const uint8_t* data = NULL;
+ size_t data_size = 0;
+ if (pic->width != 0 && pic->height != 0) {
+ ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ ok = ok && ReadYUV(data, data_size, pic);
+ } else {
+ // If no size specified, try to decode it using WIC.
+ ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
+ if (!ok) {
+ ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata);
+ }
+ }
+ if (!ok) {
+ WFPRINTF(stderr, "Error! Could not process file %s\n",
+ (const W_CHAR*)filename);
+ }
+ WebPFree((void*)data);
+ return ok;
+}
+
+#else // !HAVE_WINCODEC_H
+
+static int ReadPicture(const char* const filename, WebPPicture* const pic,
+ int keep_alpha, Metadata* const metadata) {
+ const uint8_t* data = NULL;
+ size_t data_size = 0;
+ int ok = 0;
+
+ ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ if (!ok) goto End;
+
+ if (pic->width == 0 || pic->height == 0) {
+ WebPImageReader reader = WebPGuessImageReader(data, data_size);
+ ok = reader(data, data_size, pic, keep_alpha, metadata);
+ } else {
+ // If image size is specified, infer it as YUV format.
+ ok = ReadYUV(data, data_size, pic);
+ }
+ End:
+ if (!ok) {
+ WFPRINTF(stderr, "Error! Could not process file %s\n",
+ (const W_CHAR*)filename);
+ }
+ WebPFree((void*)data);
+ return ok;
+}
+
+#endif // !HAVE_WINCODEC_H
+
+static void AllocExtraInfo(WebPPicture* const pic) {
+ const int mb_w = (pic->width + 15) / 16;
+ const int mb_h = (pic->height + 15) / 16;
+ pic->extra_info =
+ (uint8_t*)WebPMalloc(mb_w * mb_h * sizeof(*pic->extra_info));
+}
+
+static void PrintByteCount(const int bytes[4], int total_size,
+ int* const totals) {
+ int s;
+ int total = 0;
+ for (s = 0; s < 4; ++s) {
+ fprintf(stderr, "| %7d ", bytes[s]);
+ total += bytes[s];
+ if (totals) totals[s] += bytes[s];
+ }
+ fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size);
+}
+
+static void PrintPercents(const int counts[4]) {
+ int s;
+ const int total = counts[0] + counts[1] + counts[2] + counts[3];
+ for (s = 0; s < 4; ++s) {
+ fprintf(stderr, "| %3d%%", (int)(100. * counts[s] / total + .5));
+ }
+ fprintf(stderr, "| %7d\n", total);
+}
+
+static void PrintValues(const int values[4]) {
+ int s;
+ for (s = 0; s < 4; ++s) {
+ fprintf(stderr, "| %7d ", values[s]);
+ }
+ fprintf(stderr, "|\n");
+}
+
+static void PrintFullLosslessInfo(const WebPAuxStats* const stats,
+ const char* const description) {
+ fprintf(stderr, "Lossless-%s compressed size: %d bytes\n",
+ description, stats->lossless_size);
+ fprintf(stderr, " * Header size: %d bytes, image data size: %d\n",
+ stats->lossless_hdr_size, stats->lossless_data_size);
+ if (stats->lossless_features) {
+ fprintf(stderr, " * Lossless features used:");
+ if (stats->lossless_features & 1) fprintf(stderr, " PREDICTION");
+ if (stats->lossless_features & 2) fprintf(stderr, " CROSS-COLOR-TRANSFORM");
+ if (stats->lossless_features & 4) fprintf(stderr, " SUBTRACT-GREEN");
+ if (stats->lossless_features & 8) fprintf(stderr, " PALETTE");
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n",
+ stats->histogram_bits, stats->transform_bits, stats->cache_bits);
+ if (stats->palette_size > 0) {
+ fprintf(stderr, " * Palette size: %d\n", stats->palette_size);
+ }
+}
+
+static void PrintExtraInfoLossless(const WebPPicture* const pic,
+ int short_output,
+ const char* const file_name) {
+ const WebPAuxStats* const stats = pic->stats;
+ if (short_output) {
+ fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
+ } else {
+ WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
+ fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
+ fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size,
+ 8.f * stats->coded_size / pic->width / pic->height);
+ PrintFullLosslessInfo(stats, "ARGB");
+ }
+}
+
+static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
+ int full_details,
+ const char* const file_name) {
+ const WebPAuxStats* const stats = pic->stats;
+ if (short_output) {
+ fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
+ } else {
+ const int num_i4 = stats->block_count[0];
+ const int num_i16 = stats->block_count[1];
+ const int num_skip = stats->block_count[2];
+ const int total = num_i4 + num_i16;
+ WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
+ fprintf(stderr, "Dimension: %d x %d%s\n",
+ pic->width, pic->height,
+ stats->alpha_data_size ? " (with alpha)" : "");
+ fprintf(stderr, "Output: "
+ "%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n"
+ " (%.2f bpp)\n",
+ stats->coded_size,
+ stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3],
+ 8.f * stats->coded_size / pic->width / pic->height);
+ if (total > 0) {
+ int totals[4] = { 0, 0, 0, 0 };
+ fprintf(stderr, "block count: intra4: %6d (%.2f%%)\n"
+ " intra16: %6d (%.2f%%)\n"
+ " skipped: %6d (%.2f%%)\n",
+ num_i4, 100.f * num_i4 / total,
+ num_i16, 100.f * num_i16 / total,
+ num_skip, 100.f * num_skip / total);
+ fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
+ " mode-partition: %6d (%.1f%%)\n",
+ stats->header_bytes[0],
+ 100.f * stats->header_bytes[0] / stats->coded_size,
+ stats->header_bytes[1],
+ 100.f * stats->header_bytes[1] / stats->coded_size);
+ if (stats->alpha_data_size > 0) {
+ fprintf(stderr, " transparency: %6d (%.1f dB)\n",
+ stats->alpha_data_size, stats->PSNR[4]);
+ }
+ fprintf(stderr, " Residuals bytes "
+ "|segment 1|segment 2|segment 3"
+ "|segment 4| total\n");
+ if (full_details) {
+ fprintf(stderr, " intra4-coeffs: ");
+ PrintByteCount(stats->residual_bytes[0], stats->coded_size, totals);
+ fprintf(stderr, " intra16-coeffs: ");
+ PrintByteCount(stats->residual_bytes[1], stats->coded_size, totals);
+ fprintf(stderr, " chroma coeffs: ");
+ PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
+ }
+ fprintf(stderr, " macroblocks: ");
+ PrintPercents(stats->segment_size);
+ fprintf(stderr, " quantizer: ");
+ PrintValues(stats->segment_quant);
+ fprintf(stderr, " filter level: ");
+ PrintValues(stats->segment_level);
+ if (full_details) {
+ fprintf(stderr, "------------------+---------");
+ fprintf(stderr, "+---------+---------+---------+-----------------\n");
+ fprintf(stderr, " segments total: ");
+ PrintByteCount(totals, stats->coded_size, NULL);
+ }
+ }
+ if (stats->lossless_size > 0) {
+ PrintFullLosslessInfo(stats, "alpha");
+ }
+ }
+}
+
+static void PrintMapInfo(const WebPPicture* const pic) {
+ if (pic->extra_info != NULL) {
+ const int mb_w = (pic->width + 15) / 16;
+ const int mb_h = (pic->height + 15) / 16;
+ const int type = pic->extra_info_type;
+ int x, y;
+ for (y = 0; y < mb_h; ++y) {
+ for (x = 0; x < mb_w; ++x) {
+ const int c = pic->extra_info[x + y * mb_w];
+ if (type == 1) { // intra4/intra16
+ fprintf(stderr, "%c", "+."[c]);
+ } else if (type == 2) { // segments
+ fprintf(stderr, "%c", ".-*X"[c]);
+ } else if (type == 3) { // quantizers
+ fprintf(stderr, "%.2d ", c);
+ } else if (type == 6 || type == 7) {
+ fprintf(stderr, "%3d ", c);
+ } else {
+ fprintf(stderr, "0x%.2x ", c);
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static int MyWriter(const uint8_t* data, size_t data_size,
+ const WebPPicture* const pic) {
+ FILE* const out = (FILE*)pic->custom_ptr;
+ return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
+}
+
+// Dumps a picture as a PGM file using the IMC4 layout.
+static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
+ int y;
+ const int uv_width = (picture->width + 1) / 2;
+ const int uv_height = (picture->height + 1) / 2;
+ const int stride = (picture->width + 1) & ~1;
+ const uint8_t* src_y = picture->y;
+ const uint8_t* src_u = picture->u;
+ const uint8_t* src_v = picture->v;
+ const uint8_t* src_a = picture->a;
+ const int alpha_height =
+ WebPPictureHasTransparency(picture) ? picture->height : 0;
+ const int height = picture->height + uv_height + alpha_height;
+ FILE* const f = WFOPEN(PGM_name, "wb");
+ if (f == NULL) return 0;
+ fprintf(f, "P5\n%d %d\n255\n", stride, height);
+ for (y = 0; y < picture->height; ++y) {
+ if (fwrite(src_y, picture->width, 1, f) != 1) return 0;
+ if (picture->width & 1) fputc(0, f); // pad
+ src_y += picture->y_stride;
+ }
+ for (y = 0; y < uv_height; ++y) {
+ if (fwrite(src_u, uv_width, 1, f) != 1) return 0;
+ if (fwrite(src_v, uv_width, 1, f) != 1) return 0;
+ src_u += picture->uv_stride;
+ src_v += picture->uv_stride;
+ }
+ for (y = 0; y < alpha_height; ++y) {
+ if (fwrite(src_a, picture->width, 1, f) != 1) return 0;
+ if (picture->width & 1) fputc(0, f); // pad
+ src_a += picture->a_stride;
+ }
+ fclose(f);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// Metadata writing.
+
+enum {
+ METADATA_EXIF = (1 << 0),
+ METADATA_ICC = (1 << 1),
+ METADATA_XMP = (1 << 2),
+ METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP
+};
+
+static const int kChunkHeaderSize = 8;
+static const int kTagSize = 4;
+
+static void PrintMetadataInfo(const Metadata* const metadata,
+ int metadata_written) {
+ if (metadata == NULL || metadata_written == 0) return;
+
+ fprintf(stderr, "Metadata:\n");
+ if (metadata_written & METADATA_ICC) {
+ fprintf(stderr, " * ICC profile: %6d bytes\n", (int)metadata->iccp.size);
+ }
+ if (metadata_written & METADATA_EXIF) {
+ fprintf(stderr, " * EXIF data: %6d bytes\n", (int)metadata->exif.size);
+ }
+ if (metadata_written & METADATA_XMP) {
+ fprintf(stderr, " * XMP data: %6d bytes\n", (int)metadata->xmp.size);
+ }
+}
+
+// Outputs, in little endian, 'num' bytes from 'val' to 'out'.
+static int WriteLE(FILE* const out, uint32_t val, int num) {
+ uint8_t buf[4];
+ int i;
+ for (i = 0; i < num; ++i) {
+ buf[i] = (uint8_t)(val & 0xff);
+ val >>= 8;
+ }
+ return (fwrite(buf, num, 1, out) == 1);
+}
+
+static int WriteLE24(FILE* const out, uint32_t val) {
+ return WriteLE(out, val, 3);
+}
+
+static int WriteLE32(FILE* const out, uint32_t val) {
+ return WriteLE(out, val, 4);
+}
+
+static int WriteMetadataChunk(FILE* const out, const char fourcc[4],
+ const MetadataPayload* const payload) {
+ const uint8_t zero = 0;
+ const size_t need_padding = payload->size & 1;
+ int ok = (fwrite(fourcc, kTagSize, 1, out) == 1);
+ ok = ok && WriteLE32(out, (uint32_t)payload->size);
+ ok = ok && (fwrite(payload->bytes, payload->size, 1, out) == 1);
+ return ok && (fwrite(&zero, need_padding, need_padding, out) == need_padding);
+}
+
+// Sets 'flag' in 'vp8x_flags' and updates 'metadata_size' with the size of the
+// chunk if there is metadata and 'keep' is true.
+static int UpdateFlagsAndSize(const MetadataPayload* const payload,
+ int keep, int flag,
+ uint32_t* vp8x_flags, uint64_t* metadata_size) {
+ if (keep && payload->bytes != NULL && payload->size > 0) {
+ *vp8x_flags |= flag;
+ *metadata_size += kChunkHeaderSize + payload->size + (payload->size & 1);
+ return 1;
+ }
+ return 0;
+}
+
+// Writes a WebP file using the image contained in 'memory_writer' and the
+// metadata from 'metadata'. Metadata is controlled by 'keep_metadata' and the
+// availability in 'metadata'. Returns true on success.
+// For details see doc/webp-container-spec.txt#extended-file-format.
+static int WriteWebPWithMetadata(FILE* const out,
+ const WebPPicture* const picture,
+ const WebPMemoryWriter* const memory_writer,
+ const Metadata* const metadata,
+ int keep_metadata,
+ int* const metadata_written) {
+ const char kVP8XHeader[] = "VP8X\x0a\x00\x00\x00";
+ const int kAlphaFlag = 0x10;
+ const int kEXIFFlag = 0x08;
+ const int kICCPFlag = 0x20;
+ const int kXMPFlag = 0x04;
+ const size_t kRiffHeaderSize = 12;
+ const size_t kMaxChunkPayload = ~0 - kChunkHeaderSize - 1;
+ const size_t kMinSize = kRiffHeaderSize + kChunkHeaderSize;
+ uint32_t flags = 0;
+ uint64_t metadata_size = 0;
+ const int write_exif = UpdateFlagsAndSize(&metadata->exif,
+ !!(keep_metadata & METADATA_EXIF),
+ kEXIFFlag, &flags, &metadata_size);
+ const int write_iccp = UpdateFlagsAndSize(&metadata->iccp,
+ !!(keep_metadata & METADATA_ICC),
+ kICCPFlag, &flags, &metadata_size);
+ const int write_xmp = UpdateFlagsAndSize(&metadata->xmp,
+ !!(keep_metadata & METADATA_XMP),
+ kXMPFlag, &flags, &metadata_size);
+ uint8_t* webp = memory_writer->mem;
+ size_t webp_size = memory_writer->size;
+
+ *metadata_written = 0;
+
+ if (webp_size < kMinSize) return 0;
+ if (webp_size - kChunkHeaderSize + metadata_size > kMaxChunkPayload) {
+ fprintf(stderr, "Error! Addition of metadata would exceed "
+ "container size limit.\n");
+ return 0;
+ }
+
+ if (metadata_size > 0) {
+ const int kVP8XChunkSize = 18;
+ const int has_vp8x = !memcmp(webp + kRiffHeaderSize, "VP8X", kTagSize);
+ const uint32_t riff_size = (uint32_t)(webp_size - kChunkHeaderSize +
+ (has_vp8x ? 0 : kVP8XChunkSize) +
+ metadata_size);
+ // RIFF
+ int ok = (fwrite(webp, kTagSize, 1, out) == 1);
+ // RIFF size (file header size is not recorded)
+ ok = ok && WriteLE32(out, riff_size);
+ webp += kChunkHeaderSize;
+ webp_size -= kChunkHeaderSize;
+ // WEBP
+ ok = ok && (fwrite(webp, kTagSize, 1, out) == 1);
+ webp += kTagSize;
+ webp_size -= kTagSize;
+ if (has_vp8x) { // update the existing VP8X flags
+ webp[kChunkHeaderSize] |= (uint8_t)(flags & 0xff);
+ ok = ok && (fwrite(webp, kVP8XChunkSize, 1, out) == 1);
+ webp += kVP8XChunkSize;
+ webp_size -= kVP8XChunkSize;
+ } else {
+ const int is_lossless = !memcmp(webp, "VP8L", kTagSize);
+ if (is_lossless) {
+ // Presence of alpha is stored in the 37th bit (29th after the
+ // signature) of VP8L data.
+ if (webp[kChunkHeaderSize + 4] & (1 << 4)) flags |= kAlphaFlag;
+ }
+ ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1);
+ ok = ok && WriteLE32(out, flags);
+ ok = ok && WriteLE24(out, picture->width - 1);
+ ok = ok && WriteLE24(out, picture->height - 1);
+ }
+ if (write_iccp) {
+ ok = ok && WriteMetadataChunk(out, "ICCP", &metadata->iccp);
+ *metadata_written |= METADATA_ICC;
+ }
+ // Image
+ ok = ok && (fwrite(webp, webp_size, 1, out) == 1);
+ if (write_exif) {
+ ok = ok && WriteMetadataChunk(out, "EXIF", &metadata->exif);
+ *metadata_written |= METADATA_EXIF;
+ }
+ if (write_xmp) {
+ ok = ok && WriteMetadataChunk(out, "XMP ", &metadata->xmp);
+ *metadata_written |= METADATA_XMP;
+ }
+ return ok;
+ }
+
+ // No metadata, just write the original image file.
+ return (fwrite(webp, webp_size, 1, out) == 1);
+}
+
+//------------------------------------------------------------------------------
+
+static int ProgressReport(int percent, const WebPPicture* const picture) {
+ fprintf(stderr, "[%s]: %3d %% \r",
+ (char*)picture->user_data, percent);
+ return 1; // all ok
+}
+
+//------------------------------------------------------------------------------
+
+static void HelpShort(void) {
+ printf("Usage:\n\n");
+ printf(" cwebp [options] -q quality input.png -o output.webp\n\n");
+ printf("where quality is between 0 (poor) to 100 (very good).\n");
+ printf("Typical value is around 80.\n\n");
+ printf("Try -longhelp for an exhaustive list of advanced options.\n");
+}
+
+static void HelpLong(void) {
+ printf("Usage:\n");
+ printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n");
+ printf("If input size (-s) for an image is not specified, it is\n"
+ "assumed to be a PNG, JPEG, TIFF or WebP file.\n");
+ printf("Note: Animated PNG and WebP files are not supported.\n");
+#ifdef HAVE_WINCODEC_H
+ printf("Windows builds can take as input any of the files handled by WIC.\n");
+#endif
+ printf("\nOptions:\n");
+ printf(" -h / -help ............. short help\n");
+ printf(" -H / -longhelp ......... long help\n");
+ printf(" -q <float> ............. quality factor (0:small..100:big), "
+ "default=75\n");
+ printf(" -alpha_q <int> ......... transparency-compression quality (0..100),"
+ "\n default=100\n");
+ printf(" -preset <string> ....... preset setting, one of:\n");
+ printf(" default, photo, picture,\n");
+ printf(" drawing, icon, text\n");
+ printf(" -preset must come first, as it overwrites other parameters\n");
+ printf(" -z <int> ............... activates lossless preset with given\n"
+ " level in [0:fast, ..., 9:slowest]\n");
+ printf("\n");
+ printf(" -m <int> ............... compression method (0=fast, 6=slowest), "
+ "default=4\n");
+ printf(" -segments <int> ........ number of segments to use (1..4), "
+ "default=4\n");
+ printf(" -size <int> ............ target size (in bytes)\n");
+ printf(" -psnr <float> .......... target PSNR (in dB. typically: 42)\n");
+ printf("\n");
+ printf(" -s <int> <int> ......... input size (width x height) for YUV\n");
+ printf(" -sns <int> ............. spatial noise shaping (0:off, 100:max), "
+ "default=50\n");
+ printf(" -f <int> ............... filter strength (0=off..100), "
+ "default=60\n");
+ printf(" -sharpness <int> ....... "
+ "filter sharpness (0:most .. 7:least sharp), default=0\n");
+ printf(" -strong ................ use strong filter instead "
+ "of simple (default)\n");
+ printf(" -nostrong .............. use simple filter instead of strong\n");
+ printf(" -sharp_yuv ............. use sharper (and slower) RGB->YUV "
+ "conversion\n");
+ printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
+ printf(" "
+ "the first partition (0=no degradation ... 100=full)\n");
+ printf(" -pass <int> ............ analysis pass number (1..10)\n");
+ printf(" -qrange <min> <max> .... specifies the permissible quality range\n"
+ " (default: 0 100)\n");
+ printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
+ printf(" -resize <w> <h> ........ resize picture (*after* any cropping)\n");
+ printf(" -mt .................... use multi-threading if available\n");
+ printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
+ printf(" -map <int> ............. print map of extra info\n");
+ printf(" -print_psnr ............ prints averaged PSNR distortion\n");
+ printf(" -print_ssim ............ prints averaged SSIM distortion\n");
+ printf(" -print_lsim ............ prints local-similarity distortion\n");
+ printf(" -d <file.pgm> .......... dump the compressed output (PGM file)\n");
+ printf(" -alpha_method <int> .... transparency-compression method (0..1), "
+ "default=1\n");
+ printf(" -alpha_filter <string> . predictive filtering for alpha plane,\n");
+ printf(" one of: none, fast (default) or best\n");
+ printf(" -exact ................. preserve RGB values in transparent area, "
+ "default=off\n");
+ printf(" -blend_alpha <hex> ..... blend colors against background color\n"
+ " expressed as RGB values written in\n"
+ " hexadecimal, e.g. 0xc0e0d0 for red=0xc0\n"
+ " green=0xe0 and blue=0xd0\n");
+ printf(" -noalpha ............... discard any transparency information\n");
+ printf(" -lossless .............. encode image losslessly, default=off\n");
+ printf(" -near_lossless <int> ... use near-lossless image\n"
+ " preprocessing (0..100=off), "
+ "default=100\n");
+ printf(" -hint <string> ......... specify image characteristics hint,\n");
+ printf(" one of: photo, picture or graph\n");
+
+ printf("\n");
+ printf(" -metadata <string> ..... comma separated list of metadata to\n");
+ printf(" ");
+ printf("copy from the input to the output if present.\n");
+ printf(" "
+ "Valid values: all, none (default), exif, icc, xmp\n");
+
+ printf("\n");
+ printf(" -short ................. condense printed message\n");
+ printf(" -quiet ................. don't print anything\n");
+ printf(" -version ............... print version number and exit\n");
+#ifndef WEBP_DLL
+ printf(" -noasm ................. disable all assembly optimizations\n");
+#endif
+ printf(" -v ..................... verbose, e.g. print encoding/decoding "
+ "times\n");
+ printf(" -progress .............. report encoding progress\n");
+ printf("\n");
+ printf("Experimental Options:\n");
+ printf(" -jpeg_like ............. roughly match expected JPEG size\n");
+ printf(" -af .................... auto-adjust filter strength\n");
+ printf(" -pre <int> ............. pre-processing filter\n");
+ printf("\n");
+ printf("Supported input formats:\n %s\n", WebPGetEnabledInputFileFormats());
+}
+
+//------------------------------------------------------------------------------
+// Error messages
+
+static const char* const kErrorMessages[VP8_ENC_ERROR_LAST] = {
+ "OK",
+ "OUT_OF_MEMORY: Out of memory allocating objects",
+ "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer",
+ "NULL_PARAMETER: NULL parameter passed to function",
+ "INVALID_CONFIGURATION: configuration is invalid",
+ "BAD_DIMENSION: Bad picture dimension. Maximum width and height "
+ "allowed is 16383 pixels.",
+ "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n"
+ "To reduce the size of this partition, try using less segments "
+ "with the -segments option, and eventually reduce the number of "
+ "header bits using -partition_limit. More details are available "
+ "in the manual (`man cwebp`)",
+ "PARTITION_OVERFLOW: Partition is too big to fit 16M",
+ "BAD_WRITE: Picture writer returned an I/O error",
+ "FILE_TOO_BIG: File would be too big to fit in 4G",
+ "USER_ABORT: encoding abort requested by user"
+};
+
+//------------------------------------------------------------------------------
+
+int main(int argc, const char* argv[]) {
+ int return_value = -1;
+ const char* in_file = NULL, *out_file = NULL, *dump_file = NULL;
+ FILE* out = NULL;
+ int c;
+ int short_output = 0;
+ int quiet = 0;
+ int keep_alpha = 1;
+ int blend_alpha = 0;
+ uint32_t background_color = 0xffffffu;
+ int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
+ int resize_w = 0, resize_h = 0;
+ int lossless_preset = 6;
+ int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it
+ int show_progress = 0;
+ int keep_metadata = 0;
+ int metadata_written = 0;
+ WebPPicture picture;
+ int print_distortion = -1; // -1=off, 0=PSNR, 1=SSIM, 2=LSIM
+ WebPPicture original_picture; // when PSNR or SSIM is requested
+ WebPConfig config;
+ WebPAuxStats stats;
+ WebPMemoryWriter memory_writer;
+ int use_memory_writer;
+ Metadata metadata;
+ Stopwatch stop_watch;
+
+ INIT_WARGV(argc, argv);
+
+ MetadataInit(&metadata);
+ WebPMemoryWriterInit(&memory_writer);
+ if (!WebPPictureInit(&picture) ||
+ !WebPPictureInit(&original_picture) ||
+ !WebPConfigInit(&config)) {
+ fprintf(stderr, "Error! Version mismatch!\n");
+ FREE_WARGV_AND_RETURN(-1);
+ }
+
+ if (argc == 1) {
+ HelpShort();
+ FREE_WARGV_AND_RETURN(0);
+ }
+
+ for (c = 1; c < argc; ++c) {
+ int parse_error = 0;
+ if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
+ HelpShort();
+ FREE_WARGV_AND_RETURN(0);
+ } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
+ HelpLong();
+ FREE_WARGV_AND_RETURN(0);
+ } else if (!strcmp(argv[c], "-o") && c + 1 < argc) {
+ out_file = (const char*)GET_WARGV(argv, ++c);
+ } else if (!strcmp(argv[c], "-d") && c + 1 < argc) {
+ dump_file = (const char*)GET_WARGV(argv, ++c);
+ config.show_compressed = 1;
+ } else if (!strcmp(argv[c], "-print_psnr")) {
+ config.show_compressed = 1;
+ print_distortion = 0;
+ } else if (!strcmp(argv[c], "-print_ssim")) {
+ config.show_compressed = 1;
+ print_distortion = 1;
+ } else if (!strcmp(argv[c], "-print_lsim")) {
+ config.show_compressed = 1;
+ print_distortion = 2;
+ } else if (!strcmp(argv[c], "-short")) {
+ ++short_output;
+ } else if (!strcmp(argv[c], "-s") && c + 2 < argc) {
+ picture.width = ExUtilGetInt(argv[++c], 0, &parse_error);
+ picture.height = ExUtilGetInt(argv[++c], 0, &parse_error);
+ if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 ||
+ picture.height > WEBP_MAX_DIMENSION || picture.height < 0) {
+ fprintf(stderr,
+ "Specified dimension (%d x %d) is out of range.\n",
+ picture.width, picture.height);
+ goto Error;
+ }
+ } else if (!strcmp(argv[c], "-m") && c + 1 < argc) {
+ config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
+ use_lossless_preset = 0; // disable -z option
+ } else if (!strcmp(argv[c], "-q") && c + 1 < argc) {
+ config.quality = ExUtilGetFloat(argv[++c], &parse_error);
+ use_lossless_preset = 0; // disable -z option
+ } else if (!strcmp(argv[c], "-z") && c + 1 < argc) {
+ lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error);
+ if (use_lossless_preset != 0) use_lossless_preset = 1;
+ } else if (!strcmp(argv[c], "-alpha_q") && c + 1 < argc) {
+ config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-alpha_method") && c + 1 < argc) {
+ config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-alpha_cleanup")) {
+ // This flag is obsolete, does opposite of -exact.
+ config.exact = 0;
+ } else if (!strcmp(argv[c], "-exact")) {
+ config.exact = 1;
+ } else if (!strcmp(argv[c], "-blend_alpha") && c + 1 < argc) {
+ blend_alpha = 1;
+ // background color is given in hex with an optional '0x' prefix
+ background_color = ExUtilGetInt(argv[++c], 16, &parse_error);
+ background_color = background_color & 0x00ffffffu;
+ } else if (!strcmp(argv[c], "-alpha_filter") && c + 1 < argc) {
+ ++c;
+ if (!strcmp(argv[c], "none")) {
+ config.alpha_filtering = 0;
+ } else if (!strcmp(argv[c], "fast")) {
+ config.alpha_filtering = 1;
+ } else if (!strcmp(argv[c], "best")) {
+ config.alpha_filtering = 2;
+ } else {
+ fprintf(stderr, "Error! Unrecognized alpha filter: %s\n", argv[c]);
+ goto Error;
+ }
+ } else if (!strcmp(argv[c], "-noalpha")) {
+ keep_alpha = 0;
+ } else if (!strcmp(argv[c], "-lossless")) {
+ config.lossless = 1;
+ } else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) {
+ config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
+ config.lossless = 1; // use near-lossless only with lossless
+ } else if (!strcmp(argv[c], "-hint") && c + 1 < argc) {
+ ++c;
+ if (!strcmp(argv[c], "photo")) {
+ config.image_hint = WEBP_HINT_PHOTO;
+ } else if (!strcmp(argv[c], "picture")) {
+ config.image_hint = WEBP_HINT_PICTURE;
+ } else if (!strcmp(argv[c], "graph")) {
+ config.image_hint = WEBP_HINT_GRAPH;
+ } else {
+ fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]);
+ goto Error;
+ }
+ } else if (!strcmp(argv[c], "-size") && c + 1 < argc) {
+ config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-psnr") && c + 1 < argc) {
+ config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error);
+ } else if (!strcmp(argv[c], "-sns") && c + 1 < argc) {
+ config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-f") && c + 1 < argc) {
+ config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-af")) {
+ config.autofilter = 1;
+ } else if (!strcmp(argv[c], "-jpeg_like")) {
+ config.emulate_jpeg_size = 1;
+ } else if (!strcmp(argv[c], "-mt")) {
+ ++config.thread_level; // increase thread level
+ } else if (!strcmp(argv[c], "-low_memory")) {
+ config.low_memory = 1;
+ } else if (!strcmp(argv[c], "-strong")) {
+ config.filter_type = 1;
+ } else if (!strcmp(argv[c], "-nostrong")) {
+ config.filter_type = 0;
+ } else if (!strcmp(argv[c], "-sharpness") && c + 1 < argc) {
+ config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-sharp_yuv")) {
+ config.use_sharp_yuv = 1;
+ } else if (!strcmp(argv[c], "-pass") && c + 1 < argc) {
+ config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-qrange") && c + 2 < argc) {
+ config.qmin = ExUtilGetInt(argv[++c], 0, &parse_error);
+ config.qmax = ExUtilGetInt(argv[++c], 0, &parse_error);
+ if (config.qmin < 0) config.qmin = 0;
+ if (config.qmax > 100) config.qmax = 100;
+ } else if (!strcmp(argv[c], "-pre") && c + 1 < argc) {
+ config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-segments") && c + 1 < argc) {
+ config.segments = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-partition_limit") && c + 1 < argc) {
+ config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-map") && c + 1 < argc) {
+ picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-crop") && c + 4 < argc) {
+ crop = 1;
+ crop_x = ExUtilGetInt(argv[++c], 0, &parse_error);
+ crop_y = ExUtilGetInt(argv[++c], 0, &parse_error);
+ crop_w = ExUtilGetInt(argv[++c], 0, &parse_error);
+ crop_h = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-resize") && c + 2 < argc) {
+ resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
+ resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
+#ifndef WEBP_DLL
+ } else if (!strcmp(argv[c], "-noasm")) {
+ VP8GetCPUInfo = NULL;
+#endif
+ } else if (!strcmp(argv[c], "-version")) {
+ const int version = WebPGetEncoderVersion();
+ const int sharpyuv_version = SharpYuvGetVersion();
+ printf("%d.%d.%d\n",
+ (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
+ printf("libsharpyuv: %d.%d.%d\n",
+ (sharpyuv_version >> 24) & 0xff, (sharpyuv_version >> 16) & 0xffff,
+ sharpyuv_version & 0xff);
+ FREE_WARGV_AND_RETURN(0);
+ } else if (!strcmp(argv[c], "-progress")) {
+ show_progress = 1;
+ } else if (!strcmp(argv[c], "-quiet")) {
+ quiet = 1;
+ } else if (!strcmp(argv[c], "-preset") && c + 1 < argc) {
+ WebPPreset preset;
+ ++c;
+ if (!strcmp(argv[c], "default")) {
+ preset = WEBP_PRESET_DEFAULT;
+ } else if (!strcmp(argv[c], "photo")) {
+ preset = WEBP_PRESET_PHOTO;
+ } else if (!strcmp(argv[c], "picture")) {
+ preset = WEBP_PRESET_PICTURE;
+ } else if (!strcmp(argv[c], "drawing")) {
+ preset = WEBP_PRESET_DRAWING;
+ } else if (!strcmp(argv[c], "icon")) {
+ preset = WEBP_PRESET_ICON;
+ } else if (!strcmp(argv[c], "text")) {
+ preset = WEBP_PRESET_TEXT;
+ } else {
+ fprintf(stderr, "Error! Unrecognized preset: %s\n", argv[c]);
+ goto Error;
+ }
+ if (!WebPConfigPreset(&config, preset, config.quality)) {
+ fprintf(stderr, "Error! Could initialize configuration with preset.\n");
+ goto Error;
+ }
+ } else if (!strcmp(argv[c], "-metadata") && c + 1 < argc) {
+ static const struct {
+ const char* option;
+ int flag;
+ } kTokens[] = {
+ { "all", METADATA_ALL },
+ { "none", 0 },
+ { "exif", METADATA_EXIF },
+ { "icc", METADATA_ICC },
+ { "xmp", METADATA_XMP },
+ };
+ const size_t kNumTokens = sizeof(kTokens) / sizeof(kTokens[0]);
+ const char* start = argv[++c];
+ const char* const end = start + strlen(start);
+
+ 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);
+ FREE_WARGV_AND_RETURN(-1);
+ }
+ start = token + 1;
+ }
+#ifdef HAVE_WINCODEC_H
+ if (keep_metadata != 0 && keep_metadata != METADATA_ICC) {
+ // TODO(jzern): remove when -metadata is supported on all platforms.
+ fprintf(stderr, "Warning: only ICC profile extraction is currently"
+ " supported on this platform!\n");
+ }
+#endif
+ } else if (!strcmp(argv[c], "-v")) {
+ verbose = 1;
+ } else if (!strcmp(argv[c], "--")) {
+ if (c + 1 < argc) in_file = (const char*)GET_WARGV(argv, ++c);
+ break;
+ } else if (argv[c][0] == '-') {
+ fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
+ HelpLong();
+ FREE_WARGV_AND_RETURN(-1);
+ } else {
+ in_file = (const char*)GET_WARGV(argv, c);
+ }
+
+ if (parse_error) {
+ HelpLong();
+ FREE_WARGV_AND_RETURN(-1);
+ }
+ }
+ if (in_file == NULL) {
+ fprintf(stderr, "No input file specified!\n");
+ HelpShort();
+ goto Error;
+ }
+
+ if (use_lossless_preset == 1) {
+ if (!WebPConfigLosslessPreset(&config, lossless_preset)) {
+ fprintf(stderr, "Invalid lossless preset (-z %d)\n", lossless_preset);
+ goto Error;
+ }
+ }
+
+ // Check for unsupported command line options for lossless mode and log
+ // warning for such options.
+ if (!quiet && config.lossless == 1) {
+ if (config.target_size > 0 || config.target_PSNR > 0) {
+ fprintf(stderr, "Encoding for specified size or PSNR is not supported"
+ " for lossless encoding. Ignoring such option(s)!\n");
+ }
+ if (config.partition_limit > 0) {
+ fprintf(stderr, "Partition limit option is not required for lossless"
+ " encoding. Ignoring this option!\n");
+ }
+ }
+ // If a target size or PSNR was given, but somehow the -pass option was
+ // omitted, force a reasonable value.
+ if (config.target_size > 0 || config.target_PSNR > 0) {
+ if (config.pass == 1) config.pass = 6;
+ }
+
+ if (!WebPValidateConfig(&config)) {
+ fprintf(stderr, "Error! Invalid configuration.\n");
+ goto Error;
+ }
+
+ // Read the input. We need to decide if we prefer ARGB or YUVA
+ // samples, depending on the expected compression mode (this saves
+ // some conversion steps).
+ picture.use_argb = (config.lossless || config.use_sharp_yuv ||
+ config.preprocessing > 0 ||
+ crop || (resize_w | resize_h) > 0);
+ if (verbose) {
+ StopwatchReset(&stop_watch);
+ }
+ if (!ReadPicture(in_file, &picture, keep_alpha,
+ (keep_metadata == 0) ? NULL : &metadata)) {
+ WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n",
+ (const W_CHAR*)in_file);
+ goto Error;
+ }
+ picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
+
+ if (blend_alpha) {
+ WebPBlendAlpha(&picture, background_color);
+ }
+
+ if (verbose) {
+ const double read_time = StopwatchReadAndReset(&stop_watch);
+ fprintf(stderr, "Time to read input: %.3fs\n", read_time);
+ }
+ // The bitstream should be kept in memory when metadata must be appended
+ // before writing it to a file/stream, and/or when the near-losslessly encoded
+ // bitstream must be decoded for distortion computation (lossy will modify the
+ // 'picture' but not the lossless pipeline).
+ // Otherwise directly write the bitstream to a file.
+ use_memory_writer = (out_file != NULL && keep_metadata) ||
+ (!quiet && print_distortion >= 0 && config.lossless &&
+ config.near_lossless < 100);
+
+ // Open the output
+ if (out_file != NULL) {
+ const int use_stdout = !WSTRCMP(out_file, "-");
+ out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb");
+ if (out == NULL) {
+ WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
+ (const W_CHAR*)out_file);
+ goto Error;
+ } else {
+ if (!short_output && !quiet) {
+ WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file);
+ }
+ }
+ if (use_memory_writer) {
+ picture.writer = WebPMemoryWrite;
+ picture.custom_ptr = (void*)&memory_writer;
+ } else {
+ picture.writer = MyWriter;
+ picture.custom_ptr = (void*)out;
+ }
+ } else {
+ out = NULL;
+ if (use_memory_writer) {
+ picture.writer = WebPMemoryWrite;
+ picture.custom_ptr = (void*)&memory_writer;
+ }
+ if (!quiet && !short_output) {
+ fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
+ fprintf(stderr, "be performed, but its results discarded.\n\n");
+ }
+ }
+ if (!quiet) {
+ picture.stats = &stats;
+ picture.user_data = (void*)in_file;
+ }
+
+ // Crop & resize.
+ if (verbose) {
+ StopwatchReset(&stop_watch);
+ }
+ if (crop != 0) {
+ // We use self-cropping using a view.
+ if (!WebPPictureView(&picture, crop_x, crop_y, crop_w, crop_h, &picture)) {
+ fprintf(stderr, "Error! Cannot crop picture\n");
+ goto Error;
+ }
+ }
+ if ((resize_w | resize_h) > 0) {
+ WebPPicture picture_no_alpha;
+ if (config.exact) {
+ // If -exact, we can't premultiply RGB by A otherwise RGB is lost if A=0.
+ // We rescale an opaque copy and assemble scaled A and non-premultiplied
+ // RGB channels. This is slower but it's a very uncommon use case. Color
+ // leak at sharp alpha edges is possible.
+ if (!WebPPictureCopy(&picture, &picture_no_alpha)) {
+ fprintf(stderr, "Error! Cannot copy temporary picture\n");
+ goto Error;
+ }
+
+ // We enforced picture.use_argb = 1 above. Now, remove the alpha values.
+ {
+ int x, y;
+ uint32_t* argb_no_alpha = picture_no_alpha.argb;
+ for (y = 0; y < picture_no_alpha.height; ++y) {
+ for (x = 0; x < picture_no_alpha.width; ++x) {
+ argb_no_alpha[x] |= 0xff000000; // Opaque copy.
+ }
+ argb_no_alpha += picture_no_alpha.argb_stride;
+ }
+ }
+
+ if (!WebPPictureRescale(&picture_no_alpha, resize_w, resize_h)) {
+ fprintf(stderr, "Error! Cannot resize temporary picture\n");
+ goto Error;
+ }
+ }
+
+ if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
+ fprintf(stderr, "Error! Cannot resize picture\n");
+ goto Error;
+ }
+
+ if (config.exact) { // Put back the alpha information.
+ int x, y;
+ uint32_t* argb_no_alpha = picture_no_alpha.argb;
+ uint32_t* argb = picture.argb;
+ for (y = 0; y < picture_no_alpha.height; ++y) {
+ for (x = 0; x < picture_no_alpha.width; ++x) {
+ argb[x] = (argb[x] & 0xff000000) | (argb_no_alpha[x] & 0x00ffffff);
+ }
+ argb_no_alpha += picture_no_alpha.argb_stride;
+ argb += picture.argb_stride;
+ }
+ WebPPictureFree(&picture_no_alpha);
+ }
+ }
+ if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) {
+ const double preproc_time = StopwatchReadAndReset(&stop_watch);
+ fprintf(stderr, "Time to crop/resize picture: %.3fs\n", preproc_time);
+ }
+
+ if (picture.extra_info_type > 0) {
+ AllocExtraInfo(&picture);
+ }
+ // Save original picture for later comparison. Only for lossy as lossless does
+ // not modify 'picture' (even near-lossless).
+ if (print_distortion >= 0 && !config.lossless &&
+ !WebPPictureCopy(&picture, &original_picture)) {
+ fprintf(stderr, "Error! Cannot copy temporary picture\n");
+ goto Error;
+ }
+
+ // Compress.
+ if (verbose) {
+ StopwatchReset(&stop_watch);
+ }
+ if (!WebPEncode(&config, &picture)) {
+ fprintf(stderr, "Error! Cannot encode picture as WebP\n");
+ fprintf(stderr, "Error code: %d (%s)\n",
+ picture.error_code, kErrorMessages[picture.error_code]);
+ goto Error;
+ }
+ if (verbose) {
+ const double encode_time = StopwatchReadAndReset(&stop_watch);
+ fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time);
+ }
+
+ // Get the decompressed image for the lossless pipeline.
+ if (!quiet && print_distortion >= 0 && config.lossless) {
+ if (config.near_lossless == 100) {
+ // Pure lossless: image was not modified, make 'original_picture' a view
+ // of 'picture' by copying all members except the freeable pointers.
+ original_picture = picture;
+ original_picture.memory_ = original_picture.memory_argb_ = NULL;
+ } else {
+ // Decode the bitstream stored in 'memory_writer' to get the altered image
+ // to 'picture'; save the 'original_picture' beforehand.
+ assert(use_memory_writer);
+ original_picture = picture;
+ if (!WebPPictureInit(&picture)) { // Do not free 'picture'.
+ fprintf(stderr, "Error! Version mismatch!\n");
+ goto Error;
+ }
+
+ picture.use_argb = 1;
+ if (!ReadWebP(
+ memory_writer.mem, memory_writer.size, &picture,
+ /*keep_alpha=*/WebPPictureHasTransparency(&original_picture),
+ /*metadata=*/NULL)) {
+ fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n");
+ fprintf(stderr, "Error code: %d (%s)\n", picture.error_code,
+ kErrorMessages[picture.error_code]);
+ goto Error;
+ }
+ picture.stats = original_picture.stats;
+ }
+ original_picture.stats = NULL;
+ }
+
+ // Write the YUV planes to a PGM file. Only available for lossy.
+ if (dump_file) {
+ if (picture.use_argb) {
+ fprintf(stderr, "Warning: can't dump file (-d option) "
+ "in lossless mode.\n");
+ } else if (!DumpPicture(&picture, dump_file)) {
+ WFPRINTF(stderr, "Warning, couldn't dump picture %s\n",
+ (const W_CHAR*)dump_file);
+ }
+ }
+
+ if (use_memory_writer && out != NULL &&
+ !WriteWebPWithMetadata(out, &picture, &memory_writer, &metadata,
+ keep_metadata, &metadata_written)) {
+ fprintf(stderr, "Error writing WebP file!\n");
+ goto Error;
+ }
+
+ if (out == NULL && keep_metadata) {
+ // output is disabled, just display the metadata stats.
+ const struct {
+ const MetadataPayload* const payload;
+ int flag;
+ } *iter, info[] = {{&metadata.exif, METADATA_EXIF},
+ {&metadata.iccp, METADATA_ICC},
+ {&metadata.xmp, METADATA_XMP},
+ {NULL, 0}};
+ uint32_t unused1 = 0;
+ uint64_t unused2 = 0;
+
+ for (iter = info; iter->payload != NULL; ++iter) {
+ if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
+ /*flag=*/0, &unused1, &unused2)) {
+ metadata_written |= iter->flag;
+ }
+ }
+ }
+
+ if (!quiet) {
+ if (!short_output || print_distortion < 0) {
+ if (config.lossless) {
+ PrintExtraInfoLossless(&picture, short_output, in_file);
+ } else {
+ PrintExtraInfoLossy(&picture, short_output, config.low_memory, in_file);
+ }
+ }
+ if (!short_output && picture.extra_info_type > 0) {
+ PrintMapInfo(&picture);
+ }
+ if (print_distortion >= 0) { // print distortion
+ static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };
+ float values[5];
+ if (!WebPPictureDistortion(&picture, &original_picture,
+ print_distortion, values)) {
+ fprintf(stderr, "Error while computing the distortion.\n");
+ goto Error;
+ }
+ if (!short_output) {
+ fprintf(stderr, "%s: ", distortion_names[print_distortion]);
+ fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n",
+ values[0], values[1], values[2], values[3], values[4]);
+ } else {
+ fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]);
+ }
+ }
+ if (!short_output) {
+ PrintMetadataInfo(&metadata, metadata_written);
+ }
+ }
+ return_value = 0;
+
+ Error:
+ WebPMemoryWriterClear(&memory_writer);
+ WebPFree(picture.extra_info);
+ MetadataFree(&metadata);
+ WebPPictureFree(&picture);
+ WebPPictureFree(&original_picture);
+ if (out != NULL && out != stdout) {
+ fclose(out);
+ }
+
+ FREE_WARGV_AND_RETURN(return_value);
+}
+
+//------------------------------------------------------------------------------
diff --git a/examples/dwebp.c b/examples/dwebp.c
new file mode 100644
index 0000000..652de6a
--- /dev/null
+++ b/examples/dwebp.c
@@ -0,0 +1,421 @@
+// 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"
+ "Note: Animated WebP files are not supported.\n\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> ......... resize 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*)WebPMalloc(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*)WebPMalloc(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);
+ WebPFree((void*)external_buffer);
+ WebPFree((void*)data);
+ FREE_WARGV_AND_RETURN(ok ? 0 : -1);
+}
+
+//------------------------------------------------------------------------------
diff --git a/examples/example_util.c b/examples/example_util.c
new file mode 100644
index 0000000..fa38d3c
--- /dev/null
+++ b/examples/example_util.c
@@ -0,0 +1,139 @@
+// 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_) {
+ WebPFree((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**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_));
+ if (args->argv_ == NULL) {
+ ExUtilDeleteCommandLineArguments(args);
+ 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);
+ ExUtilDeleteCommandLineArguments(args);
+ 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;
+}
diff --git a/examples/example_util.h b/examples/example_util.h
new file mode 100644
index 0000000..fe762a4
--- /dev/null
+++ b/examples/example_util.h
@@ -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_
diff --git a/examples/gif2webp.c b/examples/gif2webp.c
new file mode 100644
index 0000000..cc9b25d
--- /dev/null
+++ b/examples/gif2webp.c
@@ -0,0 +1,609 @@
+// 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);
+ if (!(WebPPictureCopy(&frame, &curr_canvas) &&
+ WebPPictureCopy(&frame, &prev_canvas))) {
+ fprintf(stderr, "Error allocating canvas.\n");
+ goto End;
+ }
+
+ // 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 there's only one frame, we don't need to handle loop count.
+ if (frame_number == 1) {
+ loop_count = 0;
+ } else 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
+
+//------------------------------------------------------------------------------
diff --git a/examples/gifdec.c b/examples/gifdec.c
new file mode 100644
index 0000000..99ee996
--- /dev/null
+++ b/examples/gifdec.c
@@ -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*)WebPMalloc(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);
+ WebPFree(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
+
+// -----------------------------------------------------------------------------
diff --git a/examples/gifdec.h b/examples/gifdec.h
new file mode 100644
index 0000000..5eba9dd
--- /dev/null
+++ b/examples/gifdec.h
@@ -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_
diff --git a/examples/img2webp.c b/examples/img2webp.c
new file mode 100644
index 0000000..bfb1bfc
--- /dev/null
+++ b/examples/img2webp.c
@@ -0,0 +1,325 @@
+// 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_options] [[frame_options] frame_file]...\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");
+ printf("\nSupported input formats:\n %s\n",
+ WebPGetEnabledInputFileFormats());
+}
+
+//------------------------------------------------------------------------------
+
+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);
+ WebPFree((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();
+ FREE_WARGV_AND_RETURN(0);
+ } 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);
+}
diff --git a/examples/stopwatch.h b/examples/stopwatch.h
new file mode 100644
index 0000000..f1b0fac
--- /dev/null
+++ b/examples/stopwatch.h
@@ -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_
diff --git a/examples/test.webp b/examples/test.webp
new file mode 100644
index 0000000..3e4bca1
--- /dev/null
+++ b/examples/test.webp
Binary files differ
diff --git a/examples/test_ref.ppm b/examples/test_ref.ppm
new file mode 100644
index 0000000..97719f0
--- /dev/null
+++ b/examples/test_ref.ppm
@@ -0,0 +1,4 @@
+P6
+128 128
+255
+ËáûËáûËáûËáûËáûËáûËáûËáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÐãýÐãýÐãýÐãýÒäþÒäþÒäþÒäþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒäþÒäþÒäþÒäþÓåÿÓåÿÓåÿÓåÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûËáûËáûËáûËáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÏäýÐãýÐãýÐãýÒäþÒäþÒäþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒäþÒäþÒäþÒäþÓåÿÓåÿÓåÿÓåÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûËáûËáûËáûËáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÏäûÏäûÏäûÏäûÐåýÐåýÐåýÐåýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒäþÒäþÒäþÒäþÓåÿÓåÿÓåÿÓåÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûËáûËáûËáûËáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÌáûÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÎåûÎåûÎåûÎåûÏæýÏæýÏæýÏæýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒäþÒäþÒäþÒäþÓåÿÓåÿÓåÿÓåÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûÌâýÌâýÌâýÌâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÎåûÎåùÎåùÎåùÏæúÏæúÏæúÏæýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓåÿÓåÿÓåÿÓåÿÔæÿÔæÿÔæÿÔæÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÒèùÒèùÒèùÒèùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûÌâýÌâýÌâýÌâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåýÒèûÒèûÒèûÒèûÐæúÐæúÐæúÐæúÐåýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓåÿÓåÿÓåÿÓåÿÔæÿÔæÿÔæÿÔæÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÒèùÒèùÒèùÒèùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûÌâýÌâýÌâýÌâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåýÐæúÒåøÒåøÒåøÒåøÒåøÒåøÐæúÐåýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓåÿÓåÿÓåÿÓåÿÔæÿÔæÿÔæÿÔæÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÒèùÒèùÒèùÒèùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ËáûËáûËáûËáûÌâýÌâýÌâýÌâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäÿÐãÿÐãÿÐãÿÏäýÏäýÏäýÐãýÒäþÒåýÒåýÒåýÏáóÏáóÏáóÏáñÔåöÔåöÔåöÔåøÒåúÒåýÒåýÐåýÐåýÐåýÐåýÐåþÓåÿÓåÿÓåÿÓåÿÔæÿÔæÿÔæÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÔèÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéÿÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÔêûÔêûÔêûÔêûÔêûÔêûÔêûÔêûÓéúÓéúÓéúÓéúÒèùÒèùÒèùÒèùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒæÿÐåþÒäþÐãýÎáúÒâûÐáúÕåÿÎáýÔæÿÔæÿÓãýÏßøÉÚð·Æܪ©±»Îª»©³ÅÌÖèÖáòÓáñÖèøÔåö×éûÒåøÒåúÖêÿÐæúÒæþÓæþÓæþÓæþÓæþÔèÿÔèÿÔèÿÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÕëÿÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëý×ëþ×ëþ×ëþ×ëþÖêýÖêýÖêýÖêýÕéûÕéûÕéûÕéûÔèúÔèúÔèúÔèúÓæùÓæùÓæùÓæùÒåøÒåøÒåøÒåøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒäþÒäþÓãý×èÿÕãþÒßúÕäÿÌÛøÈÙò«Åm{dqhtlvs{
y¨¤ªº°¶Æ½ÆÕÎÜêÓäóÕæ÷ÔåöÖèúÓæùÐäùÔêþÓæûÓæûÓæûÓæûÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëý×ëþ×ëþ×ëþ×ëþÖêýÖêýÖêýÖêýÕéûÕéûÕéûÕéûÔèúÔèúÔèúÔèúÓæùÓæùÓæùÓæùÒåøÒåøÒåøÒåøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÌáùÎãûÓåÿÕèÿÒâûÓãýÔâýÙæÿÓáû©·Òlz\jmzhqmw¡¥°³Å¸½Ë©¿ËÙÓãòÖæö×æøÔåöÖèúÕéûÐä÷ÓæûÓæûÓæûÓæûÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëý×ëþ×ëþ×ëþ×ëþÖêýÖêýÖêýÖêýÕéûÕéûÕéûÕéûÔèúÔèúÔèúÔèúÓæùÓæùÓæùÓæùÒåøÒåøÒåøÒåøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ÍâýÍâýÍâýÍâýÎãþÎãþÎãþÎãþÎãûÎãûÎãûÎãûÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓèÿÒæÿÐãýÏâûÓãýÕåÿ±¿ÚªrWd~\i~¤¢½jqªz
²
©²´Á¯³¿¬±½ËÆÔäÔâòÙèùÔãôÖèúÕæùÓæûÓæûÓæûÓæûÔèýÔèýÔèýÔèýÕéþÕéþÕéþÕéþÕéþÕéþÕéþÕéþÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëýÕëý×ëþ×ëþ×ëþ×ëþÖêýÖêýÖêýÖêýÕéûÕéûÕéûÕéûÔèúÔèúÔèúÔèúÓæùÓæùÓæùÓæùÒåøÒåøÒåøÒåøÐæøÐæøÐæøÐæøÏå÷Ïå÷Ïå÷Ïå÷ÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓèÿÉÞ÷ÚìÿÔæÿÈÙòy£M[vXfVc}[deoipªfj¬xz}}~{qo¥©¤¡ÆÌÚ½ÆÕ¢±¯¹ËÖáò×å÷Úèù×æúÖæýÔèýÔèýÔèýÔèýÔèýÔèýÔèýÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþ×íÿ×íÿ×íÿ×íÿ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÖêýÕéûÔèúÕéûÕéûÕéûÕéûÓæùÓæùÓæùÓæùÓæùÓæùÓæùÓæùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒæÿÒäþÅ×ñfwM]wLZtMZsOXq_fjq~rvrs©
¤ssvs}²¬¥¤¨²·»Ç¨¡¶ÈÓÝïÚä÷ÛéúÖèúÔèýÔèýÔèýÔèýÔèýÔèýÔèýÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþ×íÿ×íÿ×íÿ×íÿ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÖêýÕéûÔèúÕéûÕéûÕéûÕéûÓæùÓæùÓæùÓæùÓæùÓæùÓæùÓæùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒæÿÏäý½ÏéXk
IZsL\vP^yN[tbisx¬~¢©¨Ë¡}}qq~²
±´¿¤¨²¨¬º{¯³»Î×ßò×å÷ÖèúÔèýÔèýÔèýÔèýÔèýÔèýÔèýÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþ×íÿ×íÿ×íÿ×íÿ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÖêýÕéûÔèúÕéûÕéûÕéûÕéûÓæùÓæùÓæùÓæùÓæùÓæùÓæùÓæùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÎãþÎãþÎãþÎãþÏäÿÏäÿÏäÿÏäÿÏäýÏäýÏäýÏäýÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåýÐåýÐåþÐåþÍßù[mGWqLZtIWrFQmox´¡¤¸ªyzss¤¤Â½¹Ù²°Ì£lmz{vx««¯¹ÌÏÚ©¨£ª°ÀÔÚê×âó×æúÔèýÔèýÔèýÔèýÔèýÔèýÔèýÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖêÿÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþÖìþ×íÿ×íÿ×íÿ×íÿ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÖêýÕéûÔèúÕéûÕéûÕéûÕéûÓæùÓæùÓæùÓæùÓæùÓæùÓæùÓæùÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐæøÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÏåÿÏåÿÏæþÏæþÎãúÏåùÖêÿÒåýºÍæk~JXvLWvLTqFNkQXtlqÆÈÚ£¥²áäï··Ä
£¢·ÎÍâÝÜïìëû¸¸Å£¢²yy£²²»ººÆ¤·£
¡¥±¬±¿ÕÞíÖå÷×éûÔèúÓæùÔêþÔêþÔéÿÕéþÖêÿÙêýÙêýÙêýÙêýÙêýÙêýÙêýÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×íÿ×íý×íý×íý×íý×íý×íý×íý×íý×íý×íý×íý×íý×íý×íý×íýÙíýÙíýÙíýÙíý×ìû×ìû×ìû×ìû×íýÖìûÕëúÔêùÔêùÔêùÔêùÔêùÓéøÓéøÓéøÓéøÒè÷Òè÷Òè÷Òè÷ÐæöÐæöÐæöÐæöÐæöÐæöÐæöÐæöÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÏåÿÏåÿÏæþÐåýÕêÿÐäùÏãø¬ÀÕViIXvN\yHPpLSpHOlei¨¢²²»ÚÛáÒÒÛ£º¹ÉÌÌÙ°°»£yy··À££¬ª¡¯´ªª³»»Åª¸ªª£©·ÌÚêÒãóÚëûÚíÿÕéûÔêþÔéÿÕéþÙêýÙêýÙêýÙêýÙêýÙêýÙêýÙêýÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìú×ïûÖíúÕìùÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÏæþÏæþÐåþÐåýÐäûÐäû½ÍãSc{FVpIWtS^}MUtLSpHOllp¡©jly
wyikxjlysv
ÉÍ×
xz¦¥¯©¨±£·²¶À£¦«¶¦²ÀÈÖæ×è÷×éùÙêýÕéþÕéþÕéþÙêýÙêýÙêýÙêýÙêýÙêýÙêýÙêýÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìú×ïûÖíúÕìùÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÏæþÐåýÐåýÒåýÒåý£³ÌTd}IWqIWrQ]{P\zOWwLTqFMjcfzil~x{y}
z~]_o~¥¨´kmzikxehw^artw~sv
iit£¢«ÂÂÌ}¡©ÌÕâÖâðÝëûÜëý×éûÕéûÕéþÙêýÙêýÙêýÙêýÙêýÙêýÙêýÙêýÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìú×ïûÖíúÕìùÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÓèÿÎãúÕéÿÈÜóqIZrJXrIWrO[yJVtPXxT\{FNkV]zv}osX\pqvfkwfj{sxy}hkei}X]ktycewbbo°°»½½È±´½ÇËÓ·½Ä¡¦·»Æ¶ºÅÀÇÒ×ãïÙæ÷ÙèùÖèúÙìÿÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÙìÿÙìÿÙìÿÙìÿ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìúÕìùÕìùÕìùÕìùÔëøÔëøÔëøÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåýÎäøÓæûÄ×ï^oHXqM[vDQlP\xNZxIUsLTsMUtHPm]ekrSZsSWoW[pfj{qttxjm]arZ^lmq^bv[^sdh}fj{dhyilehy~~£¢¢©©´¢¥»¿Çª°·±·¾ÁÅËÌÏ׶ºÅÁÈÓÚåóÚèøÛìýÖêýÖêýÖêýÖêýÖêý×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþ×ëþÙìÿÙìÿÙìÿÙìÿ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìúÕìùÕìùÕìùÕìùÔëøÔëøÔëøÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåýÕéþ²ÆÛTdzEUmM[tAOjWcMXwJSrS[zIQqJSr[c^fNWrLSoPTqINhW\simX]tae}V\oX^qU[m]bwW\s]bykqflV[pTWkqp¡ªª¶¤
²¶»·¸»ÌËÏÚÝå½Á̹ÂÏÔâòÛêûÕéûÖêýÕëýÕëýÕëýÖìþÖìþÖìþÖìþ×ëþ×ëþ×ëþ×ëþÙìÿÙìÿÙìÿÙìÿ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìúÕìùÕìùÕìùÕìùÔëøÔëøÔëøÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÐåþÒåý³ÄÚN^tIZpIWqHVqQ_zJXvLWvNZxEPoLWvQZyV^{W_}U\yOVsQUsTWt{\azSWqPUoPUlOTiV[pmrTXrOTmmrx}_d{X\qz}¨¢z~{wwÆÅÌÌÌÕ¥ª´°·ÁÅÐÞ×åöÛëúÙêúÖêýÖêýÕëýÖìþÖìþÖìþÖìþ×ëþ×ëþ×ëþ×ëþÙìÿÙìÿÙìÿÙìÿ×íý×íý×íý×íý×íý×íý×íý×íý×ïû×ïû×ïû×ïû×ïû×ïû×ïû×ïûÙíûÙíûÙíûÙíû×ìú×ìú×ìú×ìúÕìùÕìùÕìùÕìùÔëøÔëøÔëøÔëøÔëøÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÐèôÒæþÒæþÒæþÒæþÓèÿÓèÿÓèÿÓèÿÒäþÔæÿÕèÿÐãýÐãýÕèÿÕèÿ¨¸ÒZhN[tN[tO]xQ_zM[vLZtL\vJZwBQoP^{Q]{W_W]~W[{UXwQUs\_}hlTXrLOmIMkDGdDH_EI^lqTXr~TWtaeqv¦ª´~qp¡©ÅÅг·Á¡¥°¤©³ÅÌÕÙâìÜêúÞíÿÚëûÖëúÖìû×íý×ðþÙñÿ×íýÙíýÙíýÙíýÙíýÙíýÙíýÙíý×íý×ïû×ïû×ïûÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðúÙðúÙðúÙðú×ïù×ïù×ïù×ïùÖíúÖíúÖíúÖíúÕìùÕìùÕìùÕìùÕìùÔëøÔëøÔëøÓê÷Óê÷ÒéöÒéöÓê÷ÒéöÒéöÒéöÒéöÐèôÐèôÐèôÒæþÒæþÒæþÒæþÓèÿÓèÿÓèÿÓèÿÒäþÖéÿÒäþÓåÿÐãýÐãý}©O_yNZvNVsLWsQ]yLWsN\wN\wHXrIZsHWtSa~S^}[abehiWXxW[yVZwZ^xTWtPTrOSqNQoBGaINc{^c}[_y²
X\yQVpjo}¢¤±°¿wvªrp}£¿¿Ë¢¥»ÁÆÉÐÚÝé÷ÙæøÜëýÝïÿÚïþÙïþÖïýÕíû×íýÙíýÙíýÙíýÙíýÙíýÙíýÙíý×ïû×ïû×ïû×ïûÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðúÙðúÙðúÙðú×ïù×ïù×ïù×ïùÖíúÖíúÖíúÖíúÕìùÕìùÕìùÕìùÕìùÕìùÕìùÔëøÓê÷Óê÷Óê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÐèôÒæþÒæþÒæþÒæþÓèÿÓèÿÓèÿÓèÿÔæÿÓãýÖæÿÕåÿÛëÿw¡M]wDQlLWsLTqS[xV^{O[wS^zLWsBPkLZtO]xUa}Zbls_cop^bUXv\azW\vGJiHLjMPmFJbIObX^qZ^vy~¥¸w{UZq[_ttyty
£¡±¬ªº»»Èvv«¦ª²©¬´¤¨°¹¾ÈÛæôÛéùÛëúÙêùÛðþÙðýÖïûÕíú×íýÙíýÙíýÙíýÙíýÙíýÙíýÙíý×ïû×ïû×ïû×ïûÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðúÙðúÙðúÙðú×ïù×ïù×ïù×ïùÖíúÖíúÖíúÖíúÕìùÕìùÕìùÕìùÕìùÕìùÕìùÕìùÔëøÓê÷Óê÷Óê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÐèôÒæþÒæþÒæþÒæþÓèÿÓèÿÓèÿÔèÿÖæÿÔäþÓãý×èÿ~¨HXrHXrIWrIUqMUrQZwNVsQZwPXvNVsJVrS_yO\vU^y^eVZw^bsv¥y}UZs]byX]wPTqPTqMQkNSjPViLQdSWo~¤·jp]bw[_trvUZhZ\kkm}¦±¯½À¾Ì©©¶ffsxx
¢¤£ÆÏÞÝëûÜêúÛëúÙíûÖíúÙðýÚñþÙíýÙíýÙíýÙíýÙíýÙíýÙíýÙíý×ïû×ïû×ïû×ïûÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðúÙðúÙðúÙðú×ïù×ïù×ïù×ïùÖíúÖíúÖíúÖíúÕìùÕìùÕìùÕìùÕìùÕìùÕìùÕìùÔëøÔëøÔëøÓê÷Óê÷Óê÷Óê÷Óê÷ÒéöÒéöÒéöÒéöÒæþÒæþÒæþÒæþÒæþÒæþÒæþÓæþÚêÿÏÝøÎÜ÷hvHVqHVqHVqGUpHTpOWtU]zLTqLTqOVsLSpS\wOXqV]wU\v]b{ptjokmz}kpX]wLPhNSjTWtOSpW\vLPhMQfPUjV[rae}U[mU[mkp
X]r^bv^bvehybdseer«©¦³¢¬km}fixtw¢¤±¥³ÎÚèÜêøÙéöÞñýÙíùÙðúÕìùÚïþÚïþÚïþÚïþÚïþÚïþÚïþÚïþÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñûÚñûÚñûÚñûÙðúÙðúÙðúÙðú×ïû×ïû×ïû×ïûÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÕìùÔëøÔëøÔëøÔëøÔëøÔëøÓê÷ÒéöÒéöÒéöÒæþÒæþÒæþÒæþÒæþÒæþÒæþÓæþÕåÿÎÜ÷drFToIWrESmFToMXtS^zU]zHPmLSpJQoU\y\csw[_w\ax^czdichchdf_bzSWoNSjX]r\ax\azOTmPUlae}QVmHMdLPjINhMQfdj}y~ejVZojm¨¦°¨y{
z}}{¨ª·©ÀÉÙÙäòÙæôÚê÷ÜïúÙíùÛòýÚïýÚïþÚïþÚïþÚïþÚïþÚïþÚïþÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñûÚñûÚñûÚñûÙðúÙðúÙðúÙðú×ïû×ïû×ïû×ïûÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÕìùÔëøÔëøÔëøÔëøÔëøÓê÷ÒéöÒéöÒæþÒæþÒæþÒæþÒæþÒæþÒæþÓæþÕãþwHTpMXtO[wLWsNZvT_{P\xLTqIQoLSpOSq\_~il¡mpSVkdh}
W[p[^sUZoNShV[r_h~^fzwqxPWqPXockDJdGNjNUqFMiXawt}V[rSUmtw¦¨ª¤±°·xz}{£¨´´Á¤¦°½ËÖâÜëöÝíøÝðù×íöÚïúÚïýÚïþÚïþÚïþÚïþÚïþÚïþÚïþÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñûÚñûÚñûÚñûÙðúÙðúÙðúÙðú×ïû×ïû×ïû×ïûÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÔëøÔëøÔëøÔëøÔëøÔëøÓê÷ÒéöÒæÿÒæþÒæþÒæþÒæþÓæþÓæþÕåþ}¥DOkIUqMXtJVrMXtP\xS^zLWvHPpGNkELiNQodh
ª¦©Ä³[^r{ilSVkQUjMQfGLaJSf_h{ltW_vT[t^eJSiGNhNUqLSoFMjFMiIPjrzV^tLPhOQlxz°
¸·¾xwts¨´´Á«º¨©°ºÍÙâÛêòÚêôßòûÜòúÚïýÚïþÚïþÚïþÚïþÚïþÚïþÚïýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÙðýÚñþÚñþÚñþÚñþÚñþÚñþÚñþÚñûÚñûÚñûÚñûÚñûÙðúÙðúÙðúÙðú×ïù×ïû×ïû×ïûÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÖíúÔëøÔëøÔëøÔëøÔëøÔëøÔëøÓê÷ÓèÿÐåþÓåÿÓåÿÒåýÓãûÔäúm{LWsJSpJSpNVsT\yZbXa~NVvGOqFLoGMmIPlQXrbj~¢´´ºÍ¢fkim\axNSjJOfQVmLPeV[p^cxchFIfMTqHOlFOjNUqZa}FIfQUrMPmTWtejMQkMQkWZt}xz[\rbasfev¤°]\oa_r¬ÄÄл»Ç¤¤¡¤¯¦·Ë×ÞÝìôÝð÷ÝðùÜïúÜíýÜíýÜíýÜñÿÜñÿÛòÿÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÜóþÜóþÜóþÜóþÜóþÜóþÜóþÜóûÛòúÛòúÚñùÚñùÚñùÚñùÚñùÚñùÙðøÙðúÙðúÙðú×ïù×ïù×ïù×ïù×ïù×ïù×ïù×ïùÖíøÖíøÖíøÖíøÕì÷Õì÷Õì÷Õì÷ÔëöÔëöÔëöÓêôÐãýÖéÿÓæþÔäýÔäý×åÿp~TazNVsLTsLTsNVvV^~V^~NVvEMlGMpNTwLSpFMi[cypx¦¶«´Ä^cx_d{\axW\sTXpNSjNSj\avioZ^sdiFIfGNkIOpGOlSZvfk
^c}}[_yPTqeiOTmNSlbdª]_x]^t{zzyª¤¯]Zm[Zlkj}¬³³¿º¹Â¾½Ä¬¬¶¨´±»ÄÐÝäßñøÚêôÝíúÝíúÜïúÜïúÜñýÜñýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÕìôÕìôÕìôÕìôÔëóÔëóÔëóÓêò×éûÒãöÕåû×æýÖäþªIVpW_}PXxMUwMUwPXzU]NVxGOqDLmNTwIOpBIfJQmLTjmv¯·ÉpxW\schZ^vMQiSWoOTkPUjaez\btioae}AEbLSpLSpGOlJQkW\ssw£¥¾twX[vikJMjQToprMOh\]syx£¡±¨sproa_r^]p¯¯º³²»·¶½ÀÀÉ£ª¯¶¿¿ÌÓÛêòÜì÷ÝíúÝíúÜïúÜïúÜñýÜñýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÕìôÕìôÕìôÕìôÔëóÔëóÔëóÓêòÕåô×è÷Öå÷×äù°PZtS\wLTqQZyNVxNVxQZ{OWyHPrFNpIQqQWxW^{LSoMTmHOiS[qz[cwX]wV[tHMf@E\INebf~PUjrxiodjzPUjHMfOVrHOlMUrFMiHMdX\qjmei~PSkikwyloTWl_av{z¢¡«¡rqZXkmp¡¡¬º¹ÀËËÔ¦¥¯¬·¿ËÖßÛêôÝíúÝíúÜïúÜïúÜñýÜñýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÛòýÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÜóûÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÕìôÕìôÕìôÕìôÔëóÔëóÔëóÓêò¤¯¯¾È½ËÙz
S\rV]wQXtV]zS[zT\{PXxLTsFNmIQqOWwT\{W^zQXtJQkELeELeNUoU]sGNhGLePTqNSlUZqMQipt[_tzjq{}X^oHMdT[wOVsNVvSZwUWrHI_TUkrswxhi~stUXmMPeUXmst¢«¹¤¯ª¥·¨¤¸¢²¡²qpmp¦¡©¬«²´´¾³·¿¤¯«²»ª±»ÙäðáïýÜìùáóÿáóÿÜñýÜñýÛòýÛòýÜóþÜóþÜóþÜóþÜóþÜóþÜóþÜóþÝôýÝôýÝôýÝôýÝôýÝôýÝôýÝôýÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÖíöÖíöÖíöÖíöÕìôÕìôÕìôÔëóeqzit~NZeOXhPXlX]tX]w[^{QXvS[xS[xPXvNVsQZwT\yT\yMTmMTmBIcAHbMTmELeBIc@GcIMjOSpOTmjorwhldj}MScPWaahrMScV[pT[tQXvOWtT[wVXqVWlijqs
actqs
vxSVjTWlW[ohj{¡¦¦³¦¨¶±À£°¢«¢¢¹¹ÂÅÅΦª´¯³¾¦«·¶¿ÌáïýÞïûáóÿáóÿÜñýÜñýÛòýÛòýÜóþÜóþÜóþÜóþÜóþÜóþÜóþÜóþÝôýÝôýÝôýÝôýÝôýÝôýÝôýÝôýÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÖíöÖíöÖíöÖíöÕìôÕìôÕìôÔëóybkxNTdV\oX\qW[p^aySZsU^yU^yQ[vS\wU^yS\wNWpFNdAI_BJa>E^GNhGNj7>Z;B_?Ba?B_BGaX]wINech}¢GM]DIWOUeafy_dyJSiMTmWawdl[]ofevsrhfwfevml}«¡²qt_cxadx[]o¦¦³¨¦©¸£}yzw{z
¦©©²ÀÀɲ¶À¸»Æ´·Ä¢°ÁÏÝÜìùáóÿÞñýÜñýÜñýÛòýÛòýÜóþÜóþÜóþÜóþÜóþÜóþÜóþÜóþÝôýÝôýÝôýÝôýÝôýÝôýÝôýÝôýÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÖíöÖíöÖíöÖíöÕìôÕìôÕìôÔëó
t{ptlqhlzehyTVh_avZ^sXatU]sPXoQXrT[tNUoELeAHbDH_AF_@GaELh=Da=Da@Gd>A_>A^JNkHMfAF]PUjOTiOUhX^qsyejOTiS[qFNdLViT\pX\pZ\m^arihzdcvjiy£¢´rsy}~xzwy£~{
£¢¸·¾»»Å¾¾Ç¿¿Ë½½È¶¶Áª¯º¦ÓãðáñþÜïúÞñýÜñýÜñýÛòýÜóþÜóþÜóþÜóþÜóþÜóþÜóþÜóþÝôýÝôýÝôýÝôýÝôýÝôýÝôýÝôýÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÖíöÖíöÖíöÖíöÖíöÖíöÖíöÖíöÕìôÕìôÕìôÔëó£ÆÉÔ±±½¥¨svhjyps
VZmUZqPUoLOlFIhFIhGHhEFeAEc@Db@Dd>Dd>Eb>Eb?FbHOkFMiAHbAHbBIcNVlXatS[m]eydlU]sLSlJQkLSlTWtHJhOQj]^tcdyxz±±¾mp}~£¡¥
vvss
©¤¬¶º¹Â¾½Æ¤£¬¹¸Á¾½Æ²¶À©¨³ßïùáñûÛíùßòþÝòÿÚïúÞóÿÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÝöúÝöúÝöúÝöúÜôùÜôùÜôùÜôùÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÕïöÕïöÕïöÕïöÔíôÔíôÔíôÓìó¢¢£©³´ºÙÚßÈÉϬ³½¾Ä··À¨ª·[]obc{bdMNmIMkJLkLMlIJjFGi@Dd@Dd>Dd>Eb?Fb>EaGNjDJfBIeAHd?FbFMfDLb@H\IQeckQZpIPjFMfOVrMPoLOmPSm]_x]^spr
~}~vx¢¥°£¥²prvx
ss~~ª¤¤¤£¬ÓÒÛ¤£¬¬¶³²»°°¹±¶ÀÒÝéßïùáñþáóÿßôÿÝòþÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÝöúÝöúÝöúÝöúÜôùÜôùÜôùÜôùÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÕïöÕïöÕïöÕïöÔíôÔíôÔíôÓìóÁÂƤ¥©ÞßãÎÏÓÅÆÉ¿ÀÄ´¶»··Â{zcd}hhVWyLMoILiJMjHJhEFe@Db@Db>Eb>Eb?Fb>EaELhAHdAHdAHd>Ea@GcELh>E^ELe]e{JSiGOcNVjV^rPUoNSlOQjX\qQShbdvom{z{}mpQTc[]j
ddqbboyy¨£¦²±º¦¦¥¯¡©´¹Äª¬¶ÀâíùáñûÞñýÛðûÝòþÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÝöúÝöúÝöúÝöúÜôùÜôùÜôùÜôùÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÕïöÕïöÕïöÕïöÔíôÔíôÔíôÓìóÉËÍ´¶¸¦¨ª·¸ºÜÝßÚÛݸ¹»²³·ÇÇЪ©¹zxdd__NOoDFaDFaAD^?A^@Da@Db>Eb>Eb@Gc>EaDJf?Fb=D_@Gc>Ea@GcFMi@GcJQkXawPXoJSfXasPXlGLcQVm\_tQUjSTi\^ptsvtik}UWfikxx{
¡^^kzz¡£¢«¡©±°¹
£¢«¢¡ª©²¶À²½ÚãíãòýáóýÞóÿáöÿÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞôýÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÝöúÝöúÝöúÝöúÜôùÜôùÜôùÜôùÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ï÷×ï÷×ï÷×ï÷ÕïöÕïöÕïöÕïöÔíôÔíôÔíôÓì󩫪¾À¿mpoz}{ËÍÌßâáÖÖÖÒÒÔÁÀÇÀ¾Ë²±Ä«de~OOkHLaGJ_HJcFHa@E^=@]:A]=D_>Ea?Fb>Ea;B^>Ea?Fb@GcAHdMTmSZsHPfFNdS[qOWmQZpLTjJOi_d{JNc_cw]_qjl{llyy{VXjWZirtlpz¦¢¤³¡ww}}¡¡¡¥£ÆÅΣ¢«¦ª©²°¯¸ßß黻ǣºÄÎÝìôáóýßöþÛòúÞôýÞôýÞôýÞôýßöþßöþßöþßöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞ÷ûÞ÷ûÞ÷ûÞ÷ûÝöúÝöúÝöúÝöúÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ñø×ñø×ñø×ñøÖð÷Öð÷Öð÷Õïö~±²´
deh¯°²ÎÎθ¶·ÓÐÔÜÚÞÒÐ×°ºª©¹wvWXmOSdNQeNQeLOd@E\>B\:A]>Ea?Fb>Ea;B^=D_@Gc?Fb>Ea=D]=E[FNdDLbMUkS[qQZpT[tU\vV[rejTWlX\pcewjlyyy
y{\^plo~y{£vx~¢¢£¥ª¡©¦¥¯¨±°¹£¢«©¨±ª©²±°¹´³½¬°ºßëôÛíôÞôýß÷ÿÞôýÞôýÞôýÞôýßöþßöþßöþßöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞ÷ûÞ÷ûÞ÷ûÞ÷ûÝöúÝöúÝöúÝöúÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ñø×ñø×ñø×ñøÖð÷Öð÷Öð÷Õïö¡¢¥{}dei
ÅÀÁÛÙÜÓÐÔÍÌÐÆÅÌ°°¹eisV[fTXfQUfOSfAF]>B\;B^?Fb>Ea;B^=D_=D_?Fb>Ea=D_;B\BJaEMa@H^MUkIQhJSiNUoV^tdi~{W[odhysv
z}¢¢¯qpVXjxzrtvx
¢fixdfvww££°¾¾Ë¤¨¦¢¯·ÁÀÉ¥¤´³½¬¶°¯¸¦£«ÍÉÔ½½Æ£©¶½Þð÷ÞôúÝöúÞôýÞôýÞôýÞôýßöþßöþßöþßöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞöþÞ÷ûÞ÷ûÞ÷ûÞ÷ûÝöúÝöúÝöúÝöúÜóûÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ñø×ñø×ñø×ñøÖð÷Öð÷Öð÷Õïö°±´°±´¥¦ª{}efjmor_^c¯¬°ÕÓÖ¦¤¨^blV[fSWePTeBF[?D[?B_>Ea;B^=D_=D_>Ea:A];B^=D_>EaFNdAI_;DZJQkHOiBIc;B\AHbV[pafy]arhlzy{jiywybdvjl{}fiv~oq~zz¤~~««¸¤¡©¡£¢«¥ª©²¨¶´»¥¢ªÒÐ×ÀÁǯ´»¥°¶Úéðßñ÷ãöýÞôúÞôýÞôýÞôýßöþßöûßöûßöûÞöþÞöþÞöþÞöþÞöþÞ÷ûÞ÷ûÞ÷ûÞ÷ûÞ÷ûÞ÷ûÞ÷ûÝöúÝöúÝöúÝöúÜôùÜóûÜóûÜóûÛòúÛòúÛòúÛòúÚñùÚñùÚñùÚñùÙðøÙðøÙðøÙðø×ñø×ñø×ñø×ñøÖð÷Öð÷Öð÷Õïö¶´¹¨¦«£~}zy~tsxqpt«ª¯ÄÂÉVU^WV_ljwyy
lpzTWbSVaUWfGJ^GIb@Da>Eb?Fc>Gb=Fa;E];E];E_;E_;E_?Ha?Ha?Ha?Hc@Id>Gb>GbAHdMQiNSh_ctqvvt
srzykjzvt
~yy¢¢±°¹©¨¯¦¡«¢¡ª£¢©ÐÏÖª©°¥¤«°¯³±°´ª«¯³¸º²¶»°¶½´»ÂÖáæßïöáóúÝöúÞ÷ûÞ÷ûßøýáùýâøýá÷ûá÷ýá÷ýá÷ýá÷ýâøþâøýâøýâøýáùýáùýßøûÞ÷úÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöúÝöúÝöúÜôùÜôùÜôùÜôùÛóøÛóøÛóøÛóøÚò÷Úò÷Úò÷Úò÷×ñö×ñö×ñö×ñöÖðôÖðôÖðôÕïórqv¥¤©{zwvz¥¤«º¹Â¡a^k_]jb_mdbpss\_hNQ\\^kNQeGIbDGd>A_?Fc>Fc=Fa;E];E];E_;Da;Da>Gb>G_>Gb>Gb=Fa=Fa?GdELhUZsOTi]ar
svyxkjzom~dcs~~~}}¥°¯¶¬«°¨¦¡¬«´¥¤¢¡¨´³¸ÅÄÈÓÒÖ½»À¬°ª«º»¿»¿Å¤¨°ÀÆͤ«äï÷âôûÞ÷ûÝöúÜôùâúþÞ÷úß÷øãùþá÷ýá÷ýá÷ýá÷ýâøýâøýâùúâùúáùýáùýßøûÞ÷úÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÜôøÜôøÜôøÜôøÛóøÛóøÛóøÛóøÚò÷Úò÷Úò÷Úò÷×òô×òô×òô×òôÖñóÖñóÖñóÕðò}{wvzrqvvty
°¯³¡¤¢a^lZWe^^j[^iZ]h]_lPTeJNcGLe@Db?Fc>Fc=Fa;E_;E_;E_;Da;Da=Fa=F^=Fa=Fa=Fa=Fa?GdELh\azOTicfx
jly\^k{z_^oVUebaqqp~}}ss©¨¯«ª¯¯´£¡©ÆÅΨ¥²¬¶¤¥¤«¡¤ÂÁÆëêïÌËÏÆÆȱ±³ÅÆɾ¿Å¯²º½ÀÈÁÌÔßñøßöûÞôúßöûßöúãùþâúûÞ÷úá÷ýá÷ýá÷ýá÷ýâøýâøýâùúâùúáùýáùýßøûÞ÷úÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÜôøÜôøÜôøÜôøÛóøÛóøÛóøÛóøÚò÷Úò÷Úò÷Úò÷×òô×òô×òô×òôÖñóÖñóÖñóÕðò¿¾Â\[_edi±°´¶´¹[Zc
¿½Écao]]iVZdkoy_boNQcNQfGLeGJh?Fb>Fc=Fa;E_;E_;E_;Da;E_=F^=F^=Fa=Fa@Id>Gb>FcAHdGLeX]rcfxdiw]_leht~baq\[ksrxw{zyy£¢©ª©³²¹¤ª©²¡«¤¢¯·¶¿¤£ªª©°¦¥ª©¨¬ÇÆËÁÀŽ½¿¿¿Áº¹¾ÆÇ͹¹Â¾ÁɾÁÉÒáéÞñøä÷þäúÿâøýá÷ûßøùáùýá÷ýá÷ýá÷ýá÷ýâøýâøýâùúâùúáùýáùýßøûÞ÷úÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÜôøÜôøÜôøÜôøÛóøÛóøÛóøÛóøÚò÷Úò÷Úò÷Úò÷×òô×òô×òô×òôÖñóÖñóÖñóÕðò©¨¬´³¸edi~¡¤¬±¬«°¦~}WUb¬ª·ÍËÙhesbbmps~Z]ecfq_drMPdINeJOiAHd=Fa=Eb;Da;Da;Da;E_;E_;E];E];E_;E_>Gb;E_AIfJQmJOiW\qZ]olq_boz}ml}ihxrq~}vt
tttt¦¬«²¬«°ª©°¦¥£°½ºÇ¦¥¯¦¥ª¿¾ÂÆÅÉÀ¾ÁÅÂÆ¿¾ÂÔÓÚ²²»»»Å¾Áɤ¯
ÉÙáäöýÜïöá÷ûãùþãûýäýÿâøþâøþâøþâøþâøýâøýâùúâùúáùýáùýáùýáùýßøûßøûßøûßøûÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÛó÷Ûó÷Ûó÷Ûó÷ÚòöÚòöÚòöÚòö×òô×òô×òô×òôÖñóÖñóÖñóÕðò»º¿ÂÁÆ¡¤©¨¬£¢¦¨¦¢¦°¯¸[Xe^\j¸¶Ä]]iX\f_ck\_jlq}fj{DH]GLcDJd>Gb=Eb;Da;Da;Da;E_;E_;E];E];E_;E_=Fa;E_?GdGNjPUoQVkSVhlqvx
y{edtedtxwxwsrqq~¨¨±ÆÅ̽»À±°·½»Â¨{y¤£ª¦¥ª»º¿ËÉÎÈÆÉËÈÌÂÀÅÀ¿Æ»ºÄ¿¿ÈÂÂÌ°´¿}¥ßï÷èùÿáôùá÷ûáùúáùýâøþâøþâøþâøþâøýâøýâùúâùúáùýáùýáùýáùýßøûßøûßøûßøûÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÛó÷Ûó÷Ûó÷Ûó÷ÚòöÚòöÚòöÚòö×òô×òô×òô×òôÖñóÖñóÖñóÕðòÐÏÔ¯²¥¤©¦¥ª¡¸·ÀÆÄÐ^\ib_mqo}SS^Z]h[^fadohlx}FL^=AVFMf@Id=Eb=Eb;Da;Da;E_;E];E];E];E_;E_:D^:D^=EbAHdFJdNShMPb]bpxwyxtt±°·º¹¾¦¥¬¹¸¿¬¶¥£°¡¢©¨¬»º¿ËÉÎâßãÔÎÓÄÁÆÌÈÐÏÎ×ÎÍÖ»»Å¦ª´£ª´y¬¸Áè÷ÿåùþßöúßøùßøûâøþâøþâøþâøþâøýâøýâùúâùúáùýáùýáùýáùýßøûßøûßøûßøûÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÛóôÛóôÛóôÛóôÚòóÚòóÚòóÚòó×òô×òô×òô×òôÖñóÖñóÖñóÕðòÈÇ̪©¯²©¨¬£¢¦³²·¬±£¢¦{z¤¤¢¯ljwVTbVVcNP]Z]hilwbepcfqimyrvFL^BJaDJd?Fb>Eb=Da;Da;E_;E];E];E_;E_;E_9B]:D^;Da=D_@Ga?D[FI]ps
«¤xw~vv¿¾Å²±¶ª©°¡©¸·À©¨±»ºÄ¬³¸·¾¡¦¬±¾½ÁÄÂÇÍËÎÍËι·»½º¿°¯¶³²»ÁÁËÁÁ˾ÁÌ¢¦²Ë×ÞåôûèûÿâøýßøûáùýáùþâøþâøýâøýâøýáùúáùúáùúáùýáùýáùýßøûßøûßøûßøûÞ÷úÞ÷úÞ÷úÞ÷úÝöùÝöùÝöùÝöùÛóôÛóôÛóôÛóôÚòóÚòóÚòóÚòó×òô×òô×òô×òôÖñóÖñóÖñóÕðòÇÇÉÏÏÒÀÀÂ¥¥¨¨¨ª··¹¯¯±
rsy¢hhtNM]NP_SUdacrllxffrllxrt}fizAEZHJcJNkDGd>A_9@];B^@Ga?Fb?Fc>Eb>Eb=D_;B^;B^=D_;B\AF_DHb@B[LOcmp¨zzrr~xxtt¶·½¹ºÀ°±·¥¦¬«¬²³´º±²¸¯´²±¶·¶ºº¹¾£¡¤½»ÀÇÆËÁÀŲ±¶´³¸º¹¾³²·ÐÏÖÆÅÌÄÂɾ½Æ´´À¥Ýêñè÷ÿåøÿá÷ýáûþáûþâúþãúûäûýãûýâýýâýýâúûâúûâúûâúûáùúáùúáùúáùúßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÛööÛööÛööÛööÚôôÚôôÚôôÚôôÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÞÞáÈÈ˽½¿³³¶ÀÀÂÇÇÉ«««¯¯¯º»¾[^fTVcPSbX[lVXjbdsoo{±±½¦~~hhtkjz^_tHI_HJeMOlFIf?B_9@\;B^>Eb>Eb>Eb>Eb>Ea=D_;B^;B^;B\@Ga>A^@E^QUjNQcUWd
¡
iitffrllx°°¹´¶»±²¸£¤ª
¯°¶¦¨²³¹¹¸½²±¶¸·»ÁÀŹ¸½¢¡¥»º¿ÉÈ͹¸½¬«°·¶º´³¸Ù×ÜÄÂÇÈÇÎÀ½Ç¥¤²²»¥¯¹ßëôæ÷ÿäúÿáûþáûûâúûãúûäûýãûýâýýâýýâûùâûùâûùâûùáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÛööÛööÛööÛööÚôôÚôôÚôôÚôôÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðßßâÒÒÔ££¥°³³¶¯¯¯¯°³z~jlyNP_QTewyhjyzz¡ÈÈÔ\\hllytsy{PQfEG_HJeGJhAEb=D_>Ea>Eb>Eb=Da=Da>Ea>Ea=D_;B^=D]9@Z@Da?D]PTi^bsdfswz
]]immy{{jjvzz¢¢«³´º¹ºÀ²³¹³´º©ª°¸·»²±¶¬±¯²¾½Á¸·»±°´¥¤©¾½ÁÇÆ˺¹¾½»À·¶ºÀ¿ÄÎÍÔÇÆÏ°¯¸½½Æ©x±½Æéøÿä÷þâúþáûûâúûâúûãûýãûýâýýâýýâûùâûùâûùâûùáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÛööÛööÛööÛööÚôôÚôôÚôôÚôôÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÌÌÎ××Ú³³¶ªª¬°°²¬¬¯¡¡¡¥¥¥£¤¦¤¥©¤
WZiTVhpr\^m~ffsZZe¡¡¤¦¶twEH]FHaLPjGJh?Fb;B^=Da=Da=Da=Da=D_>Ea>Ea=D_>E^:A[;?\@E^NQfcfx
£¦±ww{{¢´¶»³´º³´º¤¥«¤¥«¡¢¨´³¸³²·±°´·¶ºÌËϽ»À¾½Á¹¸½¿¾Â»º¿ÆÅÉÌËÏÂÁÆìëðáßæÄÂÌÇÆ϶¶¿°³¾yë÷ÿãôûãùþáûûâúûâúûãûýãûýâýýâýýâûùâûùâûùâûùáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÛööÛööÛööÛööÚôôÚôôÚôôÚôôÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÄÄÆÌÌÎÏÏÒ¸¸ººº½³³¶ÂÂŬ¬¯¨LN]IL]qslo~kjzNM]FFSOO\eeq~~y{
_cw>@XOTmFIfAHd>Ea>Eb>Eb>Eb>Eb9@\:A]>Ea>Ea=D]=D];?\HMfHLa\_q¬°º¯¯º£¦¥¦¬¯°¶²³¹¸¹¿¡°±·´³¸¹¸½±°´º¹¾ÅÄÈÇÆ˽»À¹¸½ÅÄÈÈÇÌÅÄȤ£¨¨¦«ÖÕÚãâæÝÜãÔÓÜËÉÓÀÀÉÍÐÛ¦¢ÈÎÜë÷ÿãùþãûýâýýâýýâýýâýýãûýãûýãýúâûùáúøáúøáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÜ÷÷Ü÷÷Ü÷÷Ü÷÷ÛööÛööÛööÛööÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÀÀ··¹ËË;¾À¨¨ª¶¶¸ÈÈËÇÇɲ²²ªªª¬°¡¤¤ªGIXIL]SUdehwXWhML\^^k]]ipp{¯±ÀªILdINhHLiAHdAHd?Fc>Eb>Eb>Eb:A]:A]=D_>Ea>E^@Ga>A^AF_AEZ]arrt{}}
£¥¥±«¦¦°ª«±¸¹¿¶·½¯´±²¸ª«±»º¿ÌËÏÂÁÆ«ª¯¹¸½ÍÌÐÄÂǺ¹¾·¶º½»À¾½Á±°´¿¾ÂßÞãÄÂÇÝÜãíìöÂÁËÇÇÐÐÐÜÅÇÔª¯½ëôÿåùþâúûâýýâýýâýýâýýãûýãûýãýúâûùáúøáúøáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÜ÷÷Ü÷÷Ü÷÷Ü÷÷ÛööÛööÛööÛööÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÁÁĺº½ÅÅǾ¾À¥¥¨»»¾ÁÁÄÅÅž¾¾³´·°±´¬°¸£LN]OQc\^macr
ji{TScbboZZejjs¯²ºº½É_ctVZo@E^>A^FMiBIeBIf?Fc>Eb>Eb:A];B^=D_=D_?F_>E^@Da@E^GJ_\_q{~z~ss
¤¤¤ÍÎÔ»½Â³´º¤¥«¡¦¯´¤±°´¿¾ÂÏÎÓ¬±±°´¢¯²ÂÁÆ¿¾Â³²·¸·»«ª¯º¹¾¿¾ÂÍÌÐ÷öýÙ×áÄÂ̽½ÆÆÆÒ××ä©¢ÉÐÛèùÿâúûâýýßþýßþýâýýãûýäûýãýúâûùáúøáúøáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÜ÷÷Ü÷÷Ü÷÷Ü÷÷ÛööÛööÛööÛööÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÇÇÉÄÄƽ½¿½½¿¦¦©¹¹»±±³³³³ÁÁ¿ÇÇDz³¶°±´ªª³¡¡NM_IL]UWiik}PObqpedt^^kaaljjs·©¬·}{}SUmFHcHLiGJhDJfAJe>Gb>Ea:A];B^>Ea=D_?F_9@Z@DaFJd=?WLOc~wz
ooz£¢
³´º¿ÀÆ¡¢¨½½Æ¦¨¨¦«ÅÄÈÎÍÒ´³¸¬«°·¶ºÀ¿Ä²±¶»º¿ÅÄÈÇÆ˶´¹À¿ÄÎÍÒÜÛßÔÓ××ÖÝãâé¿ÀƬ¬¶ÀÀÌ´´Á¡¬áð÷åùûâúûâýýâýýâýýãûýãýúãýúâûùáúøáúøáúøáúøáúøáúøßøùßøùßøùßøùÞ÷øÞ÷øÞ÷øÞ÷øÜ÷÷Ü÷÷Ü÷÷Ü÷÷ÛööÛööÛööÛööÙñòÙñòÙñòÙñò×ðñ×ðñ×ðñÖïðÀÀÀ«««ËË˾¾¾ÁÁÁ¹¹¹½½½ÄÄÁ¿¿¿ÎÎЬ³¯¬¹PMaNMbHF]qo\[pzy\\illv}~¤¬½²NLeNLhJMjJTlGTkANe=F^=D]:A[;?\=@]?D]?D]?B_?B_AF_?DXfmx~swvv~~ww«¥¤«£¢«¤¯¬¹¡©¢¡¥²²´ÏÏÒÀÀÂÆÆȱ±³££¥±±³½½¿ÈÈËÇÇÉÂÂÅÄÄÆÇÇÉÍÍÏÌÌÎñðôöôùÈÇ̬³¿¾ÅÅÄͤ¸ÂËæöýäöùëÿÿãýúãþûÞýùâþøäþùãýøâû÷âû÷áúöáúöáúöáúøßù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÝ÷ôÝ÷ôÝ÷ôÝ÷ôÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïxxxÌÌÌÒÒÒ¶¶¶ÌÌÌ°°°¦¦¤¢¢¢¸¸º²±¸°º¢OL_LH^VTkWUlMLahfy¥ddp¥ss}iho
¥¤±¯½ÉÆÚXToTTpDMeN[rDPh>G_:A[:A[>A^>A^?D]?D]?B_?B_BFc=AXZ_my~txppyzz¥¶³À»ºÄ²²´ÁÁĸ¸º¿¿ÁÇÇɬ¬¯¡¡£»»¾ÆÆȾ¾ÀÁÁÄÀÀÂÅÅÇÌÌÎÇÇÉããåÂÂÅÒÐÕ·¶ºÀ¿Æ¿¾Å«ª³¢©²áëóåöùéúþåýûáúøâÿúÞý÷ãÿùãýøâû÷âû÷áúöáúöáúöáúößù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÝ÷ôÝ÷ôÝ÷ôÝ÷ôÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïlljÏÏÍ¿¿½¸¸¶~~{
¿¿½¡¡££¥±°´©¨±«©¶HFTOM]XWjXWjSQb\\ittww{{
fhmomt¯·¾»È½ºË²¯Â[WmVWpBIcQ[vISmBIe=D_>A^?B_>A^?D]?D]?D]?D]?B_BG^MSasxxzzz£{{£
zx
£¥ª©°ÇÆÍ°¯³³³¶««±±³²²´««¿¿ÁÆÆȳ³¶ÁÁÄÇÇÉÁÁĹ¹»½½¿ÈÈËÈÈ˽½¿ÇÇɸ·»ÁÀŹ¸¿ÉÈϹ¸ÁÆÐÙíúÿèùýåùùåÿýßûöáÿùãÿùãýøâû÷âû÷áúöáúöáúöáúößù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÝ÷ôÝ÷ôÝ÷ôÝ÷ôÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïaa^yywÙÙÖËËÈÈÈÆ
wwt¡¡¡´´²¢¦¥¬¤VTaLIVNN[UUbPP\EEPaalMMVMNThiokjo¢½»Â£¢«ÄÁÏ»¹ÉwsQPeFJdMTpNUqHLiEHeAEb>A^=A[?D[?D[?D]?D]?B_DHbBHXqvsvqq~wv¤
qo}¥¤¨¦°¨£»º¿¸¸º¸¸º»»¾ÄÄÆ»»¾´´·²²´íí𸸺ÅÅÇÂÂÅÅÅǽ½¿´´···¹¹¹»¨¨ªÉÉÌÄÂǺ¹¾±°·¸·¾ÈÇШ£Üéíâòöæúúãúùãÿùâþøäþùãýøâû÷âû÷áúöáúöáúöáúößù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÝ÷ôÝ÷ôÝ÷ôÝ÷ôÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïVWSopk½¾¹½¾¹vwr}²³¯³³±¡¡£kjqddmTT]TT]OOXZ[aTU[NOSdeiomr¥¤©£¢©ÂÁ˦¤±qo}edtSVk?D]OTmOTmHLiBFc;?\>B\?DX?DX>BZ>B\AEb>B\?EWzsvoo{ml}¦rp}±°¹°º¦±±³ÁÁÄÄÄƺº½ÆÆÈÆÆÈÉÉÌÌÌθ¸ºÌÌÎÇÇÉÅÅÇÀÀÂÀÀºº½²²´ºº½èèêÜÛß¿¾Â½»Â¸·¾ÍÌÕÈÈÒy©³¹íúÿä÷÷åýûäþùáý÷åÿúäþùãýøãýøâû÷âû÷âû÷âû÷ßù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÜöóÜöóÜöóÜöóÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïTUPbc^}~y«¬¨¢£bc^stpklh~°°²°¯³ijm]^bXZ]deiZ[^\]aTUXefjooqwwy¹¹»¹¸¿°¯¸cewLOdPTiPSkOQlIMj?B_>B\?DX@EZ?D[?D]?B_?D]BH[jo}{{ddqxx
¨¤£¡xw°¯¸±°¹
«ª¯»»¾ÄÄÆÉÉ̾¾ÀÌÌÎÈÈËââäÍÍϸ¸ºËËÍÉÉÌÇÇÉÂÂÅÁÁÄÂÂÅ»»¾ÀÀÂÄÂÇÈÇÌÇÆͨ¦ÒÐÚÅÅΣ{Ôáååøøåùùãýøãÿùåÿúäþùãýøãýøâû÷âû÷âû÷âû÷ßù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÜöóÜöóÜöóÜöóÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïUVOef_lmf©ª£WXQ
~mohde^stpjkfddbaa^eeeijljkm^_b]^aefi
LMOijlrrtkkkjimfel
}}fivUWiPQfPSkOTmDGd;B\@EZAGZ@E\?D]?B_@E^BH[SWey}yymmwww
¥¥¨³²»¤¤£¨»»¾ÅÅÇÕÕ×ÏÏÒÆÆÈÔÔÖÈÈËßßâ»»¾ÍÍÏÇÇÉÈÈËÌÌÎËËÍÆÆÈÂÂÅÎÎÐÇÆˬ«°¶´»«ª±º¹ÂÎÎ×¾ÁÌ{¬±ãóôæúúæþúåÿúåÿúäþùãýøãýøâû÷âû÷âû÷âû÷ßù÷ßù÷ßù÷ßù÷ÞøöÞøöÞøöÞøöÜöóÜöóÜöóÜöóÜöóÜöóÜöóÛôòÚóñÚóñÚóñÚóñÙòðÙòðÙòð×ñïUVQ[\Wfhclmffha^_Xef_cd][\U^_[^_[Z[Viifccattrceddfe]_^TVUehf{}bcekmlsssiiilll}}}vvxxxz{zddpVXhTUjTVoINh@E^AGZAGZ@EZ?D[?B_@E^>BWBFWkmzllvxxjiytt¨¨¦°zy
¤¤¦··¹ÄÄÆÎÎÐÎÎÐÐÐÓ××ÚÔÔÖÛÛÝÏÏÒÎÎÐÏÏÒÌÌÎËËÍÍÍÏÅÅÇÈÈËÂÁƾ½Ä´³º·¶½²±ºÒÐÚÒÒÝ~Þïðêýýêÿþãýøåÿúäþùãýøãýøâû÷âû÷âû÷âû÷ßù÷áø÷áø÷áø÷ß÷öß÷öß÷öß÷öÝôóÝôóÝôóÝôóÝôóÝôóÝôóÜóòÛòñÛòñÛòñÛòñÚñðÚñðÚñðÙðïOOM[[Xiif
klhefbcd]cd]NOJTTQUUSQQOppmppmXXVddbjjhbb_[[XWWUffdjjjjjjffdhheddbaa^^^\iifxxxqqqttrmmmomr__iPO_LMbGIbAD\AEVLOaNQf?AZAD\?AZ?BWBFZacr}}kkxddq¢ªª¶¥¡°°²ÀÀÂËËÍÀÀÂÏÏÒÔÔÖÈÈËÛÛÝÅÅÇÒÒÔÆÆÈÇÇÉÆÆÈÍÍÏÆÆÆËËÍÉÈϾ½Ä¬±¥¤©³²»ÆÄÐÒÐÚ·¶¿ê÷ùéûùéþúäý÷æÿùåþøäý÷äý÷ãûöãûöãûöãú÷áøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óáöòáöòáöòáöòßôñßôñßôñÞóðÞóðÝòïÝòïÝòïÝòïÜñíÜñíÜñíSSSNNNkkissqqrm]^Zbc\ijeQQOLLIZZWMMJbb_^^\ZZWiifbb_\\Z[[Xbb_hheaa^ddbeecVVTddbaa^__]eeceecmmksrojieiii
__kTScTVhQUfLP\UZeUXjEH\AEZ?AZ?BWBDXIHXlly}}©©´¤¤°__kppy¢¡¡¡ªª³¡´´···¹ËËÍÉÉÌÅÅÇÎÎÐÇÇÉÛÛÝÍÍÏÓÓÕÄÄÆÉÉÌÓÓÕÝÝßÚÚÚÆÆÈÆÅÌÄÂÉËÉΡ¯·¿½ÉËÇÒÖÕÞ£ßíìëþûéþùæÿùæÿùåþøäý÷äý÷ãûöãûöãûöãûöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óáöòáöòáöòáöòßôñßôñßôñÞóðÞóðÝòïÝòïÝòïÝòïÜñíÜñíÜñíJJJMMM]][hhefhcbc^_aZfhcTTQOOM__]TTQUUS~~{SSPbc^]^Z[\W\]Xbc^efb^_[efbiifPPN]][eechhemmkjjhddbppmbb____{}^^hZZeX\dU[_\biZ^jFI[@DW@DXBF[HI^TSeiivzzww£¤ª²³¹ÅÆÌbboZZf¶¶¿¶´¹¸¸º¸¸ºÂÂÅÒÒÔÂÂÅÐÐÓÔÔÖÔÔÖÓÓÕÐÐÓÇÇÉÆÆÈÈÈË¥¥¨···»»¾ÄÂÇÉÈÍ¿¾ÂÇÆË£²±ºÍÉÔ¾½ÆÀÁÇÜêéåøöéþùäý÷æÿùåþøäý÷äý÷ãûöãûöãûöãûöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óáöòáöòáöòáöòßôñßôñßôñÞóðÞóðÞóðÝòïÝòïÝòïÝòïÜñíÜñíAAALLLUUSccabc^Z[V^_Xab]WWUXXVUUSNNLXXVeecLLI[\WWXTWXTZ[V_a\\]X\]X_a\^^\ZZW]][eeceecmmkjjhZZWffd[]\^a_vxwklo]^bZ[]X]\]bcX\dDFS@BTDEZLMbTVhLJ[aam~~
¡¢¥¶·¹ÆÇËÆÆÒ
XWhbbo
¡¤¥«¢¥¥¨¨¨ªÀÀ¶¶¸»»¾ËËÍÌÌÎÀÀÂÌÌÎÆÆÈÆÆÈÎÎÐÉÉÌyy{¨¨ªÂÂÅÀ¿Ä¿¾ÂÕÔÛ«ª±¹¶ÀÏÎ×Ö×ÝÍÛÚèúøêÿúèÿúæÿùåþøäý÷äý÷ãûöãûöãûöãûöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óáöòáöòáöòáöòßôñßôñßôñÞóðÞóðÞóðÝòïÝòïÝòïÝòïÜñíÜñíHHHNNNVVTffd]^ZNOJQSL_a\WWU\\ZPPNPPN^^\cca}}zVVTXZU_aZWXQ_aZab[\]VZ[T_a\bb_]][ZZW^^\eeceecddbUUSX[ZX[Z^a_ceddddiiihheTVSTVQ[]Z^_cQQ[IIVEDTML\^]m]]jaaliir}~¯±°¾¿ÁÉÉÓÎÎÛQQ^qqz¢~}ÅÅǬ¬¯¿¿ÁËËÍÀÀž¾ÀÍÍÏÆÆȸ¸º½½¿ÎÎÐÍÍÏÓÓÕÎÎÐÌÌί¯±¾¾ÀÉÈ͸·¾½»ÂÐÏÖ¹¶ÀÍÌÕÜÝãÍÓ×Õãâéûùæû÷ãûöæÿùåþøäý÷äý÷ãûöãûöãûöãûöäùöäùöäùöäùöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óßôñßôñßôñÞóðßôñßôñÞóðÞóðÝòïÝòïÝòïÝòïOOOGGGQQO]][VWSMNIUVOab]]][__]__][[XVVTaa^aa^]][TUPhibUVObc\bc\]^WWXQ^_[[[X]][VVT]][eecddbddbVXWSWXX]^[\^bdcbbbccalljWXTZ[Vbd_abdTU[JJTFFQJJVWWcaajijp\]cz{~}~¥¨¦±²´ÁÁËÐÐÝÍÍÚss^^j¤¤¢¢«¿¿Á³³¶ÅÅdz³¶ÈÈËÂÂÅËËÍÓÓÕÒÒÔªª¬¢¹¹»ËËÍÓÓÕÔÔÖããåééë··¹ÄÂÇËÉв±ºÂÁȯ´¯«¶ÁÀÉÎÏÕÙÞãÛéèèúøæû÷äý÷æÿùåþøäý÷äý÷ãûöãûöãûöãûöäùöäùöäùöäùöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óßôñßôñßôñÞóðßôñßôñÞóðÞóðÝòïÝòïÝòïÝòïZZZPPPQQOOOMPQMNOJWXQ^_[[[X^^\__]\\ZVVTcca^^\ZZW_a\de^XZSde^ab[_aZbc\TUPZZW]][\\Z__]cca__]aa^VXWUZ[PUWNSUcdfiik]]]cab[ZWVWSccaddd\[_WV]TSZSQVTSW]^bvwycdfqrttwvwyx©ª°ÉÉÓ××á¾¾É[[hxx
½½¿ÝÝߢ¢¤°°²¾¾ÀÌÌÎÂÂÅËËÍÒÒÔ¦¦©½½¿ÆÆÈÕÕ×ÚÚÜææéææéÛÛÛ¿¿ÁÍÌÕ¿¾ÇÍÌÓÈÇΣª·¶¿ÀÁÇÝãèáïíèúøèýøåþøæÿùåþøäý÷äý÷ãûöãûöãûöãûöäùöäùöäùöäùöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óßôñßôñßôñÞóðßôñßôñÞóðÞóðÝòïÝòïÝòïÝòïXXXaa^XXVTTQOPLOPLWXQZ[V[\Weec__]bb_[[X__]XXVUVQbc\de^STMXZSde^cd]]^WUVOWXTSSP]][XXV]][XXV[[XTVSNSTGLMEIJ_acaac]]]b_a_^\VVTcca^^^VVXTTVWWZZZ\WWWZ\[fih_ba_bafihqsr
ÅÆÌÖ×ÝÒÓÙ¥¥±vveeqâáå´´·ÅÅÇÍÍÏÈÈËÈÈËÒÒÔÍÍÏææéÒÒÔÍÍÏÌÌÎßßâååèññóäääÇÇÉÆÅÌÐÏÖÈÇÎÄÂǽ¹Á¬³ÅÆÉÎÔÖßëëé÷ôêûøêýùéþùåþøäý÷äý÷ãûöãûöãûöåúöäùöäùöäùöäùöãøôãøôãøôãøôâ÷óâ÷óâ÷óâ÷óßôñßóóßóóÞòòßôñßôñÞóðÞóðÝòïÝññÝññÝññUUS\]X_a\UVQQSNIJFOPL\]XZ[V]^Z^_[]^Z]^ZWXTZ[VXZUab[de^[\UMNG^_XWXQZ[TZ[TVWSWXT_a\XZUab]QSNXZU\\ZNPMVXWGIHXXXeee^^\aa^ccaUUSeecddbZZZSSS___[[[OOO[[[hhhXXVddbjjhyyw¿¾ÅÒÒÔÈÈ˶´¹£¢¦~}^]fvs¨¢ÞÞáÒÒÔÌÌÌÇÇÉÅÅÇßßâÉÉÌÖÖÙÐÐÓÒÒÔÙÙÛÞÞÞêêêêêêÕÕÕÅÅÇÈÈË××ÚÀÀÂÀÀ··¹½¾ÀÉÎÏËÒÒÙßÝìöòìøôêýùéþùèýöåúóéþ÷åúóäùòäùôãööä÷÷ä÷ôåøöãöòåøôåøôâôñâôñâôñâôòáóñáóóáòöáòöáòöáóñáóðáóñáóñßòòßñôßñôßñôOPLUVQ]^ZZ[VHIEEFAMNIXZUTUP]^Z^_[WXT^_[XZUTUP]^Z\]V]^WXZSEF?WXQUVOZ[TZ[TXZU]^Z[\WZ[V^_[STOQSN]^ZSSP\\ZPPNVVTZZWQQOWWU\\ZPPNXXViif^^\LLIUUSWWUSSP^^^cca_a\cd_rsowxsttrqqs{z¤¤¦¹¹»dbp}z
©¨¬ÂÂÅÀÀÀÇÇÉÐÐÓÖÖÙºº½ÏÏÒÛÛÝÈÈËÉÉÌÝÝÝ×××ßßßÖÖÖÄÄÄÍÍÍÌÌÌÅÅÅÁÁÁÇÇÇ°²±ÅÇÆÅÉÈÂÇÆìñðïøôìþúêÿúéþ÷éþ÷åúöèýøåúóâ÷òæù÷åøøãöóâôòæùöãöòâöïåøôâôñâôòáóñßòòáóóáòöáòøáòöáóñáóñáóñáóóßòòßñôßñ÷ßñ÷IJFQSN^_[^_[JLGBD?GHDTUPSTO\]X]^ZVWS^_[XZUTUP]^ZZ[T[\U]^WGHAVWPVWP[\UXZSXZS^_XZ[TXZS\]VNOHOPI^_[]^ZZ[VQSNSTO^_[QSNSTOXZUQSNWXTjkfXZUMNIQSNZ[V[[X__]eec_a\de^fhadeappmlllihl~}rrp~¥¥¥£¢©ecpb_lljw´³½´³º¡±±³´´·ÕÕ×ÛÛÝÜÜÞÍÍÏÖÖÙÈÈËÐÐÓÓÓÓÐÐÐÜÜÜÓÓÓÍÍÍÔÔÔÆÆÆÈÈÈÆÆƾ¾¾¹»ºÎÓÒÁÆÅ×ÜÛôþúìþøèûôåøôåøôéûùåøöä÷ôæù÷âôòãöóåøôæùöãöòåøôåøôâôñä÷ôãöóâôôâôôáóóáòöáòöáòöáóñáóñáóóáóóßòòßñôßñôßñôHIETUPbc^^_[MNI>?:EFA[\WXZU\]X]^Z\]X]^ZWXTZ[VXZU^_X^_Xbc\STM[\U[\U]^WVWPZ[T]^WZ[TUVO[\UHIBQSL_aZUVQWXTWXTQSN\]XOPLSTO]^ZPQM\]XijeXZUVWSUVQbc^^_[ccaab]fhacd]bc\de^efb___aacqqsmmmhheqqo{{~ÂÁÆ{z\[d[Zcdcjjim¨¨ª««ËËÍÇÇÉßßâÔÔÖÕÕ×ÕÕ×ÓÓÕÙÙÙÙÙÙßßßáááÔÔÔÍÍÍÕÕÕÌÌ̹¹¹ÉÉ̲³¶³¸¹ÐÕÖÌÐÒéððíûùëûúìýûéùúéùýéøÿè÷ÿåôûå÷úä÷÷ä÷÷ãöóä÷ôâôòâôñä÷ôä÷ôãööãööâôôáóóáóóáóóáóóáóóáóóáóóáóóßòòßòòßòòßñôIJFIJFZ[V\]XLMH9:6BD?]^ZVWSUVQXZU\]X[\WZ[V^_[WXTab[\]V]^WXZSNOHTUNXZSXZSZ[Q]^UbcZ\]T\]TTULWXOZ[TSTMXZS]^WLMFZ[T[\U_aZbc\OPI]^Wde^bc\^_XWXQab[]^Z[\W^_[hibde\abX_aZ]^Zbb_VVXjjljjh_a\jkfccahhj¦¥ªÌËÏzy~~ªª¬¥¥¨bbd°¾¾À¤¤¦¾¾ÀÀÀÂÍÍÏÓÓÕÒÒÔÜÜÜåååßßßâââÜÜÜÔÔÔÈÈÈÁÁÁÆÆÈÅÄÈ¢°±´²´ÂÇÉÛßââèêêôøéöúÕâé·ÂÌ£±¢´£¹¡«¾·ÅÓ°À˺ÌÓÍÞäâó÷áóóÝðíä÷ôÝððáóóáóóßòòáóóáóóáóóáóóáóóáóóáóóáóóáóóáóóáóóáóóLMHLMH\]X^_[QSN?@;EFA[\WOPLQSNZ[VVWSZ[VZ[VZ[VUVQ\]V[\U]^W\]VJLEPQJUVOUVOWXO\]TabXZ[QQSITULXZP[\SOPIWXQbc\UVOTUNWXQ[\U[\UNOHde^ab[[\U\]VUVO]^WXZS\]Xcd]Z[Q]^Ucd[]^UZ[T__]ZZZfffbb_Z[V_a\bb____¡¶´¹²±¶~~¸¸ºkkm
¨¨ª´´·²²´½½¿ÍÍÏÐÐÐÚÚÚßßßéééæææÛÛÛÌÌ̸¸ºÎÍÒ¿¾Â¡¢¥©ª«°²´¹»ÎÓÕáæëÏÖÝÇÎ×´¿¥¶¬±Æ¢»¤¦¥¨¨²¨¹ÀÆ×ÝÜíñÞðóäöùâó÷ßñôÞññáóóáóóáóñáóñáòöáòöáòöáóóáóóáóóáóñáóñVWSQSN[\WZ[V[\WGHDHIEXZUNOJSTOZ[VXZUZ[VVWSXZUOPLWXQXZSWXQXZSGHAMNGPQJQSLSTJ[\S_aWUVMMNEQSIUVMZ[Q\]VQSLXZSXZSVWPZ[TXZSUVOOPIde^^_XWXQ\]VTUN[\UUVOZ[VZ[T]^U_bU^aTbcZUVOaa^\\\bbb\\ZXZUbc^iif^^^iiikkk´´·¡¡£¥¥¨jjlÄÄƹ¹»¹¹»ÒÒÒðððÔÔÔÙÙÙåååÙÙÙÆÆÈÂÁÆÎÍÔ¡¬³°³¹¥©¯»¿ÅÞâèëñóÖÜáÇÌÖ¸½Ëßãø±³Î¨~¢z}¡¢²¿¾ÎÙÙêñãôúáòöÝððáóóáóñáóñáóñáòöáòøáòöáóóáóóáóñáóñáóðWXTTUP]^Z\]Xab]MNIJLGWXTIJFPQMNOJ[\W[\WPQMZ[VIJFUVOVWPOPIPQMDE@IJFNOJNOJPQJZ[Q^_VSTJOPGOPGNOFXZP[\UNOHUVOVWPIJDSTMWXQUVOPQJ\]V_aZZ[T^_XUVO[\UTUP\]XZ[V_aWcd[WXO\]Tab]^^\]][aa^\]X^_[dealmieecbbbTTQddb¢¢¢}}}«««SSUyy{»»¾
ppr¾¾Àppp¶¶¶äääíííæææâââÝÝÝÏÏÏÄÂÇÄÂÇÁÂƱ²¶¨©¬ÒÖÙèìïÓ×Ú»¿Ç½Á͸»Ï·
¢}{{yx
}ª£´¡¯½ËÜãáòøáòöáóóáóñáóðáóðáóóáòöáòöáóóáóóáóñáóñáóñSTOVWSWXTUVQUVQVWSPQMXZUGHDJLGOPLab]LMH[\WPQMIJFQSNMNISTOTTQIIGNNLLLLMMJSTOSTMUVOUVOQSLWXQSTMVWPVWPPQJOPISTMGHAQSLPQJSTMUVMUVM\]V^_XXZUUVQUVQMMJTTQZ[V]^W_aZab[[\UXZU^^\[[X\\Zdeade^ab[lmiffd__]UVQZ[Tjkf}~yooliifXXXlll¡¡¡~~~hhhddb¸¸¶ÎÎÌååãÕÕÓÖÖÔ¯¯¬ÇÇǺº½ÐÐÓ±±³©©«¢¥¦©ÍÎÒæèí¯¯¸©«¸¯¥¡¤¤»¤©À¯¨t{
¢¤²ÂÕåðáòøÞòòßôðßôíãøñâôñãóòãóòãóôâòóâòöâòöâòöJLGPQMVWSVWS[\WXZUNOJSTOGHDIJFUVQ_a\LMHWXTNOJEFAQSNLMHNNLUUSLLLLLLGGIJJJOPLPQJTUNTUNSTMMNGZ[T[\UVWPPQJOPISTMNOHLMFSTMOPIUVMUVMXZS]^WVWSTUPOOMHHFPPNXXV]^Zab[cd]^_[XXV]][^^\__]^_[^_XUVO^_[XXVTUPQSLVWNcd]mohbc^xytffd\\Z___qqqvvvmmm\\\^^\qrm¦¨£×ÙÔ«¬¨ÄÅÀÌÌÌ···ÎÎÎÐÐÐÛÛÛ½½½ºººªª¬ÝÜãÒÐÚ¾¾É¬«»¨¢£
¡«¶¢¤½±©y¦£±¿ÕæíÞðóÛðìáöïßôíâôñãóòãóòãóôâòóâòöâñøâñøFGBNOJTUPVWSVWSTUPJLGOPLPQMLMHZ[VTUPJLGVWSVWSNOJOPLMNIMMJSSPPPPGGG@@BGGGIJFQSLMNGUVONOHWXQ]^W^_XVWPPQJOPISTMUVOHIBOPINOHUVMUVMVWN[\UQSLUVQQSNPQMOOMVVTWXTZ[Tef_deaZZW^^\[[Xaa^XZU^_X[\U]^ZPPNJLGUVO\]Tab[bc\TUPefb[[XQQO\\Z__]eeeqqqxxxiiiqqsVVV\\Zffdlljyyw¶¶³{{yrrp´´´³³³ÆÆÆÁÁÁÈÈȬ¬¬½½½»»¾âáèÇÅÒÍÌܨ©{{¢wy~ª£¦»²¶É£´©{¡¬»ÆÚëñæùùãøôáöñâôòãóòãóôãóôâòóâòöâòöâòö@@>FFDJJHJJHVVTPPNBB@DE@QSNJLG[\WTUPJLGTUPUVQIJFIJFPQMNNLOOMSSSEEE::=EEEHIEHIEQSNQSNNOJQSNTUPZ[VVWSPQMOPLSTOXZUIJFJLGNOHJLBTULXZP]^WNOHSTOMNIJLGPPNPPNOPLPQJ]^Wbc^XXVVVT\\ZccaPQMVWPWXQWXTJJHGHDVWP]^U^_XXZSPQMcd_bb_]][TTQ\\Z___hhh[[[TTV^^aLLNNNNbb_ddbiifeecmmk]][³³³ººº¾¾¾
{{{ÂÂÅÙ×ÜÆÅÎÆÆÒ°¯¿Ö×ì¿ÀÙ±¤wxxy}£©¢°©tw¥ÏÞæÜíóßñôä÷÷ãóôãóôãóôãóôâòóâòóâòóâòö>>>AAAMMMFFFHHHJJJAAA@@>PQMPQMXZUMNI@A=HIENOJEFAGHDFGBFFDGGENNNAAA99;>>>DDA@@>LLIMMJLLIJJHNNLOOMUUSMMJIIGPPN]][SSPJJHMNISTJWXO^_X^_XPQMEFAHHFIIGLLIPPNVWSSTM^_X]^ZSSPTTQUUS]][UVQUVOZ[TUVQHHFMNIWXQ_aWab[]^WUVQ\]XZZWPPNUVQXXVQQO[[[UUUMMOONSGGIPPPZZZZZZ\\\TTT[[[\\\iii°°°sss½½ºÉÉÇÀÁÅÅÇÖÐÒæ²¥{}xyxz}ª¨»¢ª½¦r}s¨·ÆÐÜíôÛìòãó÷äôöãóôäôöãóôâòóâòóâòó666;;;GGG>>>DDDAAA>>>AAAMMJJLGPQMNOJBD?HIELMHDE@DE@EFAEEBDDASSSFFF88:::=;;;@@>??=IIGGGELLIGGEFFDOOMLLIFFDQQOXXVSSPNNLHIELMFSTJ\]V^_XWXTGHDFFDDDAGGEJJHQSNMNG[\U]^ZSSPOOMVVTXXVUVQPQJVWPLMHIIGSTO^_Xfh^fhabc\VWSQSNSSPXXVNOJTUPWWUPPPQQTGGIHGLA@ENNP[[[UUU___WWWSSS]]]ZZZbbb~~~jjjlllooo±²ÇÈĪ¬«xy¦ª´}xyrty{{~wz
¢¬£¨¶¢¨º¬rzlwr}ª²ÀÎãóþâñøãó÷äôøâòóãóôãóôâòñâòñ>>@::=FFHFFHJJMHHJBBE999MMJIJFGHDDE@BD?FGBLMHGHDBD?FGBFFDBB@TTTJJJ88:99;888777>>>BBBLLLEEEGGGGGGJJJFFFGGGQQQQQQUUUOOODDAMNGPQHVWPVWPWXTIJFLLILLINNLLLIMNIHIB^_Xfhc\\ZTTQWWU[[XZ[VUVOWXQOPLHHFTUPbc\ijahibab[XZUFGBJJHXXVOPLXZUUUSNNNSSUPPSQPUDBGJJMUUWPPS^^aJJMHHJPPSbbd^^acceXX[VVX[[]ddf~~
¯¯¯£¤¦motz~oq~qsps{{rvtx¦±¦iq
fos~¥¥·ÄÒâÜëóâñøâòöâòóãóôãóòãóòâóð???>>>IIIGGI??A;;>AADAAAEEBHIEEFA?@;?@;BD?LMHMNIDE@IJFIIGDDAQQQNNN:::;;;777666===AAAJJJNNNMMMNNNGGG>>>JJJPPPMMMVVVLLLFFDGHDMNGUVOVWP]^ZOPLQQOQQOJJHEEBHIEFGBUVQbc^VVTJJHOOMZ[VVWSXZUQSNXZULLI]][^_Xde\cd]\]Vab]NOJNNLSSP\]XXZUXXVJJHQQQPPSUTXLJOFEIIHMNMQZZ\PPSMMOOOQ[[][[]]]___bWWZTTViikooq
yy{fhkz~kotfjrilwoq~vxrtfizwx
~£
¡vz¤qypyª¥ºÅÔÞÛêñßðóßðñâòóãóòãóòãóò480794BEALNM>?A236687FHE@@>FFDFFD>>;GGEAA?FFDHHFDDALLIJJHJJHVVT]][TTQFFD442997;;9@@>DDALLIJJHBB@BEAEGFILJEFHFGINPO@BAGIFDDAIIGUVQ[\WOPLLMH997???GGEBB@FFDEEB]][[[XQQONNLLMHSTONOJWWUSSPMMMIIIUUSef_de\ab[ef_cd_TUPMMJNNLWWU\\Z[[XTUPMMJNNLUUUSSUDEJEFLFGMVW[MNQIJNIJMUVX[[[QQQUUUVVVOOO]]]eeeeeeefi^_bijlabdcdhopshilefjdekqqzssjjwrq¬oqcfzw}{s{t{~¢¬ÌÙßßìïâðïäôöáñòãööáóóAE:AE=EGBDFE9:=013687ILHEEBLLIGGE886663@@>GGEEEB??=MMJPPNQQOaa^bb_XXVTTQ??=@@>;;9DDAFFDLLIJJHAA?JMIEGFGHJFGIDEGIJMJMLFHEFFFGGGVVTXZUQSNTTQ???;;;FFD@@>FFDNNLiif__]SSPSSPMNIOPLOOMJJHQQQFFFDDFBBBVWPab[ab[TUP\]XVVTMMJMMJSSSWWWPPNXZUIJFNNLNNNOOQFGMDDMGHNTU[NOSEFIEFHVWZSSSMMMTTTXXXQQQVVV[[[WWW^_bUVX^_b]^a]^abcebce]^abcfdei{}ffpvv«ª½¡¥ijadvsx£¦º{txt{¤ÛèêäòñãóôäôöÛííä÷÷BF;=@8>@;>@?78:-/1243BEAMMJOOMFFD220220??=EEBGGE@@>IIGJJHLLIUUSbb_ccaaa^OOMEEB997BB@DDALLIJJHBB@DFB>@??@B?@B:;>@ADNPOILHLLLNNNZZW\]XUVQOOMPPP@@@LLIMMJIIGJJHbb___]TTQLLIUVQMNIOOMNNLNNN===::=???PQMXZS[\WGHD\\ZLLIFFFIIIQQQWWWLLIXZUJLGOOMOOOJJMGHL@AGEFLNOSOPTFGIFGIWZXMMMHHHNNNTTTVVVUUUSSSWWWTUWUVX\]_VWZbce]^a]^abcebcfdeibci^^hhhsllyzy¢qrikz©¬°Á¯qsrwr{vÅÒÔâðïáñôãó÷åö÷ßðñTWMNQI?A=@BA@AD347243?A>NNLIIG??=774>>;;;9==:JJHGGEHHFHHFQQOJJHQQOSSPXXV]][HHF774AA???=IIGMMJGGE:=9;>=@AD=>@;=?;=?EGFDFBGGGOOOOOMXZUWXTJJHJJJ???LLIHHFAA?GGEZZWTTQJJHJJHHIEHIEHHFGGE@@@;;;88:AAA\]XXZUXZUUUSLLI???IIIGGGJJJQQQQQO_a\QSNQQOSSSFFH@AE;=BBDGGHLPQTMNPMONX[ZJJJEEEIIINNNIIITTTTTTVVVOPSNOQTUWVWZXZ\_acXZ\[\^^_cefjfhmQSXeeoddpxx
¨z}_bomq{~txqw
wªÜéëäñøâñøãó÷áñò[^TOSJ8:68:9@AD124364>@=LLIJJHAA?::8HHF;;9??=QQOBB@??=QQOSSPNNLOOMOOMNNLZZWEEB::8EEBEEBFFDLLIPPN9;80219:=46801389;>@?@B?FFFQQQSSPNOJXZUSSP>>>BBBOOMLLIGGEFFDOOMHHFBB@BB@EFA?@;AA?DDADDD???::=EEEPPNPQM[[XAA?>>>:::FFHPPSFFFMMMNNLXZUSTOMMJSSSIIL?@D:;?GHLSTVIJMMONNPOUWTOOONNNFFFMMMHHHQQQOOOQQQLMONOQOPSMNPXZ\]^aVWZPQTVWZVW[^_c]^b[\b_afffpmmyz}acp[^feiqmp}{zoqlq{ipwÅÏÕáëóÞëòßìñéöúTWMLOGDFA;>=@AD679132@B?LLIQQOGGE774MMJEEBAA?NNLEEBAA?PPNLLIWWULLIFFDIIGVVTAA?442??=BB@IIGJJHTTQ>@=79889;/02124>?A?A@GIFGGGEEEHHFQSN[\W^^\LLLLLLLLIIIGJJHEEBIIGIIGAA?GGE@A=DE@HHF@@>BBBHHHEEGBBBJJHMMJZZWBBB@@@NNPGGIMMODDDAAA>>;NOJXZUMMJPPPIIIBDFBDGNOQZ[]LNMLNMJMIQTPVVVQQQEEELLLHHHNNNSSSVVVPQTOPSPQTFGITUW[\^UVXTUWQSUTUW\]_^_cOPTVW[cdhklrdhpSV^W\^efjss}vt
oo{eiqekpv~¶½ÄÜãì¸ÁÌâìòâïóMPFMPHNPL=?>=>@78:8:9LNJGGENNLHHF>>;PPNNNL>>;JJHBB@@@>MMJFFDUUSTTQNNLHHFWWU@@>331;;9DDAQQOIIGUUSFHE;>=89;34789;@AD:=;>@=HHH>>>HHF]^Zab]\\ZZZZLLLLLIMMJHHF@@>DDAEEB774IIG@A=;=8FFDBB@DDDJJJNNPGGGGGELLI[[[EEENNPQQT@?DBBE;;;>>>??=QSN^_[LLIJJJIIIGHJHILMNPUWVNPOHJGEGDMOLSSSVVVLLLOOOMMMJJJWWWWWWVWZMNPIJMIJMPQTPQTZ[]WX[LMONOQ[\^_acUVXUVX^_bbceX]_TX[dehdehdcjvt~wtjirbfibhjjpt£©°¿ÆÐÌÖÜÙãæIMBSVNPSN=?>=>@1249;:HJGMMJFFD??=@@>AA?UUS>>;TTQFFDGGEUUSMMJLLIOOMOOMLLI\\ZEEB663>>;FFD[[XFFDNNLBEA8:92364682369;:HJGILHDDDFFDIJFJLG[\WPQMJJH??=GGETTQJJH886>>;MMJ;;9HHFFGB?@;NNLIIGFFFSSSUUU???GGGMMM^^^JJMIILEDHDBG;:?88:>>>==:HIE^_[GGEFFFHHJBDFFGIGHJSUTOQPGIF@B?ILHGGEXXXWWWVVVSSSHHHXXXUUUQTSQSUGHJMNPMNPNOQXZ\\]_QSUPQTVXWX[Z[]\UWV^a_abd^cdPUVacbbdcbaehfmmlsbah^cdejkilrv{}»ÂÉÙãæGH?PQJWXTMMM@@B//1BBBBB@JMH:=8362798>@?TVSFHDTVQDE@MNIVWSOPLNOJJLGMNIHIEQQOOOM9:6FGBVWSab]GHDLMHJJJ>>@224224DDDIII??=DDALLIHHFMNINOJVWP^_XSTMHIEJJHMMJDDA442::8886886EEBNNL@@>EEBTTQAA?LLIXXVIIIOOOEEETTVPPSVUZFEIBAH:9>88:???@@>JJH]][AA????JJMABFFGJHIMFGIXZ\MONILJMOLIIGTTQ^^\MMJTTQPPNNNLTTQSUTQTSNPOLNMILJILJQTS\^][\^UVXUVXVWZ^_b[\^[\^]^a\]__ac\]_^_babd^_c^_c_ac^_bijlhioeiq_dp^co£@A8MNGOPLIIIDDF113:::;;9PSNAD?3644768:9NPO@B>OSJNOJLMHOPLLMHPQMFGBLMHAB>UUS[[XGHD?@;HIBZ[THIBJLGFFH327224BBELLLPPPAA???=??=??=HHFNOJPQM\]VUVONOHJLGPPNNNL;;9442663774GGEPPNBB@AA?QQOIIGEEBPPNSSPWWWIIIGGI??AFEI@?D=;B98=779??ADDDZZWaa^LLL@@BJJM9:>?@DDEHFGJOPSGHJGIHJMLJJHOPLZ[VUVQXZUVWSQSNVVTPSQX[ZWZXLNMHJIFHGJMLUWV\]_TUWQSUTUWZ[]WX[STVXZ\[\^XZ\[\^Z[]^_bQSUVWZ\]_bbbcce_afadlX\fX]hsy}GH?LMFTUPFFFQQT113111;;9MOJAD@/10/02468JML=?;JMHNOJIJFOPLMNIGHD?@;IJFEFAFFDUUSWXTPQMNOHWXQJLEQSNLLL99;,,/;;;UUUUUSNNL@@>@@>>>>EEBGGELMHVWSNOHGHABD?MMJPPNHHF886220997@@>SSPDDA==:NNLJJHFFDPPNTTQWWUJJJNNNHHJ@@B;:??>BIHM@@B??AMMMZZWZZWQQQ;;>GGI:;?;=@?@DBDGMNPHILGIHHJIMMJNNLUUSZZWVVTUUSPPNTTQQTSWZXVXWOQPHJIGIHGIHOQPXZ\QSUNOQVWZXZ\Z[]PQTWX[XZ\VWZXZ\WX[]^aPQTQSU]^a_acWX[TU[[^fSV^LOW_ej_ejLMDQSLNOJ@@@SSU>>@777;;9LNJFHE236347679LMO>@=MOLPPNIIGOOMEEBBB@AA?FFDDDAMMJVVTVWSFGBFG@VWPQSLVWSFFF447;;;777LLITTQHIEEFADDDAAAGGGIIGFFDTUPQSNMNIMMJUUSMMJPPN==:++)997??=TTQDDA>>;LLILLIIIGNNLPPN\\ZIIGUUULLLWWZMMOFEI87;668==?HHHQQO\\ZJJJMMOHHJ89=9:>@AEHIMIJMEFHADB?A@OOOQQQSSSVVVNNNQQQNNNPPPSUTLNMMONSUTNPOILJHJIMONWX[TUWJLNMNPTUWTUWIJMTUWTUWWX[TUWVWZUVXSTVJLNXZ\WX[OTVIMSPTZQU]OSXZ^aW\^VWNUVOMNIDDDOOQTTVHHH::8>@==?>*+-&(+67:@AD@BAEGFFFF>>>FFFFFFMMMPPPPPPMMJAA?QQOWXTHIEIJDNOHTUNPQMJJHGGGTTTFFDIIGVWSSTO>?:888668>>>AAA>>;HHFPPNSSPSSPMMJNNLQQOIIG774442??=VVTOOMEEBFFDUUSMMJIIGMMJXZUXXVWWULLLTTTLLN--0336113>>@HHHUUS\\ZOOOLLN??A67::;?=>AGHLDEGFGI=?>EGFLLLTTVLLNOOQLLNNNPGGIQQQSUTOQPQTSOQPWZXPSQOQPZ\[VWZUVXGHJLMOPQTXZ\FGIHILPQTQSUTUWWX[STVZ[]MNPPQTMQSPUWJNTBFLLOUVZ_TXZTUWWXOLMFHIE???DDFGGI>>>11/79878:)*-*+/237469468:=;DDD======AAADDD@@@@@@DDDEEBUUSVWS?@;@A:FG@VWP[\WQQO[[[SSPEEBNOJQSNOPI894AAA>>@>>@======JJHPPNJJHIIGMMJHHFNNLOOM@@>AA?BB@UUSVVTNNLHHFSSPIIGMMJJJHUVQSTOLLIQQONNNOOO;;>IIL88:;;>QQQOOM[[X\\\BBEDDF?@D?@D;=@>?BDEGDEG9;:;>=EEGPPSJJMGGIGGIJJMFFHLLNJMLMONQTSPSQSUTSUTUWVTVUOPSNOQEFHIJMIJMPQTBDFFGILMOPQTSTVTUWMNPVWZTUWOTUFMMPVXPTZEHNIMSTUXQTSQTSUVMPQJEFABBB??AEEGBBB886243236(),/0634:67:78:=?>FFH::=::=??AAAD::=::=AAATTQVVTWXTMNIJLEFG@NOHOPLTTQ^^\]][GHDMNIQSLEF?9:6IILGFJ??A::=999HHHMMJGGEGGEJJHGGENNLSSPGGE??=;;9OOMWWUTTQGGEIIGJJHNNLFFDQSNLMHMNILLINNLNNNFFF@@@GGIMMOUUUGGEXXVNNNAAD88:78;9:>?@D@AE:;>>?A?A@@BAEEGNNPLLNFFHEEGGGIEEGEEGFHGMONOQPSUTTVUQTSVXWOQPTUWNOQEFHEFHBDFMNPHILNOQHILJLNPQTQSUHILPQTWX[MQSAGIMSUQW\IMSMQTTUWTTQVVTJLEIJDHIE??=BBBQQQIII444-/1236+,0/03-/29:>;=??A@JJM447@@B@@B>>@::=::=>>@@@@UUS[\WGHD?@;BD?OPLWXTPPN\\Z\\ZLMHGHDLMHDE@==:LLNMMOAAD==?777AAAJJHLLIHHFBB@>>;@@>@@>BB@>>>999HHHPPPMMJFFDJJHFFDFFDLLIMNINOJJJHIIGMMJ[[[XXXUUULLNPPSQQQDDAUUSPPP99;44778;=>AIJNIJM9:=?@BDEGBDFBBEEEGFFHBBBBBBEEGFFHAADEGFNPONPOSUTPSQILJVXWVXWUVXOPSJLNJLNEFHJLNFGIFGIFGIHILLMOPQTHILMNPWX[GLM=BEJPSOUWJOQLPQPSQNPMTTQNOJOPLPQMGHDDE@GGEBBE87;:;A01778;013124468:;>>?AEEG779779AADIIL99;336::=HHHZZWUUSEEB>>;FFDLLI[[XPPNZZZ\\\PPNBB@MMJBB@BBBDFEILJ;>=FHG=?>8:9MONFHGLNM@B?9;8=?;?A>;>=78:348=>AGHJHJIILHLNIJMIHJGFHGHJINPOFHGFHGFHGLMO?@B:;>ABEIJMEGF?A>TVSOQP@AD89;/039:>FGIUWV=?>;=?:;>?@D=>AEFHSUTOQNEGD=?>@AD?@BLNMNPOPSQQTSQTSJMLNPOX[ZTUWPQTIJMNOQJLNGHJGHJIJMDFEGIHGIHMONFHGLNMVXWMNPINOHMNMQSLPQHMNINOMQPQTSPPNMMJLMHDE>;=8AA?>>@32911:/06;=@6796879;:9:=:;>>>@224779??A==?224//1668===IIGVVTNNL>>;EEBPPNTTQZZZXXX\\\IIIAAAGGGFFF@@@?A@BEDDFEBED:=;8:9JMLEGFILJ>@?362362:=;89;46923967=@AEDFEEGDGIEFHEEGFDFEJLNNOQDEGABEFGIQSUDEG9:=BDFABEDFE@B?OQNTVUIJMABE2379:>EFHVXWEGF;=?78;:;?>?BIJMTVSTVQJMHBEADEG?@DGHJHJILNMQTSMONHJILNMTVUWX[OPSIJMMNPPQTJLNEFHABEGIHHJINPOLNMJMLSUTTVUMONFJLEIJINOHMNEIJGLMINOLPQIIGQQOTUPFG@9:6??===?329,,6-/4?@D?@B243=?>;=?>?A?@D12667:78;-/2+,0126;=?>>>HHFUUSQQOAA?AA?JJHUUSUUUZZZWWWPPP@@@JJJEEEEEEADB@BAHJIADB9;:9;:HJIEGFMONDFE9;8796=?>9:=46912889??@D=?>;>:?A=BEAFHGILJGHJJLN?@B?@B?@BQSUNOQLMO>?AEFHILJ?A>NPMSUTHIL@AD:;?ABFGHJVXWSUT>?A78;89=469GHJQTPWZUOQMILHEFH>?BJLNHILFGIGHJEFHBDFFGILMONOQIJMGHJEFHJLNJLNHILEFHEGFFHGJMLEGFBEDMONQTSNPOHMNGLMLPQJOPBGHDHIGLMINOQQOUUSUVQGHA=>9BB@AAD98?//8+,2>?BEFH687ADB:;>:;>>?B126:;?:;?237014348:;>???MMJLLIDDA>>;FFDHHFQQOWWWUUUZZZPPPEEEIIINNNGGG@BA8:9=?>:=;7989;:FHGDFEHJIDFE=?;9;8DFE>?A469/0667=>?B>@?=?;FHDFHEFHGFHG>?AFGI?@BBDF;=?EFH;=?9:=78:?@B=?>=?>PSQLNM=>@67:67:ABFDEGJML\^]GHJ>?B89=:;?MNPPSOTVQOQMILHGHJABFHILGHJEFHEFH?@B?@BBDFFGIHILMNPNOQ?@BIJMJLNIJMEFHFHGNPOJMLFHGILJMONVXWLNMEIJDHIHMNGLM?DEAFGDHIFJLSSPWWUWXTPQJ=>9??=DDFA@GEEN12878;347798@BA@AD4687;>&*037=14:-17*-3*-3-/2:::NNLQQOIIG??=AA?GGELLINNNUUUWWWNNNAAAHHHQQQGGGEGF?A@9;:ADB8:99;:DFE@BAEGFBED@B?=?;GIH9:=126-/478>;=@ADB>@=BE@?A>:=;798>?A;=?67978:67989;78:3479:>:;?9:=>?AGHJPQTFGJ46989=?@DEFHEGF\^]LMO=>A12667:FGIQTPX[V^a\JMIHIL;=@?@D>?B?@D?@D;=@:;?@AEHIMGHJ?@BJLN9:=ABELMODEG=>@HJIOQPJMLFHGFHGEGFNPOHJIAFG@EFDHIAFG>BD;@ABGHGLMOOMUUSUVQOPI894886==?>=D88A/0689=6799;:ADB>?A12637=$(-,06(+1*-3(+1*-3014;;;LLINNLHHF@@>==:??=HHFJJJUUUTTTQQQ===GGGMMMIII@BA=?>9;:HJI?A@>@?DFEBEDADBBEDEGDGIFILJ;=?46912834:78;>@?>@=GIEEGDBEDADB>?A9:=12434767989;89;67:78>;=B89=89;DEGNOSDEJ12878;=>AABEDFE[]\PQTBDG9:>FGJMNPSUQWZU]_[PSOLMO?@D;=@:;??@D>?B78;9:>ABFIJNMNPGHJPQT@ADGHJIJMGHJGHJPSQOQPNPOEGFGIHEGFMONMONFJLDHIFJLDHI;@A;@ABGHEIJSSPUUSPQMGHA340997;;>218++4,-378;679364>@?>?A469-17&*2/2:,08%)1%)1*-6239PPPQQOBB@442==:??=;;9==:IIIOOOUUUSSS;;;AAAIIIDDD@BA=?>>@?JMLEGF?A@?A@?A@9;:?A@GIFLNJILJ;=?469128/060149;::=9FHDBEA=?>8:99:=67901334746878:78:46934:89?46967:HIMIJN?@F67=34889=?@BDFESUTPQTDEH>?BGHLIJMOQNSUPZ\WUWTOPS?@D9:@9:@>?E:;A78>89?=>D@AEABEABENOQEFHEFHFGIJLNLMOGIHGIHMONJMLGIHADBFHGHJIBGH?DE@EF=AB9>?;@ABGHBGHNNLQSNOPIFG@:;7::8779,+2%&,,-3469124687>?A;=?014),4#&/&*2"%-"%-#&,*-3348DFELLIFFD??=886DDALLIGGEBBBNNNPPNTTQ;;9IIG@@@>>>9;:@BAGIHPSQOQPEGFDFE?A@=?>BEDLNJQTPGIH9:=126-/467=237:=;=?;@B?=?;9;:78:89=67:01434812634834812622;33=12878;IJNNOSDEJ78>12889==>@ABESTVVWZJLNFGJNOSHILILHJMHQTOTVSMON;=?9:>67=:;A9:@12878>>?EABH>?B?@BHILABE89;?@BJLNIJMFHGJMLLNMQTSNPOADBFHGIJMDHI?DE?DE;@A7;=;@ABGH@EFPQMMNGOPISTMMNIBBB=;@43:)*0()/78;3474689:=78;/06**6%%1$$-%%/()/126236013>@?BED@BA9;:;>=ADBFHGLNMPPPHHFQSNQSNHIELMHHHFBBB78:@ADFHEMOLLNJJMIIJM@AD>?ADFEOQNNPMADB78:34:,,612812689;9;::=;89;78;78>14:14=03;/2=-1;69A26>03;009009/0678;GHJJLO@AG34:1289:@?@D=>AFGJVWZEFHEFH@@BLLNFFFIIGUUSUUSNNLGGGEFH89=34:67=11:88A66?88A?@DEFHHILBDF=>@=>@GHJEFHEFHBDFIJMNOQGHJGHJEFHHIL:;?=>A>?B:;?9:>9:>=>A:;?PQJIJDZ[TMNIDDA===76:218*+1,-3:;?236-/1348128((1))4%%2%%1&&0&(--/2468687?A@:=;798798?A@?A@BEDADB???GGGJLGOPI892>?:???;;>89=ABEFHENPLQTOGIFFGIFGJBDFABEGIHNPMJML=>@239,,634:67=9:>236?@B?@D;=B46;37?,0:+-:02?13@79F14?,08--922;017237:;>QSVFGM67=34:78>EFL=>DBDGNOSGHJ>?A??ALLNHHHFFFSSPWWUPQMEEBNOQ?@D34:239//866?11=>>G?@DDEGGHJ@AD:;>=>@DEGDEG>?A=>@HILNOQMNPFGIABEGHJDEH@AE;=@78;=>A=>A>?B=>AQSLGHAWXQOPLBB@III649107+,2128>?B013+,/126/06%%/&&2$$1%%1))2%&,*+/9:=>@?>@?9;:364243:=;BED>@?>@?GGIGGGNNLLMHAB>IIG;;;==?9:>>?A>@=DFASUP@B?;=?@AE@AD9:=:=;GIFNPO?@B017//834:89?=>A89;>?A89=34:34:26>+/9*,9/1>13@79F14?,0822>//8,-3348?@BOPT@AG23923967=DEJ;=BABFMNQHIL;=?JJMIILFFFHHHVVTTTQMNIHHFX[ZWX\89=67=34:66?11:88A=>A@AEABF:;?78;;=@?@DABF?@B>?AHILNOQMNPFGIABEGHJ?@D9:>67:469BDGEFIBDGDEHLMFQSLTUNNOJMMJ@@@327/-4()/128=>A)*,*+-/03,-3$$-%%1$$1&&2**3#$*&(+;=?BEDEGF679/02679679:;>ABE@ADDDFDDFNNLPPNOOMMMJJJMAAD>?BDEG>@=>@;NPL:=9124014@AD>?A:=;BEALNM=>@-/400967=23934812478:78;67=34:/2:-1;,/;+-:-0=68E26@03;11=11:,-3014FGISTWIJP67=-/467==>D9:@ABFQSVIJM=>@>>@@@BEEEFFFTTQVVTOPLFFDZ\[abdABF237/0612899B67=BDIEFIEFI=>A469:;?;=@@AE?@B=>@DEGHILGHJGHJEFHHILGHL=>A469126>?BBDG@AE?@DSTMIJDQSLVWSEEB@@@98=/-4()/128;=@+,/*+-)*-#$*$$-%%1##0$$0&&0&(-)*-BDFILJ236/03,-1348;=@67:78;34898===?GGGLLLAAA???336-,1+,0236AD@HJFTVQGIF124/03=>@>?AADBEGDBED89;,-3++412846;78;01378:89=89?78>,08(+6-0=02?+-:+-:+/9+/7--9,,6,-3469LMOLMPNOU:;A/0646;89?9:@@AEIJN@AD9:=AAD==?:::AAATTQ[[XLMHLLIZ\[TUWMNP=>A126/06*+19:@;=B;=B>?E46;67==>D?@F>?B;=?;=?BDFEFHIJMIJMHILFGIDEGEFH679124?@BHILHILDEG?@9@A:PQJUVQTTQFFF438(&-()/78>BDG/02)*,)*-#$*%%/##/""/$$0**3()/014GHJTUW89=/03+,0-/2/03014:;?237,+0;:?BBEHHHEEE@@B76:0/34699:=:=9?A=OQMLNJ:;>78;89;;=?>@?=?;>@?78:-/4,,646;46;469,-089;67:128-/4+/7),7,/;,/;*,9*,9*-8*-6--9,,6&(-9:>JLNJLOQSXLMS0172399:@46;BDGDEH>?A;=?HHJ99;888>>>MMJOOMIJFMNIPSOTVUUVXNOQ:;?014/0646;89?67=78>34:01789?;=B:;A9:>468=>@EFHGHJGHJEFHBDFDEGABE9:=89;=>@DEGEFH>?A:;4>?8PQJWXTMMJBBB327%$+*+1?@FJLO347,-0,-1)*0++4((3$$1**666?$%+126BDFSTV:;?-/4,-3+,2239-/4017)*00/698=HHJHHHEEE??A98=/-4:;?;=?8:79;7NPLJMI9:=67:89;@AD@BA9;88:9679/06--746;128126,-078:4699:@ABH+/7),7,/;(*7)+8)+8),7),4))4009+,278;BDFFGJFGM:;A9:@01723934:>?B@AE;=?:;>>>@::=>>>===IIGOOMSTOQSNLNJQTSNPOIJM469-/2126;=B:;A66?33=22;11:77@;;E;=B@AE9:=;=?@AD?@BDEGGHJIJMHJI=?>687798=?>ADBFHGADB>?8:;4IJDTUPIIGHHH:9>&%,+,2DEJQSV78:124237/0622;%%1""/**699B()/78;?@BQSU9:>+,2/06,-3,-39:@89?67=43::9>AADHHHBBB::=76:+*189=78:;>::=8QTOEGD-/1+,0236>?A>@?241364468017--7017,-3014/0223678;78>34:*-6*-8+-:$&3(*7(*7(+6(+3++7))2,-39:>GHJIJNOPVQSX@AG017*+146;;=@?@D89;89;??A==?777;;;FFDOOMTUPPQMLNJSUQLNMGHJ/03-/2+,0;=B??H66?22;33=33=22;33=67=78;4689:=9:=@ADEFHHILIJMDFE4763648:9@BA@BAFHGHJI
\ No newline at end of file
diff --git a/examples/unicode.h b/examples/unicode.h
new file mode 100644
index 0000000..0831e23
--- /dev/null
+++ b/examples/unicode.h
@@ -0,0 +1,116 @@
+// 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_
+
+#include <stdio.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 <fcntl.h>
+#include <io.h>
+#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 = \
+ (const W_CHAR**)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 WFPRINTF(STREAM, STR, ...) \
+ do { \
+ int prev_mode; \
+ fflush(STREAM); \
+ prev_mode = _setmode(_fileno(STREAM), _O_U8TEXT); \
+ fwprintf(STREAM, TO_W_CHAR(STR), __VA_ARGS__); \
+ fflush(STREAM); \
+ (void)_setmode(_fileno(STREAM), prev_mode); \
+ } while (0)
+#define WPRINTF(STR, ...) WFPRINTF(stdout, 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
+
+#include <string.h>
+
+// 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(STREAM, STR, ...) fprintf(STREAM, 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_
diff --git a/examples/unicode_gif.h b/examples/unicode_gif.h
new file mode 100644
index 0000000..626c6e7
--- /dev/null
+++ b/examples/unicode_gif.h
@@ -0,0 +1,76 @@
+// 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_
diff --git a/examples/vwebp.c b/examples/vwebp.c
new file mode 100644
index 0000000..35f1b18
--- /dev/null
+++ b/examples/vwebp.c
@@ -0,0 +1,654 @@
+// 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 void PrintStringW(const char* const text) {
+#if defined(_WIN32) && defined(_UNICODE)
+ void* const font = GLUT_BITMAP_9_BY_15;
+ const W_CHAR* const wtext = (const W_CHAR*)text;
+ int i;
+ for (i = 0; wtext[i]; ++i) {
+ glutBitmapCharacter(font, wtext[i]);
+ }
+#else
+ PrintString(text);
+#endif
+}
+
+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);
+ PrintStringW(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) {
+ int width = kParams.canvas_width;
+ int height = kParams.canvas_height;
+ int screen_width, screen_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
+ screen_width = glutGet(GLUT_SCREEN_WIDTH);
+ screen_height = glutGet(GLUT_SCREEN_HEIGHT);
+ if (width > screen_width || height > screen_height) {
+ if (width > screen_width) {
+ height = (height * screen_width + width - 1) / width;
+ width = screen_width;
+ }
+ if (height > screen_height) {
+ width = (width * screen_height + height - 1) / height;
+ height = screen_height;
+ }
+ }
+ 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
+
+//------------------------------------------------------------------------------
diff --git a/examples/webpinfo.c b/examples/webpinfo.c
new file mode 100644
index 0000000..356abae
--- /dev/null
+++ b/examples/webpinfo.c
@@ -0,0 +1,1186 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Command-line tool to print out the chunk level structure of WebP files
+// along with basic integrity checks.
+//
+// Author: Hui Su (huisu@google.com)
+
+#include <assert.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "../imageio/imageio_util.h"
+#include "./unicode.h"
+#include "webp/decode.h"
+#include "webp/format_constants.h"
+#include "webp/mux_types.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#define LOG_ERROR(MESSAGE) \
+ do { \
+ if (webp_info->show_diagnosis_) { \
+ fprintf(stderr, "Error: %s\n", MESSAGE); \
+ } \
+ } while (0)
+
+#define LOG_WARN(MESSAGE) \
+ do { \
+ if (webp_info->show_diagnosis_) { \
+ fprintf(stderr, "Warning: %s\n", MESSAGE); \
+ } \
+ ++webp_info->num_warnings_; \
+ } while (0)
+
+static const char* const kFormats[3] = {
+ "Unknown",
+ "Lossy",
+ "Lossless"
+};
+
+static const char* const kLosslessTransforms[4] = {
+ "Predictor",
+ "Cross Color",
+ "Subtract Green",
+ "Color Indexing"
+};
+
+static const char* const kAlphaFilterMethods[4] = {
+ "None",
+ "Horizontal",
+ "Vertical",
+ "Gradient"
+};
+
+typedef enum {
+ WEBP_INFO_OK = 0,
+ WEBP_INFO_TRUNCATED_DATA,
+ WEBP_INFO_PARSE_ERROR,
+ WEBP_INFO_INVALID_PARAM,
+ WEBP_INFO_BITSTREAM_ERROR,
+ WEBP_INFO_MISSING_DATA,
+ WEBP_INFO_INVALID_COMMAND
+} WebPInfoStatus;
+
+typedef enum ChunkID {
+ CHUNK_VP8,
+ CHUNK_VP8L,
+ CHUNK_VP8X,
+ CHUNK_ALPHA,
+ CHUNK_ANIM,
+ CHUNK_ANMF,
+ CHUNK_ICCP,
+ CHUNK_EXIF,
+ CHUNK_XMP,
+ CHUNK_UNKNOWN,
+ CHUNK_TYPES = CHUNK_UNKNOWN
+} ChunkID;
+
+typedef struct {
+ size_t start_;
+ size_t end_;
+ const uint8_t* buf_;
+} MemBuffer;
+
+typedef struct {
+ size_t offset_;
+ size_t size_;
+ const uint8_t* payload_;
+ ChunkID id_;
+} ChunkData;
+
+typedef struct WebPInfo {
+ int canvas_width_;
+ int canvas_height_;
+ int loop_count_;
+ int num_frames_;
+ int chunk_counts_[CHUNK_TYPES];
+ int anmf_subchunk_counts_[3]; // 0 VP8; 1 VP8L; 2 ALPH.
+ uint32_t bgcolor_;
+ int feature_flags_;
+ int has_alpha_;
+ // Used for parsing ANMF chunks.
+ int frame_width_, frame_height_;
+ size_t anim_frame_data_size_;
+ int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_;
+ // Print output control.
+ int quiet_, show_diagnosis_, show_summary_;
+ int num_warnings_;
+ int parse_bitstream_;
+} WebPInfo;
+
+static void WebPInfoInit(WebPInfo* const webp_info) {
+ memset(webp_info, 0, sizeof(*webp_info));
+}
+
+static const uint32_t kWebPChunkTags[CHUNK_TYPES] = {
+ MKFOURCC('V', 'P', '8', ' '),
+ MKFOURCC('V', 'P', '8', 'L'),
+ MKFOURCC('V', 'P', '8', 'X'),
+ MKFOURCC('A', 'L', 'P', 'H'),
+ MKFOURCC('A', 'N', 'I', 'M'),
+ MKFOURCC('A', 'N', 'M', 'F'),
+ MKFOURCC('I', 'C', 'C', 'P'),
+ MKFOURCC('E', 'X', 'I', 'F'),
+ MKFOURCC('X', 'M', 'P', ' '),
+};
+
+// -----------------------------------------------------------------------------
+// Data reading.
+
+static int GetLE16(const uint8_t* const data) {
+ return (data[0] << 0) | (data[1] << 8);
+}
+
+static int GetLE24(const uint8_t* const data) {
+ return GetLE16(data) | (data[2] << 16);
+}
+
+static uint32_t GetLE32(const uint8_t* const data) {
+ return GetLE16(data) | ((uint32_t)GetLE16(data + 2) << 16);
+}
+
+static int ReadLE16(const uint8_t** data) {
+ const int val = GetLE16(*data);
+ *data += 2;
+ return val;
+}
+
+static int ReadLE24(const uint8_t** data) {
+ const int val = GetLE24(*data);
+ *data += 3;
+ return val;
+}
+
+static uint32_t ReadLE32(const uint8_t** data) {
+ const uint32_t val = GetLE32(*data);
+ *data += 4;
+ return val;
+}
+
+static int ReadFileToWebPData(const char* const filename,
+ WebPData* const webp_data) {
+ const uint8_t* data;
+ size_t size;
+ if (!ImgIoUtilReadFile(filename, &data, &size)) return 0;
+ webp_data->bytes = data;
+ webp_data->size = size;
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// MemBuffer object.
+
+static void InitMemBuffer(MemBuffer* const mem, const WebPData* webp_data) {
+ mem->buf_ = webp_data->bytes;
+ mem->start_ = 0;
+ mem->end_ = webp_data->size;
+}
+
+static size_t MemDataSize(const MemBuffer* const mem) {
+ return (mem->end_ - mem->start_);
+}
+
+static const uint8_t* GetBuffer(MemBuffer* const mem) {
+ return mem->buf_ + mem->start_;
+}
+
+static void Skip(MemBuffer* const mem, size_t size) {
+ mem->start_ += size;
+}
+
+static uint32_t ReadMemBufLE32(MemBuffer* const mem) {
+ const uint8_t* const data = mem->buf_ + mem->start_;
+ const uint32_t val = GetLE32(data);
+ assert(MemDataSize(mem) >= 4);
+ Skip(mem, 4);
+ return val;
+}
+
+// -----------------------------------------------------------------------------
+// Lossy bitstream analysis.
+
+static int GetBits(const uint8_t* const data, size_t data_size, size_t nb,
+ int* val, uint64_t* const bit_pos) {
+ *val = 0;
+ while (nb-- > 0) {
+ const uint64_t p = (*bit_pos)++;
+ if ((p >> 3) >= data_size) {
+ return 0;
+ } else {
+ const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
+ *val = (*val << 1) | bit;
+ }
+ }
+ return 1;
+}
+
+static int GetSignedBits(const uint8_t* const data, size_t data_size, size_t nb,
+ int* val, uint64_t* const bit_pos) {
+ int sign;
+ if (!GetBits(data, data_size, nb, val, bit_pos)) return 0;
+ if (!GetBits(data, data_size, 1, &sign, bit_pos)) return 0;
+ if (sign) *val = -(*val);
+ return 1;
+}
+
+#define GET_BITS(v, n) \
+ do { \
+ if (!GetBits(data, data_size, n, &(v), bit_pos)) { \
+ LOG_ERROR("Truncated lossy bitstream."); \
+ return WEBP_INFO_TRUNCATED_DATA; \
+ } \
+ } while (0)
+
+#define GET_SIGNED_BITS(v, n) \
+ do { \
+ if (!GetSignedBits(data, data_size, n, &(v), bit_pos)) { \
+ LOG_ERROR("Truncated lossy bitstream."); \
+ return WEBP_INFO_TRUNCATED_DATA; \
+ } \
+ } while (0)
+
+static WebPInfoStatus ParseLossySegmentHeader(const WebPInfo* const webp_info,
+ const uint8_t* const data,
+ size_t data_size,
+ uint64_t* const bit_pos) {
+ int use_segment;
+ GET_BITS(use_segment, 1);
+ printf(" Use segment: %d\n", use_segment);
+ if (use_segment) {
+ int update_map, update_data;
+ GET_BITS(update_map, 1);
+ GET_BITS(update_data, 1);
+ printf(" Update map: %d\n"
+ " Update data: %d\n",
+ update_map, update_data);
+ if (update_data) {
+ int i, a_delta;
+ int quantizer[4] = {0, 0, 0, 0};
+ int filter_strength[4] = {0, 0, 0, 0};
+ GET_BITS(a_delta, 1);
+ printf(" Absolute delta: %d\n", a_delta);
+ for (i = 0; i < 4; ++i) {
+ int bit;
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(quantizer[i], 7);
+ }
+ for (i = 0; i < 4; ++i) {
+ int bit;
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(filter_strength[i], 6);
+ }
+ printf(" Quantizer: %d %d %d %d\n", quantizer[0], quantizer[1],
+ quantizer[2], quantizer[3]);
+ printf(" Filter strength: %d %d %d %d\n", filter_strength[0],
+ filter_strength[1], filter_strength[2], filter_strength[3]);
+ }
+ if (update_map) {
+ int i;
+ int prob_segment[3] = {255, 255, 255};
+ for (i = 0; i < 3; ++i) {
+ int bit;
+ GET_BITS(bit, 1);
+ if (bit) GET_BITS(prob_segment[i], 8);
+ }
+ printf(" Prob segment: %d %d %d\n",
+ prob_segment[0], prob_segment[1], prob_segment[2]);
+ }
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ParseLossyFilterHeader(const WebPInfo* const webp_info,
+ const uint8_t* const data,
+ size_t data_size,
+ uint64_t* const bit_pos) {
+ int simple_filter, level, sharpness, use_lf_delta;
+ GET_BITS(simple_filter, 1);
+ GET_BITS(level, 6);
+ GET_BITS(sharpness, 3);
+ GET_BITS(use_lf_delta, 1);
+ printf(" Simple filter: %d\n", simple_filter);
+ printf(" Level: %d\n", level);
+ printf(" Sharpness: %d\n", sharpness);
+ printf(" Use lf delta: %d\n", use_lf_delta);
+ if (use_lf_delta) {
+ int update;
+ GET_BITS(update, 1);
+ printf(" Update lf delta: %d\n", update);
+ if (update) {
+ int i;
+ for (i = 0; i < 4 + 4; ++i) {
+ int temp;
+ GET_BITS(temp, 1);
+ if (temp) GET_BITS(temp, 7);
+ }
+ }
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
+ const WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
+ const uint32_t bits = (uint32_t)data[0] | (data[1] << 8) | (data[2] << 16);
+ const int key_frame = !(bits & 1);
+ const int profile = (bits >> 1) & 7;
+ const int display = (bits >> 4) & 1;
+ const uint32_t partition0_length = (bits >> 5);
+ WebPInfoStatus status = WEBP_INFO_OK;
+ uint64_t bit_position = 0;
+ uint64_t* const bit_pos = &bit_position;
+ int colorspace, clamp_type;
+ printf(" Parsing lossy bitstream...\n");
+ // Calling WebPGetFeatures() in ProcessImageChunk() should ensure this.
+ assert(chunk_data->size_ >= CHUNK_HEADER_SIZE + 10);
+ if (profile > 3) {
+ LOG_ERROR("Unknown profile.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ if (!display) {
+ LOG_ERROR("Frame is not displayable.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ data += 3;
+ data_size -= 3;
+ printf(" Key frame: %s\n"
+ " Profile: %d\n"
+ " Display: %s\n"
+ " Part. 0 length: %d\n",
+ key_frame ? "Yes" : "No", profile,
+ display ? "Yes" : "No", partition0_length);
+ if (key_frame) {
+ if (!(data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a)) {
+ LOG_ERROR("Invalid lossy bitstream signature.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ printf(" Width: %d\n"
+ " X scale: %d\n"
+ " Height: %d\n"
+ " Y scale: %d\n",
+ ((data[4] << 8) | data[3]) & 0x3fff, data[4] >> 6,
+ ((data[6] << 8) | data[5]) & 0x3fff, data[6] >> 6);
+ data += 7;
+ data_size -= 7;
+ } else {
+ LOG_ERROR("Non-keyframe detected in lossy bitstream.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ if (partition0_length >= data_size) {
+ LOG_ERROR("Bad partition length.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ GET_BITS(colorspace, 1);
+ GET_BITS(clamp_type, 1);
+ printf(" Color space: %d\n", colorspace);
+ printf(" Clamp type: %d\n", clamp_type);
+ status = ParseLossySegmentHeader(webp_info, data, data_size, bit_pos);
+ if (status != WEBP_INFO_OK) return status;
+ status = ParseLossyFilterHeader(webp_info, data, data_size, bit_pos);
+ if (status != WEBP_INFO_OK) return status;
+ { // Partition number and size.
+ const uint8_t* part_size = data + partition0_length;
+ int num_parts, i;
+ size_t part_data_size;
+ GET_BITS(num_parts, 2);
+ num_parts = 1 << num_parts;
+ if ((int)(data_size - partition0_length) < (num_parts - 1) * 3) {
+ LOG_ERROR("Truncated lossy bitstream.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ part_data_size = data_size - partition0_length - (num_parts - 1) * 3;
+ printf(" Total partitions: %d\n", num_parts);
+ for (i = 1; i < num_parts; ++i) {
+ const size_t psize =
+ part_size[0] | (part_size[1] << 8) | (part_size[2] << 16);
+ if (psize > part_data_size) {
+ LOG_ERROR("Truncated partition.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ printf(" Part. %d length: %d\n", i, (int)psize);
+ part_data_size -= psize;
+ part_size += 3;
+ }
+ }
+ // Quantizer.
+ {
+ int base_q, bit;
+ int dq_y1_dc = 0, dq_y2_dc = 0, dq_y2_ac = 0, dq_uv_dc = 0, dq_uv_ac = 0;
+ GET_BITS(base_q, 7);
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(dq_y1_dc, 4);
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(dq_y2_dc, 4);
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(dq_y2_ac, 4);
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(dq_uv_dc, 4);
+ GET_BITS(bit, 1);
+ if (bit) GET_SIGNED_BITS(dq_uv_ac, 4);
+ printf(" Base Q: %d\n", base_q);
+ printf(" DQ Y1 DC: %d\n", dq_y1_dc);
+ printf(" DQ Y2 DC: %d\n", dq_y2_dc);
+ printf(" DQ Y2 AC: %d\n", dq_y2_ac);
+ printf(" DQ UV DC: %d\n", dq_uv_dc);
+ printf(" DQ UV AC: %d\n", dq_uv_ac);
+ }
+ if ((*bit_pos >> 3) >= partition0_length) {
+ LOG_ERROR("Truncated lossy bitstream.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ return WEBP_INFO_OK;
+}
+
+// -----------------------------------------------------------------------------
+// Lossless bitstream analysis.
+
+static int LLGetBits(const uint8_t* const data, size_t data_size, size_t nb,
+ int* val, uint64_t* const bit_pos) {
+ uint32_t i = 0;
+ *val = 0;
+ while (i < nb) {
+ const uint64_t p = (*bit_pos)++;
+ if ((p >> 3) >= data_size) {
+ return 0;
+ } else {
+ const int bit = !!(data[p >> 3] & (1 << ((p & 7))));
+ *val = *val | (bit << i);
+ ++i;
+ }
+ }
+ return 1;
+}
+
+#define LL_GET_BITS(v, n) \
+ do { \
+ if (!LLGetBits(data, data_size, n, &(v), bit_pos)) { \
+ LOG_ERROR("Truncated lossless bitstream."); \
+ return WEBP_INFO_TRUNCATED_DATA; \
+ } \
+ } while (0)
+
+static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info,
+ const uint8_t* const data,
+ size_t data_size,
+ uint64_t* const bit_pos) {
+ int use_transform, block_size, n_colors;
+ LL_GET_BITS(use_transform, 1);
+ printf(" Use transform: %s\n", use_transform ? "Yes" : "No");
+ if (use_transform) {
+ int type;
+ LL_GET_BITS(type, 2);
+ printf(" 1st transform: %s (%d)\n", kLosslessTransforms[type], type);
+ switch (type) {
+ case PREDICTOR_TRANSFORM:
+ case CROSS_COLOR_TRANSFORM:
+ LL_GET_BITS(block_size, 3);
+ block_size = 1 << (block_size + 2);
+ printf(" Tran. block size: %d\n", block_size);
+ break;
+ case COLOR_INDEXING_TRANSFORM:
+ LL_GET_BITS(n_colors, 8);
+ n_colors += 1;
+ printf(" No. of colors: %d\n", n_colors);
+ break;
+ default: break;
+ }
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
+ uint64_t bit_position = 0;
+ uint64_t* const bit_pos = &bit_position;
+ WebPInfoStatus status;
+ printf(" Parsing lossless bitstream...\n");
+ if (data_size < VP8L_FRAME_HEADER_SIZE) {
+ LOG_ERROR("Truncated lossless bitstream.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ if (data[0] != VP8L_MAGIC_BYTE) {
+ LOG_ERROR("Invalid lossless bitstream signature.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ data += 1;
+ data_size -= 1;
+ {
+ int width, height, has_alpha, version;
+ LL_GET_BITS(width, 14);
+ LL_GET_BITS(height, 14);
+ LL_GET_BITS(has_alpha, 1);
+ LL_GET_BITS(version, 3);
+ width += 1;
+ height += 1;
+ printf(" Width: %d\n", width);
+ printf(" Height: %d\n", height);
+ printf(" Alpha: %d\n", has_alpha);
+ printf(" Version: %d\n", version);
+ }
+ status = ParseLosslessTransform(webp_info, data, data_size, bit_pos);
+ if (status != WEBP_INFO_OK) return status;
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
+ if (data_size <= ALPHA_HEADER_LEN) {
+ LOG_ERROR("Truncated ALPH chunk.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ printf(" Parsing ALPH chunk...\n");
+ {
+ const int compression_method = (data[0] >> 0) & 0x03;
+ const int filter = (data[0] >> 2) & 0x03;
+ const int pre_processing = (data[0] >> 4) & 0x03;
+ const int reserved_bits = (data[0] >> 6) & 0x03;
+ printf(" Compression: %d\n", compression_method);
+ printf(" Filter: %s (%d)\n",
+ kAlphaFilterMethods[filter], filter);
+ printf(" Pre-processing: %d\n", pre_processing);
+ if (compression_method > ALPHA_LOSSLESS_COMPRESSION) {
+ LOG_ERROR("Invalid Alpha compression method.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ if (pre_processing > ALPHA_PREPROCESSED_LEVELS) {
+ LOG_ERROR("Invalid Alpha pre-processing method.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ if (reserved_bits != 0) {
+ LOG_WARN("Reserved bits in ALPH chunk header are not all 0.");
+ }
+ data += ALPHA_HEADER_LEN;
+ data_size -= ALPHA_HEADER_LEN;
+ if (compression_method == ALPHA_LOSSLESS_COMPRESSION) {
+ uint64_t bit_pos = 0;
+ WebPInfoStatus status =
+ ParseLosslessTransform(webp_info, data, data_size, &bit_pos);
+ if (status != WEBP_INFO_OK) return status;
+ }
+ }
+ return WEBP_INFO_OK;
+}
+
+// -----------------------------------------------------------------------------
+// Chunk parsing.
+
+static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info,
+ MemBuffer* const mem) {
+ const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
+ size_t riff_size;
+
+ if (MemDataSize(mem) < min_size) {
+ LOG_ERROR("Truncated data detected when parsing RIFF header.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
+ memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
+ LOG_ERROR("Corrupted RIFF header.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE);
+ if (riff_size < CHUNK_HEADER_SIZE) {
+ LOG_ERROR("RIFF size is too small.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (riff_size > MAX_CHUNK_PAYLOAD) {
+ LOG_ERROR("RIFF size is over limit.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ riff_size += CHUNK_HEADER_SIZE;
+ if (!webp_info->quiet_) {
+ printf("RIFF HEADER:\n");
+ printf(" File size: %6d\n", (int)riff_size);
+ }
+ if (riff_size < mem->end_) {
+ LOG_WARN("RIFF size is smaller than the file size.");
+ mem->end_ = riff_size;
+ } else if (riff_size > mem->end_) {
+ LOG_ERROR("Truncated data detected when parsing RIFF payload.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ Skip(mem, RIFF_HEADER_SIZE);
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
+ MemBuffer* const mem,
+ ChunkData* const chunk_data) {
+ memset(chunk_data, 0, sizeof(*chunk_data));
+ if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
+ LOG_ERROR("Truncated data detected when parsing chunk header.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ } else {
+ const size_t chunk_start_offset = mem->start_;
+ const uint32_t fourcc = ReadMemBufLE32(mem);
+ const uint32_t payload_size = ReadMemBufLE32(mem);
+ const uint32_t payload_size_padded = payload_size + (payload_size & 1);
+ const size_t chunk_size = CHUNK_HEADER_SIZE + payload_size_padded;
+ int i;
+ if (payload_size > MAX_CHUNK_PAYLOAD) {
+ LOG_ERROR("Size of chunk payload is over limit.");
+ return WEBP_INFO_INVALID_PARAM;
+ }
+ if (payload_size_padded > MemDataSize(mem)){
+ LOG_ERROR("Truncated data detected when parsing chunk payload.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ for (i = 0; i < CHUNK_TYPES; ++i) {
+ if (kWebPChunkTags[i] == fourcc) break;
+ }
+ chunk_data->offset_ = chunk_start_offset;
+ chunk_data->size_ = chunk_size;
+ chunk_data->id_ = (ChunkID)i;
+ chunk_data->payload_ = GetBuffer(mem);
+ if (chunk_data->id_ == CHUNK_ANMF) {
+ if (payload_size != payload_size_padded) {
+ LOG_ERROR("ANMF chunk size should always be even.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ // There are sub-chunks to be parsed in an ANMF chunk.
+ Skip(mem, ANMF_CHUNK_SIZE);
+ } else {
+ Skip(mem, payload_size_padded);
+ }
+ return WEBP_INFO_OK;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Chunk analysis.
+
+static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ if (webp_info->chunk_counts_[CHUNK_VP8] ||
+ webp_info->chunk_counts_[CHUNK_VP8L] ||
+ webp_info->chunk_counts_[CHUNK_VP8X]) {
+ LOG_ERROR("Already seen a VP8/VP8L/VP8X chunk when parsing VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (chunk_data->size_ != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
+ LOG_ERROR("Corrupted VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ ++webp_info->chunk_counts_[CHUNK_VP8X];
+ webp_info->feature_flags_ = *data;
+ data += 4;
+ webp_info->canvas_width_ = 1 + ReadLE24(&data);
+ webp_info->canvas_height_ = 1 + ReadLE24(&data);
+ if (!webp_info->quiet_) {
+ printf(" ICCP: %d\n Alpha: %d\n EXIF: %d\n XMP: %d\n Animation: %d\n",
+ (webp_info->feature_flags_ & ICCP_FLAG) != 0,
+ (webp_info->feature_flags_ & ALPHA_FLAG) != 0,
+ (webp_info->feature_flags_ & EXIF_FLAG) != 0,
+ (webp_info->feature_flags_ & XMP_FLAG) != 0,
+ (webp_info->feature_flags_ & ANIMATION_FLAG) != 0);
+ printf(" Canvas size %d x %d\n",
+ webp_info->canvas_width_, webp_info->canvas_height_);
+ }
+ if (webp_info->canvas_width_ > MAX_CANVAS_SIZE) {
+ LOG_WARN("Canvas width is out of range in VP8X chunk.");
+ }
+ if (webp_info->canvas_height_ > MAX_CANVAS_SIZE) {
+ LOG_WARN("Canvas height is out of range in VP8X chunk.");
+ }
+ if ((uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
+ MAX_IMAGE_AREA) {
+ LOG_WARN("Canvas area is out of range in VP8X chunk.");
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
+ LOG_ERROR("ANIM chunk detected before VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (chunk_data->size_ != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
+ LOG_ERROR("Corrupted ANIM chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ webp_info->bgcolor_ = ReadLE32(&data);
+ webp_info->loop_count_ = ReadLE16(&data);
+ ++webp_info->chunk_counts_[CHUNK_ANIM];
+ if (!webp_info->quiet_) {
+ printf(" Background color:(ARGB) %02x %02x %02x %02x\n",
+ (webp_info->bgcolor_ >> 24) & 0xff,
+ (webp_info->bgcolor_ >> 16) & 0xff,
+ (webp_info->bgcolor_ >> 8) & 0xff,
+ webp_info->bgcolor_ & 0xff);
+ printf(" Loop count : %d\n", webp_info->loop_count_);
+ }
+ if (webp_info->loop_count_ > MAX_LOOP_COUNT) {
+ LOG_WARN("Loop count is out of range in ANIM chunk.");
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_;
+ int offset_x, offset_y, width, height, duration, blend, dispose, temp;
+ if (webp_info->is_processing_anim_frame_) {
+ LOG_ERROR("ANMF chunk detected within another ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (!webp_info->chunk_counts_[CHUNK_ANIM]) {
+ LOG_ERROR("ANMF chunk detected before ANIM chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (chunk_data->size_ <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) {
+ LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ offset_x = 2 * ReadLE24(&data);
+ offset_y = 2 * ReadLE24(&data);
+ width = 1 + ReadLE24(&data);
+ height = 1 + ReadLE24(&data);
+ duration = ReadLE24(&data);
+ temp = *data;
+ dispose = temp & 1;
+ blend = (temp >> 1) & 1;
+ ++webp_info->chunk_counts_[CHUNK_ANMF];
+ if (!webp_info->quiet_) {
+ printf(" Offset_X: %d\n Offset_Y: %d\n Width: %d\n Height: %d\n"
+ " Duration: %d\n Dispose: %d\n Blend: %d\n",
+ offset_x, offset_y, width, height, duration, dispose, blend);
+ }
+ if (duration > MAX_DURATION) {
+ LOG_ERROR("Invalid duration parameter in ANMF chunk.");
+ return WEBP_INFO_INVALID_PARAM;
+ }
+ if (offset_x > MAX_POSITION_OFFSET || offset_y > MAX_POSITION_OFFSET) {
+ LOG_ERROR("Invalid offset parameters in ANMF chunk.");
+ return WEBP_INFO_INVALID_PARAM;
+ }
+ if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width_ ||
+ (uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height_) {
+ LOG_ERROR("Frame exceeds canvas in ANMF chunk.");
+ return WEBP_INFO_INVALID_PARAM;
+ }
+ webp_info->is_processing_anim_frame_ = 1;
+ webp_info->seen_alpha_subchunk_ = 0;
+ webp_info->seen_image_subchunk_ = 0;
+ webp_info->frame_width_ = width;
+ webp_info->frame_height_ = height;
+ webp_info->anim_frame_data_size_ =
+ chunk_data->size_ - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE;
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ const uint8_t* data = chunk_data->payload_ - CHUNK_HEADER_SIZE;
+ WebPBitstreamFeatures features;
+ const VP8StatusCode vp8_status =
+ WebPGetFeatures(data, chunk_data->size_, &features);
+ if (vp8_status != VP8_STATUS_OK) {
+ LOG_ERROR("VP8/VP8L bitstream error.");
+ return WEBP_INFO_BITSTREAM_ERROR;
+ }
+ if (!webp_info->quiet_) {
+ assert(features.format >= 0 && features.format <= 2);
+ printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n"
+ " Format: %s (%d)\n",
+ features.width, features.height, features.has_alpha,
+ features.has_animation, kFormats[features.format], features.format);
+ }
+ if (webp_info->is_processing_anim_frame_) {
+ ++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1];
+ if (chunk_data->id_ == CHUNK_VP8L && webp_info->seen_alpha_subchunk_) {
+ LOG_ERROR("Both VP8L and ALPH sub-chunks are present in an ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->frame_width_ != features.width ||
+ webp_info->frame_height_ != features.height) {
+ LOG_ERROR("Frame size in VP8/VP8L sub-chunk differs from ANMF header.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->seen_image_subchunk_) {
+ LOG_ERROR("Consecutive VP8/VP8L sub-chunks in an ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ webp_info->seen_image_subchunk_ = 1;
+ } else {
+ if (webp_info->chunk_counts_[CHUNK_VP8] ||
+ webp_info->chunk_counts_[CHUNK_VP8L]) {
+ LOG_ERROR("Multiple VP8/VP8L chunks detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (chunk_data->id_ == CHUNK_VP8L &&
+ webp_info->chunk_counts_[CHUNK_ALPHA]) {
+ LOG_WARN("Both VP8L and ALPH chunks are detected.");
+ }
+ if (webp_info->chunk_counts_[CHUNK_ANIM] ||
+ webp_info->chunk_counts_[CHUNK_ANMF]) {
+ LOG_ERROR("VP8/VP8L chunk and ANIM/ANMF chunk are both detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->chunk_counts_[CHUNK_VP8X]) {
+ if (webp_info->canvas_width_ != features.width ||
+ webp_info->canvas_height_ != features.height) {
+ LOG_ERROR("Image size in VP8/VP8L chunk differs from VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ } else {
+ webp_info->canvas_width_ = features.width;
+ webp_info->canvas_height_ = features.height;
+ if (webp_info->canvas_width_ < 1 || webp_info->canvas_height_ < 1 ||
+ webp_info->canvas_width_ > MAX_CANVAS_SIZE ||
+ webp_info->canvas_height_ > MAX_CANVAS_SIZE ||
+ (uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
+ MAX_IMAGE_AREA) {
+ LOG_WARN("Invalid parameters in VP8/VP8L chunk.");
+ }
+ }
+ ++webp_info->chunk_counts_[chunk_data->id_];
+ }
+ ++webp_info->num_frames_;
+ webp_info->has_alpha_ |= features.has_alpha;
+ if (webp_info->parse_bitstream_) {
+ const int is_lossy = (chunk_data->id_ == CHUNK_VP8);
+ const WebPInfoStatus status =
+ is_lossy ? ParseLossyHeader(chunk_data, webp_info)
+ : ParseLosslessHeader(chunk_data, webp_info);
+ if (status != WEBP_INFO_OK) return status;
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ if (webp_info->is_processing_anim_frame_) {
+ ++webp_info->anmf_subchunk_counts_[2];
+ if (webp_info->seen_alpha_subchunk_) {
+ LOG_ERROR("Consecutive ALPH sub-chunks in an ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ webp_info->seen_alpha_subchunk_ = 1;
+
+ if (webp_info->seen_image_subchunk_) {
+ LOG_ERROR("ALPHA sub-chunk detected after VP8 sub-chunk "
+ "in an ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ } else {
+ if (webp_info->chunk_counts_[CHUNK_ANIM] ||
+ webp_info->chunk_counts_[CHUNK_ANMF]) {
+ LOG_ERROR("ALPHA chunk and ANIM/ANMF chunk are both detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
+ LOG_ERROR("ALPHA chunk detected before VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->chunk_counts_[CHUNK_VP8]) {
+ LOG_ERROR("ALPHA chunk detected after VP8 chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->chunk_counts_[CHUNK_ALPHA]) {
+ LOG_ERROR("Multiple ALPHA chunks detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ ++webp_info->chunk_counts_[CHUNK_ALPHA];
+ }
+ webp_info->has_alpha_ = 1;
+ if (webp_info->parse_bitstream_) {
+ const WebPInfoStatus status = ParseAlphaHeader(chunk_data, webp_info);
+ if (status != WEBP_INFO_OK) return status;
+ }
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessICCPChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ (void)chunk_data;
+ if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
+ LOG_ERROR("ICCP chunk detected before VP8X chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (webp_info->chunk_counts_[CHUNK_VP8] ||
+ webp_info->chunk_counts_[CHUNK_VP8L] ||
+ webp_info->chunk_counts_[CHUNK_ANIM]) {
+ LOG_ERROR("ICCP chunk detected after image data.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ ++webp_info->chunk_counts_[CHUNK_ICCP];
+ return WEBP_INFO_OK;
+}
+
+static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
+ WebPInfo* const webp_info) {
+ WebPInfoStatus status = WEBP_INFO_OK;
+ ChunkID id = chunk_data->id_;
+ if (chunk_data->id_ == CHUNK_UNKNOWN) {
+ char error_message[50];
+ snprintf(error_message, 50, "Unknown chunk at offset %6d, length %6d",
+ (int)chunk_data->offset_, (int)chunk_data->size_);
+ LOG_WARN(error_message);
+ } else {
+ if (!webp_info->quiet_) {
+ char tag[4];
+ uint32_t fourcc = kWebPChunkTags[chunk_data->id_];
+#ifdef WORDS_BIGENDIAN
+ fourcc = (fourcc >> 24) | ((fourcc >> 8) & 0xff00) |
+ ((fourcc << 8) & 0xff0000) | (fourcc << 24);
+#endif
+ memcpy(tag, &fourcc, sizeof(tag));
+ printf("Chunk %c%c%c%c at offset %6d, length %6d\n",
+ tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_,
+ (int)chunk_data->size_);
+ }
+ }
+ switch (id) {
+ case CHUNK_VP8:
+ case CHUNK_VP8L:
+ status = ProcessImageChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_VP8X:
+ status = ProcessVP8XChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_ALPHA:
+ status = ProcessALPHChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_ANIM:
+ status = ProcessANIMChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_ANMF:
+ status = ProcessANMFChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_ICCP:
+ status = ProcessICCPChunk(chunk_data, webp_info);
+ break;
+ case CHUNK_EXIF:
+ case CHUNK_XMP:
+ ++webp_info->chunk_counts_[id];
+ break;
+ case CHUNK_UNKNOWN:
+ default:
+ break;
+ }
+ if (webp_info->is_processing_anim_frame_ && id != CHUNK_ANMF) {
+ if (webp_info->anim_frame_data_size_ == chunk_data->size_) {
+ if (!webp_info->seen_image_subchunk_) {
+ LOG_ERROR("No VP8/VP8L chunk detected in an ANMF chunk.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ webp_info->is_processing_anim_frame_ = 0;
+ } else if (webp_info->anim_frame_data_size_ > chunk_data->size_) {
+ webp_info->anim_frame_data_size_ -= chunk_data->size_;
+ } else {
+ LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
+ return WEBP_INFO_TRUNCATED_DATA;
+ }
+ }
+ return status;
+}
+
+static WebPInfoStatus Validate(WebPInfo* const webp_info) {
+ if (webp_info->num_frames_ < 1) {
+ LOG_ERROR("No image/frame detected.");
+ return WEBP_INFO_MISSING_DATA;
+ }
+ if (webp_info->chunk_counts_[CHUNK_VP8X]) {
+ const int iccp = !!(webp_info->feature_flags_ & ICCP_FLAG);
+ const int exif = !!(webp_info->feature_flags_ & EXIF_FLAG);
+ const int xmp = !!(webp_info->feature_flags_ & XMP_FLAG);
+ const int animation = !!(webp_info->feature_flags_ & ANIMATION_FLAG);
+ const int alpha = !!(webp_info->feature_flags_ & ALPHA_FLAG);
+ if (!alpha && webp_info->has_alpha_) {
+ LOG_ERROR("Unexpected alpha data detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (alpha && !webp_info->has_alpha_) {
+ LOG_WARN("Alpha flag is set with no alpha data present.");
+ }
+ if (iccp && !webp_info->chunk_counts_[CHUNK_ICCP]) {
+ LOG_ERROR("Missing ICCP chunk.");
+ return WEBP_INFO_MISSING_DATA;
+ }
+ if (exif && !webp_info->chunk_counts_[CHUNK_EXIF]) {
+ LOG_ERROR("Missing EXIF chunk.");
+ return WEBP_INFO_MISSING_DATA;
+ }
+ if (xmp && !webp_info->chunk_counts_[CHUNK_XMP]) {
+ LOG_ERROR("Missing XMP chunk.");
+ return WEBP_INFO_MISSING_DATA;
+ }
+ if (!iccp && webp_info->chunk_counts_[CHUNK_ICCP]) {
+ LOG_ERROR("Unexpected ICCP chunk detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (!exif && webp_info->chunk_counts_[CHUNK_EXIF]) {
+ LOG_ERROR("Unexpected EXIF chunk detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (!xmp && webp_info->chunk_counts_[CHUNK_XMP]) {
+ LOG_ERROR("Unexpected XMP chunk detected.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ // Incomplete animation frame.
+ if (webp_info->is_processing_anim_frame_) return WEBP_INFO_MISSING_DATA;
+ if (!animation && webp_info->num_frames_ > 1) {
+ LOG_ERROR("More than 1 frame detected in non-animation file.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ if (animation && (!webp_info->chunk_counts_[CHUNK_ANIM] ||
+ !webp_info->chunk_counts_[CHUNK_ANMF])) {
+ LOG_ERROR("No ANIM/ANMF chunk detected in animation file.");
+ return WEBP_INFO_PARSE_ERROR;
+ }
+ }
+ return WEBP_INFO_OK;
+}
+
+static void ShowSummary(const WebPInfo* const webp_info) {
+ int i;
+ printf("Summary:\n");
+ printf("Number of frames: %d\n", webp_info->num_frames_);
+ printf("Chunk type : VP8 VP8L VP8X ALPH ANIM ANMF(VP8 /VP8L/ALPH) ICCP "
+ "EXIF XMP\n");
+ printf("Chunk counts: ");
+ for (i = 0; i < CHUNK_TYPES; ++i) {
+ printf("%4d ", webp_info->chunk_counts_[i]);
+ if (i == CHUNK_ANMF) {
+ printf("%4d %4d %4d ",
+ webp_info->anmf_subchunk_counts_[0],
+ webp_info->anmf_subchunk_counts_[1],
+ webp_info->anmf_subchunk_counts_[2]);
+ }
+ }
+ printf("\n");
+}
+
+static WebPInfoStatus AnalyzeWebP(WebPInfo* const webp_info,
+ const WebPData* webp_data) {
+ ChunkData chunk_data;
+ MemBuffer mem_buffer;
+ WebPInfoStatus webp_info_status = WEBP_INFO_OK;
+
+ InitMemBuffer(&mem_buffer, webp_data);
+ webp_info_status = ParseRIFFHeader(webp_info, &mem_buffer);
+ if (webp_info_status != WEBP_INFO_OK) goto Error;
+
+ // Loop through all the chunks. Terminate immediately in case of error.
+ while (webp_info_status == WEBP_INFO_OK && MemDataSize(&mem_buffer) > 0) {
+ webp_info_status = ParseChunk(webp_info, &mem_buffer, &chunk_data);
+ if (webp_info_status != WEBP_INFO_OK) goto Error;
+ webp_info_status = ProcessChunk(&chunk_data, webp_info);
+ }
+ if (webp_info_status != WEBP_INFO_OK) goto Error;
+ if (webp_info->show_summary_) ShowSummary(webp_info);
+
+ // Final check.
+ webp_info_status = Validate(webp_info);
+
+ Error:
+ if (!webp_info->quiet_) {
+ if (webp_info_status == WEBP_INFO_OK) {
+ printf("No error detected.\n");
+ } else {
+ printf("Errors detected.\n");
+ }
+ if (webp_info->num_warnings_ > 0) {
+ printf("There were %d warning(s).\n", webp_info->num_warnings_);
+ }
+ }
+ return webp_info_status;
+}
+
+static void Help(void) {
+ printf("Usage: webpinfo [options] in_files\n"
+ "Note: there could be multiple input files;\n"
+ " options must come before input files.\n"
+ "Options:\n"
+ " -version ........... Print version number and exit.\n"
+ " -quiet ............. Do not show chunk parsing information.\n"
+ " -diag .............. Show parsing error diagnosis.\n"
+ " -summary ........... Show chunk stats summary.\n"
+ " -bitstream_info .... Parse bitstream header.\n");
+}
+
+int main(int argc, const char* argv[]) {
+ int c, quiet = 0, show_diag = 0, show_summary = 0;
+ int parse_bitstream = 0;
+ WebPInfoStatus webp_info_status = WEBP_INFO_OK;
+ WebPInfo webp_info;
+
+ INIT_WARGV(argc, argv);
+
+ if (argc == 1) {
+ Help();
+ FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
+ }
+
+ // Parse command-line input.
+ for (c = 1; c < argc; ++c) {
+ if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help") ||
+ !strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
+ Help();
+ FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
+ } else if (!strcmp(argv[c], "-quiet")) {
+ quiet = 1;
+ } else if (!strcmp(argv[c], "-diag")) {
+ show_diag = 1;
+ } else if (!strcmp(argv[c], "-summary")) {
+ show_summary = 1;
+ } else if (!strcmp(argv[c], "-bitstream_info")) {
+ parse_bitstream = 1;
+ } else if (!strcmp(argv[c], "-version")) {
+ const int version = WebPGetDecoderVersion();
+ printf("WebP Decoder version: %d.%d.%d\n",
+ (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
+ FREE_WARGV_AND_RETURN(0);
+ } else { // Assume the remaining are all input files.
+ break;
+ }
+ }
+
+ if (c == argc) {
+ Help();
+ FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND);
+ }
+
+ // Process input files one by one.
+ for (; c < argc; ++c) {
+ WebPData webp_data;
+ const W_CHAR* in_file = NULL;
+ WebPInfoInit(&webp_info);
+ webp_info.quiet_ = quiet;
+ webp_info.show_diagnosis_ = show_diag;
+ webp_info.show_summary_ = show_summary;
+ webp_info.parse_bitstream_ = parse_bitstream;
+ in_file = GET_WARGV(argv, c);
+ if (in_file == NULL ||
+ !ReadFileToWebPData((const char*)in_file, &webp_data)) {
+ webp_info_status = WEBP_INFO_INVALID_COMMAND;
+ WFPRINTF(stderr, "Failed to open input file %s.\n", in_file);
+ continue;
+ }
+ if (!webp_info.quiet_) WPRINTF("File: %s\n", in_file);
+ webp_info_status = AnalyzeWebP(&webp_info, &webp_data);
+ WebPDataClear(&webp_data);
+ }
+ FREE_WARGV_AND_RETURN(webp_info_status);
+}
diff --git a/examples/webpmux.c b/examples/webpmux.c
new file mode 100644
index 0000000..b61eed6
--- /dev/null
+++ b/examples/webpmux.c
@@ -0,0 +1,1234 @@
+// 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 command-line to create a WebP container file and to extract or strip
+// relevant data from the container file.
+//
+// Authors: Vikas (vikaas.arora@gmail.com),
+// Urvang (urvang@google.com)
+
+/* Usage examples:
+
+ Create container WebP file:
+ webpmux -frame anim_1.webp +100+10+10 \
+ -frame anim_2.webp +100+25+25+1 \
+ -frame anim_3.webp +100+50+50+1 \
+ -frame anim_4.webp +100 \
+ -loop 10 -bgcolor 128,255,255,255 \
+ -o out_animation_container.webp
+
+ webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
+ webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp
+ webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
+ webpmux -set loop 1 in.webp -o out_looped.webp
+
+ Extract relevant data from WebP container file:
+ webpmux -get frame n in.webp -o out_frame.webp
+ webpmux -get icc in.webp -o image_profile.icc
+ webpmux -get exif in.webp -o image_metadata.exif
+ webpmux -get xmp in.webp -o image_metadata.xmp
+
+ Strip data from WebP Container file:
+ webpmux -strip icc in.webp -o out.webp
+ webpmux -strip exif in.webp -o out.webp
+ webpmux -strip xmp in.webp -o out.webp
+
+ Change duration of frame intervals:
+ webpmux -duration 150 in.webp -o out.webp
+ webpmux -duration 33,2 in.webp -o out.webp
+ webpmux -duration 200,10,0 -duration 150,6,50 in.webp -o out.webp
+
+ Misc:
+ webpmux -info in.webp
+ webpmux [ -h | -help ]
+ webpmux -version
+ webpmux argument_file_name
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "webp/decode.h"
+#include "webp/mux.h"
+#include "../examples/example_util.h"
+#include "../imageio/imageio_util.h"
+#include "./unicode.h"
+
+//------------------------------------------------------------------------------
+// Config object to parse command-line arguments.
+
+typedef enum {
+ NIL_ACTION = 0,
+ ACTION_GET,
+ ACTION_SET,
+ ACTION_STRIP,
+ ACTION_INFO,
+ ACTION_HELP,
+ ACTION_DURATION
+} ActionType;
+
+typedef enum {
+ NIL_SUBTYPE = 0,
+ SUBTYPE_ANMF,
+ SUBTYPE_LOOP,
+ SUBTYPE_BGCOLOR
+} FeatureSubType;
+
+typedef struct {
+ FeatureSubType subtype_;
+ const char* filename_;
+ const char* params_;
+} FeatureArg;
+
+typedef enum {
+ NIL_FEATURE = 0,
+ FEATURE_EXIF,
+ FEATURE_XMP,
+ FEATURE_ICCP,
+ FEATURE_ANMF,
+ FEATURE_DURATION,
+ FEATURE_LOOP,
+ FEATURE_BGCOLOR,
+ LAST_FEATURE
+} FeatureType;
+
+static const char* const kFourccList[LAST_FEATURE] = {
+ NULL, "EXIF", "XMP ", "ICCP", "ANMF"
+};
+
+static const char* const kDescriptions[LAST_FEATURE] = {
+ NULL, "EXIF metadata", "XMP metadata", "ICC profile",
+ "Animation frame"
+};
+
+typedef struct {
+ CommandLineArguments cmd_args_;
+
+ ActionType action_type_;
+ const char* input_;
+ const char* output_;
+ FeatureType type_;
+ FeatureArg* args_;
+ int arg_count_;
+} Config;
+
+//------------------------------------------------------------------------------
+// Helper functions.
+
+static int CountOccurrences(const CommandLineArguments* const args,
+ const char* const arg) {
+ int i;
+ int num_occurences = 0;
+
+ for (i = 0; i < args->argc_; ++i) {
+ if (!strcmp(args->argv_[i], arg)) {
+ ++num_occurences;
+ }
+ }
+ return num_occurences;
+}
+
+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];
+}
+
+#define RETURN_IF_ERROR(ERR_MSG) \
+ if (err != WEBP_MUX_OK) { \
+ fprintf(stderr, ERR_MSG); \
+ return err; \
+ }
+
+#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \
+ if (err != WEBP_MUX_OK) { \
+ fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
+ return err; \
+ }
+
+#define ERROR_GOTO1(ERR_MSG, LABEL) \
+ do { \
+ fprintf(stderr, ERR_MSG); \
+ ok = 0; \
+ goto LABEL; \
+ } while (0)
+
+#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
+ do { \
+ fprintf(stderr, ERR_MSG, FORMAT_STR); \
+ ok = 0; \
+ goto LABEL; \
+ } while (0)
+
+#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
+ do { \
+ fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
+ ok = 0; \
+ goto LABEL; \
+ } while (0)
+
+static WebPMuxError DisplayInfo(const WebPMux* mux) {
+ int width, height;
+ uint32_t flag;
+
+ WebPMuxError err = WebPMuxGetCanvasSize(mux, &width, &height);
+ assert(err == WEBP_MUX_OK); // As WebPMuxCreate() was successful earlier.
+ printf("Canvas size: %d x %d\n", width, height);
+
+ err = WebPMuxGetFeatures(mux, &flag);
+ RETURN_IF_ERROR("Failed to retrieve features\n");
+
+ if (flag == 0) {
+ printf("No features present.\n");
+ return err;
+ }
+
+ // Print the features present.
+ printf("Features present:");
+ if (flag & ANIMATION_FLAG) printf(" animation");
+ if (flag & ICCP_FLAG) printf(" ICC profile");
+ if (flag & EXIF_FLAG) printf(" EXIF metadata");
+ if (flag & XMP_FLAG) printf(" XMP metadata");
+ if (flag & ALPHA_FLAG) printf(" transparency");
+ printf("\n");
+
+ if (flag & ANIMATION_FLAG) {
+ const WebPChunkId id = WEBP_CHUNK_ANMF;
+ const char* const type_str = "frame";
+ int nFrames;
+
+ WebPMuxAnimParams params;
+ err = WebPMuxGetAnimationParams(mux, ¶ms);
+ assert(err == WEBP_MUX_OK);
+ printf("Background color : 0x%.8X Loop Count : %d\n",
+ params.bgcolor, params.loop_count);
+
+ err = WebPMuxNumChunks(mux, id, &nFrames);
+ assert(err == WEBP_MUX_OK);
+
+ printf("Number of %ss: %d\n", type_str, nFrames);
+ if (nFrames > 0) {
+ int i;
+ printf("No.: width height alpha x_offset y_offset ");
+ printf("duration dispose blend ");
+ printf("image_size compression\n");
+ for (i = 1; i <= nFrames; i++) {
+ WebPMuxFrameInfo frame;
+ err = WebPMuxGetFrame(mux, i, &frame);
+ if (err == WEBP_MUX_OK) {
+ WebPBitstreamFeatures features;
+ const VP8StatusCode status = WebPGetFeatures(
+ frame.bitstream.bytes, frame.bitstream.size, &features);
+ assert(status == VP8_STATUS_OK); // Checked by WebPMuxCreate().
+ (void)status;
+ printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
+ features.height, features.has_alpha ? "yes" : "no",
+ frame.x_offset, frame.y_offset);
+ {
+ const char* const dispose =
+ (frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
+ : "background";
+ const char* const blend =
+ (frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no";
+ printf("%8d %10s %5s ", frame.duration, dispose, blend);
+ }
+ printf("%10d %11s\n", (int)frame.bitstream.size,
+ (features.format == 1) ? "lossy" :
+ (features.format == 2) ? "lossless" :
+ "undefined");
+ }
+ WebPDataClear(&frame.bitstream);
+ RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
+ }
+ }
+ }
+
+ if (flag & ICCP_FLAG) {
+ WebPData icc_profile;
+ err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
+ assert(err == WEBP_MUX_OK);
+ printf("Size of the ICC profile data: %d\n", (int)icc_profile.size);
+ }
+
+ if (flag & EXIF_FLAG) {
+ WebPData exif;
+ err = WebPMuxGetChunk(mux, "EXIF", &exif);
+ assert(err == WEBP_MUX_OK);
+ printf("Size of the EXIF metadata: %d\n", (int)exif.size);
+ }
+
+ if (flag & XMP_FLAG) {
+ WebPData xmp;
+ err = WebPMuxGetChunk(mux, "XMP ", &xmp);
+ assert(err == WEBP_MUX_OK);
+ printf("Size of the XMP metadata: %d\n", (int)xmp.size);
+ }
+
+ if ((flag & ALPHA_FLAG) && !(flag & ANIMATION_FLAG)) {
+ WebPMuxFrameInfo image;
+ err = WebPMuxGetFrame(mux, 1, &image);
+ if (err == WEBP_MUX_OK) {
+ printf("Size of the image (with alpha): %d\n", (int)image.bitstream.size);
+ }
+ WebPDataClear(&image.bitstream);
+ RETURN_IF_ERROR("Failed to retrieve the image\n");
+ }
+
+ return WEBP_MUX_OK;
+}
+
+static void PrintHelp(void) {
+ printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
+ printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
+ printf(" webpmux -duration DURATION_OPTIONS [-duration ...]\n");
+ printf(" INPUT -o OUTPUT\n");
+ printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
+ printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]"
+ "\n");
+ printf(" [-bgcolor BACKGROUND_COLOR] -o OUTPUT\n");
+ printf(" webpmux -info INPUT\n");
+ printf(" webpmux [-h|-help]\n");
+ printf(" webpmux -version\n");
+ printf(" webpmux argument_file_name\n");
+
+ printf("\n");
+ printf("GET_OPTIONS:\n");
+ printf(" Extract relevant data:\n");
+ printf(" icc get ICC profile\n");
+ printf(" exif get EXIF metadata\n");
+ printf(" xmp get XMP metadata\n");
+ printf(" frame n get nth frame\n");
+
+ printf("\n");
+ printf("SET_OPTIONS:\n");
+ printf(" Set color profile/metadata/parameters:\n");
+ printf(" loop LOOP_COUNT set the loop count\n");
+ printf(" bgcolor BACKGROUND_COLOR set the animation background color\n");
+ printf(" icc file.icc set ICC profile\n");
+ printf(" exif file.exif set EXIF metadata\n");
+ printf(" xmp file.xmp set XMP metadata\n");
+ printf(" where: 'file.icc' contains the ICC profile to be set,\n");
+ printf(" 'file.exif' contains the EXIF metadata to be set\n");
+ printf(" 'file.xmp' contains the XMP metadata to be set\n");
+
+ printf("\n");
+ printf("DURATION_OPTIONS:\n");
+ printf(" Set duration of selected frames:\n");
+ printf(" duration set duration for all frames\n");
+ printf(" duration,frame set duration of a particular frame\n");
+ printf(" duration,start,end set duration of frames in the\n");
+ printf(" interval [start,end])\n");
+ printf(" where: 'duration' is the duration in milliseconds\n");
+ printf(" 'start' is the start frame index\n");
+ printf(" 'end' is the inclusive end frame index\n");
+ printf(" The special 'end' value '0' means: last frame.\n");
+
+ printf("\n");
+ printf("STRIP_OPTIONS:\n");
+ printf(" Strip color profile/metadata:\n");
+ printf(" icc strip ICC profile\n");
+ printf(" exif strip EXIF metadata\n");
+ printf(" xmp strip XMP metadata\n");
+
+ printf("\n");
+ printf("FRAME_OPTIONS(i):\n");
+ printf(" Create animation:\n");
+ printf(" file_i +di[+xi+yi[+mi[bi]]]\n");
+ printf(" where: 'file_i' is the i'th animation frame (WebP format),\n");
+ printf(" 'di' is the pause duration before next frame,\n");
+ printf(" 'xi','yi' specify the image offset for this frame,\n");
+ printf(" 'mi' is the dispose method for this frame (0 or 1),\n");
+ printf(" 'bi' is the blending method for this frame (+b or -b)"
+ "\n");
+
+ printf("\n");
+ printf("LOOP_COUNT:\n");
+ printf(" Number of times to repeat the animation.\n");
+ printf(" Valid range is 0 to 65535 [Default: 0 (infinite)].\n");
+
+ printf("\n");
+ printf("BACKGROUND_COLOR:\n");
+ printf(" Background color of the canvas.\n");
+ printf(" A,R,G,B\n");
+ printf(" where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 "
+ "specifying\n");
+ printf(" the Alpha, Red, Green and Blue component values "
+ "respectively\n");
+ printf(" [Default: 255,255,255,255]\n");
+
+ printf("\nINPUT & OUTPUT are in WebP format.\n");
+
+ printf("\nNote: The nature of EXIF, XMP and ICC data is not checked");
+ printf(" and is assumed to be\nvalid.\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 void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
+ if ((info->x_offset | info->y_offset) & 1) {
+ fprintf(stderr, "Warning: odd offsets will be snapped to even values"
+ " (%d, %d) -> (%d, %d)\n", info->x_offset, info->y_offset,
+ info->x_offset & ~1, info->y_offset & ~1);
+ }
+}
+
+static int CreateMux(const char* const filename, WebPMux** mux) {
+ WebPData bitstream;
+ assert(mux != NULL);
+ if (!ExUtilReadFileToWebPData(filename, &bitstream)) return 0;
+ *mux = WebPMuxCreate(&bitstream, 1);
+ WebPDataClear(&bitstream);
+ if (*mux != NULL) return 1;
+ WFPRINTF(stderr, "Failed to create mux object from file %s.\n",
+ (const W_CHAR*)filename);
+ return 0;
+}
+
+static int WriteData(const char* filename, const WebPData* const webpdata) {
+ int ok = 0;
+ FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb")
+ : ImgIoUtilSetBinaryMode(stdout);
+ if (fout == NULL) {
+ WFPRINTF(stderr, "Error opening output WebP file %s!\n",
+ (const W_CHAR*)filename);
+ return 0;
+ }
+ if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) {
+ WFPRINTF(stderr, "Error writing file %s!\n", (const W_CHAR*)filename);
+ } else {
+ WFPRINTF(stderr, "Saved file %s (%d bytes)\n",
+ (const W_CHAR*)filename, (int)webpdata->size);
+ ok = 1;
+ }
+ if (fout != stdout) fclose(fout);
+ return ok;
+}
+
+static int WriteWebP(WebPMux* const mux, const char* filename) {
+ int ok;
+ WebPData webp_data;
+ const WebPMuxError err = WebPMuxAssemble(mux, &webp_data);
+ if (err != WEBP_MUX_OK) {
+ fprintf(stderr, "Error (%s) assembling the WebP file.\n", ErrorString(err));
+ return 0;
+ }
+ ok = WriteData(filename, &webp_data);
+ WebPDataClear(&webp_data);
+ return ok;
+}
+
+static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
+ WebPMux* new_mux = WebPMuxNew();
+ WebPMuxAnimParams p;
+ WebPMuxError err;
+ int i;
+ int ok = 1;
+
+ if (new_mux == NULL) return NULL;
+
+ err = WebPMuxGetAnimationParams(mux, &p);
+ if (err == WEBP_MUX_OK) {
+ err = WebPMuxSetAnimationParams(new_mux, &p);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO2("Error (%s) handling animation params.\n",
+ ErrorString(err), End);
+ }
+ } else {
+ /* it might not be an animation. Just keep moving. */
+ }
+
+ for (i = 1; i <= 3; ++i) {
+ WebPData metadata;
+ err = WebPMuxGetChunk(mux, kFourccList[i], &metadata);
+ if (err == WEBP_MUX_OK && metadata.size > 0) {
+ err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO1("Error transferring metadata in DuplicateMuxHeader().",
+ End);
+ }
+ }
+ }
+
+ End:
+ if (!ok) {
+ WebPMuxDelete(new_mux);
+ new_mux = NULL;
+ }
+ return new_mux;
+}
+
+static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
+ int dispose_method, unused;
+ char plus_minus, blend_method;
+ const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
+ &info->x_offset, &info->y_offset, &dispose_method,
+ &plus_minus, &blend_method, &unused);
+ switch (num_args) {
+ case 1:
+ info->x_offset = info->y_offset = 0; // fall through
+ case 3:
+ dispose_method = 0; // fall through
+ case 4:
+ plus_minus = '+';
+ blend_method = 'b'; // fall through
+ case 6:
+ break;
+ case 2:
+ case 5:
+ default:
+ return 0;
+ }
+
+ WarnAboutOddOffset(info);
+
+ // Note: The validity of the following conversion is checked by
+ // WebPMuxPushFrame().
+ info->dispose_method = (WebPMuxAnimDispose)dispose_method;
+
+ if (blend_method != 'b') return 0;
+ if (plus_minus != '-' && plus_minus != '+') return 0;
+ info->blend_method =
+ (plus_minus == '+') ? WEBP_MUX_BLEND : WEBP_MUX_NO_BLEND;
+ return 1;
+}
+
+static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
+ uint32_t a, r, g, b;
+ if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
+ if (a >= 256 || r >= 256 || g >= 256 || b >= 256) return 0;
+ *bgcolor = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Clean-up.
+
+static void DeleteConfig(Config* const config) {
+ if (config != NULL) {
+ free(config->args_);
+ ExUtilDeleteCommandLineArguments(&config->cmd_args_);
+ memset(config, 0, sizeof(*config));
+ }
+}
+
+//------------------------------------------------------------------------------
+// Parsing.
+
+// Basic syntactic checks on the command-line arguments.
+// Returns 1 on valid, 0 otherwise.
+// Also fills up num_feature_args to be number of feature arguments given.
+// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
+static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
+ int* num_feature_args) {
+ int num_frame_args;
+ int num_loop_args;
+ int num_bgcolor_args;
+ int num_durations_args;
+ int ok = 1;
+
+ assert(num_feature_args != NULL);
+ *num_feature_args = 0;
+
+ // Simple checks.
+ if (CountOccurrences(cmd_args, "-get") > 1) {
+ ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
+ }
+ if (CountOccurrences(cmd_args, "-set") > 1) {
+ ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
+ }
+ if (CountOccurrences(cmd_args, "-strip") > 1) {
+ ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
+ }
+ if (CountOccurrences(cmd_args, "-info") > 1) {
+ ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
+ }
+ if (CountOccurrences(cmd_args, "-o") > 1) {
+ ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
+ }
+
+ // Compound checks.
+ num_frame_args = CountOccurrences(cmd_args, "-frame");
+ num_loop_args = CountOccurrences(cmd_args, "-loop");
+ num_bgcolor_args = CountOccurrences(cmd_args, "-bgcolor");
+ num_durations_args = CountOccurrences(cmd_args, "-duration");
+
+ if (num_loop_args > 1) {
+ ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
+ }
+ if (num_bgcolor_args > 1) {
+ ERROR_GOTO1("ERROR: Multiple background colors specified.\n", ErrValidate);
+ }
+
+ if ((num_frame_args == 0) && (num_loop_args + num_bgcolor_args > 0)) {
+ ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
+ "case of animation.\n", ErrValidate);
+ }
+ if (num_durations_args > 0 && num_frame_args != 0) {
+ ERROR_GOTO1("ERROR: Can not combine -duration and -frame commands.\n",
+ ErrValidate);
+ }
+
+ assert(ok == 1);
+ if (num_durations_args > 0) {
+ *num_feature_args = num_durations_args;
+ } else if (num_frame_args == 0) {
+ // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
+ *num_feature_args = 1;
+ } else {
+ // Multiple arguments ('set' action for animation)
+ *num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
+ }
+
+ ErrValidate:
+ return ok;
+}
+
+#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
+
+#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE)
+
+#define CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL) \
+ if (argc < i + (NUM)) { \
+ fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
+ goto LABEL; \
+ }
+
+#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \
+ if (argc > i + (NUM)) { \
+ fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
+ goto LABEL; \
+ }
+
+#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \
+ CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
+ CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
+
+// Parses command-line arguments to fill up config object. Also performs some
+// semantic checks. unicode_argv contains wchar_t arguments or is null.
+static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
+ int i = 0;
+ int feature_arg_index = 0;
+ int ok = 1;
+ int argc = config->cmd_args_.argc_;
+ const char* const* argv = config->cmd_args_.argv_;
+ // Unicode file paths will be used if available.
+ const char* const* wargv =
+ (unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv;
+
+ while (i < argc) {
+ FeatureArg* const arg = &config->args_[feature_arg_index];
+ if (argv[i][0] == '-') { // One of the action types or output.
+ if (!strcmp(argv[i], "-set")) {
+ if (ACTION_IS_NIL) {
+ config->action_type_ = ACTION_SET;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ ++i;
+ } else if (!strcmp(argv[i], "-duration")) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
+ config->action_type_ = ACTION_DURATION;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) {
+ config->type_ = FEATURE_DURATION;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
+ }
+ arg->params_ = argv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else if (!strcmp(argv[i], "-get")) {
+ if (ACTION_IS_NIL) {
+ config->action_type_ = ACTION_GET;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ ++i;
+ } else if (!strcmp(argv[i], "-strip")) {
+ if (ACTION_IS_NIL) {
+ config->action_type_ = ACTION_STRIP;
+ config->arg_count_ = 0;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ ++i;
+ } else if (!strcmp(argv[i], "-frame")) {
+ CHECK_NUM_ARGS_AT_LEAST(3, ErrParse);
+ if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
+ config->action_type_ = ACTION_SET;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
+ config->type_ = FEATURE_ANMF;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
+ }
+ arg->subtype_ = SUBTYPE_ANMF;
+ arg->filename_ = wargv[i + 1];
+ arg->params_ = argv[i + 2];
+ ++feature_arg_index;
+ i += 3;
+ } else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
+ config->action_type_ = ACTION_SET;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ }
+ if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) {
+ config->type_ = FEATURE_ANMF;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
+ }
+ arg->subtype_ =
+ !strcmp(argv[i], "-loop") ? SUBTYPE_LOOP : SUBTYPE_BGCOLOR;
+ arg->params_ = argv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else if (!strcmp(argv[i], "-o")) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ config->output_ = wargv[i + 1];
+ i += 2;
+ } else if (!strcmp(argv[i], "-info")) {
+ CHECK_NUM_ARGS_EXACTLY(2, ErrParse);
+ if (config->action_type_ != NIL_ACTION) {
+ ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
+ } else {
+ config->action_type_ = ACTION_INFO;
+ config->arg_count_ = 0;
+ config->input_ = wargv[i + 1];
+ }
+ i += 2;
+ } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
+ PrintHelp();
+ DeleteConfig(config);
+ LOCAL_FREE((W_CHAR** const)unicode_argv);
+ exit(0);
+ } else if (!strcmp(argv[i], "-version")) {
+ const int version = WebPGetMuxVersion();
+ printf("%d.%d.%d\n",
+ (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
+ DeleteConfig(config);
+ LOCAL_FREE((W_CHAR** const)unicode_argv);
+ exit(0);
+ } else if (!strcmp(argv[i], "--")) {
+ if (i < argc - 1) {
+ ++i;
+ if (config->input_ == NULL) {
+ config->input_ = wargv[i];
+ } else {
+ ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
+ argv[i], ErrParse);
+ }
+ }
+ break;
+ } else {
+ ERROR_GOTO2("ERROR: Unknown option: '%s'.\n", argv[i], ErrParse);
+ }
+ } else { // One of the feature types or input.
+ if (ACTION_IS_NIL) {
+ ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n",
+ ErrParse);
+ }
+ if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
+ !strcmp(argv[i], "xmp")) {
+ if (FEATURETYPE_IS_NIL) {
+ config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
+ (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
+ } else {
+ ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
+ }
+ if (config->action_type_ == ACTION_SET) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ arg->filename_ = wargv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else {
+ ++i;
+ }
+ } else if (!strcmp(argv[i], "frame") &&
+ (config->action_type_ == ACTION_GET)) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ config->type_ = FEATURE_ANMF;
+ arg->params_ = argv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else if (!strcmp(argv[i], "loop") &&
+ (config->action_type_ == ACTION_SET)) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ config->type_ = FEATURE_LOOP;
+ arg->params_ = argv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else if (!strcmp(argv[i], "bgcolor") &&
+ (config->action_type_ == ACTION_SET)) {
+ CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
+ config->type_ = FEATURE_BGCOLOR;
+ arg->params_ = argv[i + 1];
+ ++feature_arg_index;
+ i += 2;
+ } else { // Assume input file.
+ if (config->input_ == NULL) {
+ config->input_ = wargv[i];
+ } else {
+ ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
+ argv[i], ErrParse);
+ }
+ ++i;
+ }
+ }
+ }
+ ErrParse:
+ return ok;
+}
+
+// Additional checks after config is filled.
+static int ValidateConfig(Config* const config) {
+ int ok = 1;
+
+ // Action.
+ if (ACTION_IS_NIL) {
+ ERROR_GOTO1("ERROR: No action specified.\n", ErrValidate2);
+ }
+
+ // Feature type.
+ if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) {
+ ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2);
+ }
+
+ // Input file.
+ if (config->input_ == NULL) {
+ if (config->action_type_ != ACTION_SET) {
+ ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
+ } else if (config->type_ != FEATURE_ANMF) {
+ ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
+ }
+ }
+
+ // Output file.
+ if (config->output_ == NULL && config->action_type_ != ACTION_INFO) {
+ ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2);
+ }
+
+ ErrValidate2:
+ return ok;
+}
+
+// Create config object from command-line arguments.
+static int InitializeConfig(int argc, const char* argv[], Config* const config,
+ const W_CHAR** const unicode_argv) {
+ int num_feature_args = 0;
+ int ok;
+
+ memset(config, 0, sizeof(*config));
+
+ ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args_);
+ if (!ok) return 0;
+
+ // Validate command-line arguments.
+ if (!ValidateCommandLine(&config->cmd_args_, &num_feature_args)) {
+ ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
+ }
+
+ config->arg_count_ = num_feature_args;
+ config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_));
+ if (config->args_ == NULL) {
+ ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
+ }
+
+ // Parse command-line.
+ if (!ParseCommandLine(config, unicode_argv) || !ValidateConfig(config)) {
+ ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
+ }
+
+ Err1:
+ return ok;
+}
+
+#undef ACTION_IS_NIL
+#undef FEATURETYPE_IS_NIL
+#undef CHECK_NUM_ARGS_AT_LEAST
+#undef CHECK_NUM_ARGS_AT_MOST
+#undef CHECK_NUM_ARGS_EXACTLY
+
+//------------------------------------------------------------------------------
+// Processing.
+
+static int GetFrame(const WebPMux* mux, const Config* config) {
+ WebPMuxError err = WEBP_MUX_OK;
+ WebPMux* mux_single = NULL;
+ int num = 0;
+ int ok = 1;
+ int parse_error = 0;
+ const WebPChunkId id = WEBP_CHUNK_ANMF;
+ WebPMuxFrameInfo info;
+ WebPDataInit(&info.bitstream);
+
+ num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
+ if (num < 0) {
+ ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
+ }
+ if (parse_error) goto ErrGet;
+
+ err = WebPMuxGetFrame(mux, num, &info);
+ if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND;
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO3("ERROR (%s): Could not get frame %d.\n",
+ ErrorString(err), num, ErrGet);
+ }
+
+ mux_single = WebPMuxNew();
+ if (mux_single == NULL) {
+ err = WEBP_MUX_MEMORY_ERROR;
+ ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
+ ErrorString(err), ErrGet);
+ }
+ err = WebPMuxSetImage(mux_single, &info.bitstream, 1);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO2("ERROR (%s): Could not create single image mux object.\n",
+ ErrorString(err), ErrGet);
+ }
+
+ ok = WriteWebP(mux_single, config->output_);
+
+ ErrGet:
+ WebPDataClear(&info.bitstream);
+ WebPMuxDelete(mux_single);
+ return ok && !parse_error;
+}
+
+// Read and process config.
+static int Process(const Config* config) {
+ WebPMux* mux = NULL;
+ WebPData chunk;
+ WebPMuxError err = WEBP_MUX_OK;
+ int ok = 1;
+
+ switch (config->action_type_) {
+ case ACTION_GET: {
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ switch (config->type_) {
+ case FEATURE_ANMF:
+ ok = GetFrame(mux, config);
+ break;
+
+ case FEATURE_ICCP:
+ case FEATURE_EXIF:
+ case FEATURE_XMP:
+ err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
+ ErrorString(err), kDescriptions[config->type_], Err2);
+ }
+ ok = WriteData(config->output_, &chunk);
+ break;
+
+ default:
+ ERROR_GOTO1("ERROR: Invalid feature for action 'get'.\n", Err2);
+ break;
+ }
+ break;
+ }
+ case ACTION_SET: {
+ switch (config->type_) {
+ case FEATURE_ANMF: {
+ int i;
+ WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
+ mux = WebPMuxNew();
+ if (mux == NULL) {
+ ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
+ ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
+ }
+ for (i = 0; i < config->arg_count_; ++i) {
+ switch (config->args_[i].subtype_) {
+ case SUBTYPE_BGCOLOR: {
+ uint32_t bgcolor;
+ ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor);
+ if (!ok) {
+ ERROR_GOTO1("ERROR: Could not parse the background color \n",
+ Err2);
+ }
+ params.bgcolor = bgcolor;
+ break;
+ }
+ case SUBTYPE_LOOP: {
+ int parse_error = 0;
+ const int loop_count =
+ ExUtilGetInt(config->args_[i].params_, 10, &parse_error);
+ if (loop_count < 0 || loop_count > 65535) {
+ // Note: This is only a 'necessary' condition for loop_count
+ // to be valid. The 'sufficient' conditioned in checked in
+ // WebPMuxSetAnimationParams() method called later.
+ ERROR_GOTO1("ERROR: Loop count must be in the range 0 to "
+ "65535.\n", Err2);
+ }
+ ok = !parse_error;
+ if (!ok) goto Err2;
+ params.loop_count = loop_count;
+ break;
+ }
+ case SUBTYPE_ANMF: {
+ WebPMuxFrameInfo frame;
+ frame.id = WEBP_CHUNK_ANMF;
+ ok = ExUtilReadFileToWebPData(config->args_[i].filename_,
+ &frame.bitstream);
+ if (!ok) goto Err2;
+ ok = ParseFrameArgs(config->args_[i].params_, &frame);
+ if (!ok) {
+ WebPDataClear(&frame.bitstream);
+ ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
+ Err2);
+ }
+ err = WebPMuxPushFrame(mux, &frame, 1);
+ WebPDataClear(&frame.bitstream);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO3("ERROR (%s): Could not add a frame at index %d."
+ "\n", ErrorString(err), i, Err2);
+ }
+ break;
+ }
+ default: {
+ ERROR_GOTO1("ERROR: Invalid subtype for 'frame'", Err2);
+ break;
+ }
+ }
+ }
+ err = WebPMuxSetAnimationParams(mux, ¶ms);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
+ ErrorString(err), Err2);
+ }
+ break;
+ }
+
+ case FEATURE_ICCP:
+ case FEATURE_EXIF:
+ case FEATURE_XMP: {
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ ok = ExUtilReadFileToWebPData(config->args_[0].filename_, &chunk);
+ if (!ok) goto Err2;
+ err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1);
+ WebPDataClear(&chunk);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
+ ErrorString(err), kDescriptions[config->type_], Err2);
+ }
+ break;
+ }
+ case FEATURE_LOOP: {
+ WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
+ int parse_error = 0;
+ const int loop_count =
+ ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
+ if (loop_count < 0 || loop_count > 65535 || parse_error) {
+ ERROR_GOTO1("ERROR: Loop count must be in the range 0 to 65535.\n",
+ Err2);
+ }
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK);
+ if (!ok) {
+ ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n",
+ Err2);
+ }
+ params.loop_count = loop_count;
+ err = WebPMuxSetAnimationParams(mux, ¶ms);
+ ok = (err == WEBP_MUX_OK);
+ if (!ok) {
+ ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
+ ErrorString(err), Err2);
+ }
+ break;
+ }
+ case FEATURE_BGCOLOR: {
+ WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
+ uint32_t bgcolor;
+ ok = ParseBgcolorArgs(config->args_[0].params_, &bgcolor);
+ if (!ok) {
+ ERROR_GOTO1("ERROR: Could not parse the background color.\n",
+ Err2);
+ }
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK);
+ if (!ok) {
+ ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n",
+ Err2);
+ }
+ params.bgcolor = bgcolor;
+ err = WebPMuxSetAnimationParams(mux, ¶ms);
+ ok = (err == WEBP_MUX_OK);
+ if (!ok) {
+ ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
+ ErrorString(err), Err2);
+ }
+ break;
+ }
+ default: {
+ ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2);
+ break;
+ }
+ }
+ ok = WriteWebP(mux, config->output_);
+ break;
+ }
+ case ACTION_DURATION: {
+ int num_frames;
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames);
+ ok = (err == WEBP_MUX_OK);
+ if (!ok) {
+ ERROR_GOTO1("ERROR: can not parse the number of frames.\n", Err2);
+ }
+ if (num_frames == 0) {
+ fprintf(stderr, "Doesn't look like the source is animated. "
+ "Skipping duration setting.\n");
+ ok = WriteWebP(mux, config->output_);
+ if (!ok) goto Err2;
+ } else {
+ int i;
+ int* durations = NULL;
+ WebPMux* new_mux = DuplicateMuxHeader(mux);
+ if (new_mux == NULL) goto Err2;
+ durations = (int*)WebPMalloc((size_t)num_frames * sizeof(*durations));
+ if (durations == NULL) goto Err2;
+ for (i = 0; i < num_frames; ++i) durations[i] = -1;
+
+ // Parse intervals to process.
+ for (i = 0; i < config->arg_count_; ++i) {
+ int k;
+ int args[3];
+ int duration, start, end;
+ const int nb_args = ExUtilGetInts(config->args_[i].params_,
+ 10, 3, args);
+ ok = (nb_args >= 1);
+ if (!ok) goto Err3;
+ duration = args[0];
+ if (duration < 0) {
+ ERROR_GOTO1("ERROR: duration must be strictly positive.\n", Err3);
+ }
+
+ if (nb_args == 1) { // only duration is present -> use full interval
+ start = 1;
+ end = num_frames;
+ } else {
+ start = args[1];
+ if (start <= 0) {
+ start = 1;
+ } else if (start > num_frames) {
+ start = num_frames;
+ }
+ end = (nb_args >= 3) ? args[2] : start;
+ if (end == 0 || end > num_frames) end = num_frames;
+ }
+
+ for (k = start; k <= end; ++k) {
+ assert(k >= 1 && k <= num_frames);
+ durations[k - 1] = duration;
+ }
+ }
+
+ // Apply non-negative durations to their destination frames.
+ for (i = 1; i <= num_frames; ++i) {
+ WebPMuxFrameInfo frame;
+ err = WebPMuxGetFrame(mux, i, &frame);
+ if (err != WEBP_MUX_OK || frame.id != WEBP_CHUNK_ANMF) {
+ ERROR_GOTO2("ERROR: can not retrieve frame #%d.\n", i, Err3);
+ }
+ if (durations[i - 1] >= 0) frame.duration = durations[i - 1];
+ err = WebPMuxPushFrame(new_mux, &frame, 1);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO2("ERROR: error push frame data #%d\n", i, Err3);
+ }
+ WebPDataClear(&frame.bitstream);
+ }
+ WebPMuxDelete(mux);
+ ok = WriteWebP(new_mux, config->output_);
+ mux = new_mux; // transfer for the WebPMuxDelete() call
+ new_mux = NULL;
+
+ Err3:
+ WebPFree(durations);
+ WebPMuxDelete(new_mux);
+ if (!ok) goto Err2;
+ }
+ break;
+ }
+ case ACTION_STRIP: {
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF ||
+ config->type_ == FEATURE_XMP) {
+ err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]);
+ if (err != WEBP_MUX_OK) {
+ ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
+ ErrorString(err), kDescriptions[config->type_], Err2);
+ }
+ } else {
+ ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
+ break;
+ }
+ ok = WriteWebP(mux, config->output_);
+ break;
+ }
+ case ACTION_INFO: {
+ ok = CreateMux(config->input_, &mux);
+ if (!ok) goto Err2;
+ ok = (DisplayInfo(mux) == WEBP_MUX_OK);
+ break;
+ }
+ default: {
+ assert(0); // Invalid action.
+ break;
+ }
+ }
+
+ Err2:
+ WebPMuxDelete(mux);
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+// Main.
+
+int main(int argc, const char* argv[]) {
+ Config config;
+ int ok;
+
+ INIT_WARGV(argc, argv);
+
+ ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL());
+ if (ok) {
+ ok = Process(&config);
+ } else {
+ PrintHelp();
+ }
+ DeleteConfig(&config);
+ FREE_WARGV_AND_RETURN(!ok);
+}
+
+//------------------------------------------------------------------------------
diff --git a/extras/Makefile.am b/extras/Makefile.am
new file mode 100644
index 0000000..7e29888
--- /dev/null
+++ b/extras/Makefile.am
@@ -0,0 +1,44 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
+noinst_LTLIBRARIES = libwebpextras.la
+
+noinst_HEADERS =
+noinst_HEADERS += ../src/webp/types.h
+
+libwebpextras_la_SOURCES =
+libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
+
+libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
+libwebpextras_la_LDFLAGS = -lm
+libwebpextras_la_LIBADD = ../src/libwebp.la
+
+noinst_PROGRAMS =
+noinst_PROGRAMS += webp_quality
+if BUILD_DEMUX
+ noinst_PROGRAMS += get_disto
+endif
+if BUILD_VWEBP_SDL
+ noinst_PROGRAMS += vwebp_sdl
+endif
+
+get_disto_SOURCES = get_disto.c
+get_disto_CPPFLAGS = $(AM_CPPFLAGS)
+get_disto_LDADD =
+get_disto_LDADD += ../imageio/libimageio_util.la
+get_disto_LDADD += ../imageio/libimagedec.la
+get_disto_LDADD += ../src/libwebp.la
+get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
+
+webp_quality_SOURCES = webp_quality.c
+webp_quality_CPPFLAGS = $(AM_CPPFLAGS)
+webp_quality_LDADD =
+webp_quality_LDADD += ../imageio/libimageio_util.la
+webp_quality_LDADD += libwebpextras.la
+webp_quality_LDADD += ../src/libwebp.la
+
+vwebp_sdl_SOURCES = vwebp_sdl.c webp_to_sdl.c webp_to_sdl.h
+vwebp_sdl_CPPFLAGS = $(AM_CPPFLAGS) $(SDL_INCLUDES)
+vwebp_sdl_LDADD =
+vwebp_sdl_LDADD += ../imageio/libimageio_util.la
+vwebp_sdl_LDADD += ../src/libwebp.la
+vwebp_sdl_LDADD += $(SDL_LIBS)
diff --git a/extras/extras.c b/extras/extras.c
new file mode 100644
index 0000000..b170ee2
--- /dev/null
+++ b/extras/extras.c
@@ -0,0 +1,162 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Additional WebP utilities.
+//
+
+#include "extras/extras.h"
+#include "webp/format_constants.h"
+#include "src/dsp/dsp.h"
+
+#include <assert.h>
+#include <string.h>
+
+#define XTRA_MAJ_VERSION 1
+#define XTRA_MIN_VERSION 3
+#define XTRA_REV_VERSION 0
+
+//------------------------------------------------------------------------------
+
+int WebPGetExtrasVersion(void) {
+ return (XTRA_MAJ_VERSION << 16) | (XTRA_MIN_VERSION << 8) | XTRA_REV_VERSION;
+}
+
+//------------------------------------------------------------------------------
+
+int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) {
+ int y, width, uv_width;
+ if (pic == NULL || gray_data == NULL) return 0;
+ pic->colorspace = WEBP_YUV420;
+ if (!WebPPictureAlloc(pic)) return 0;
+ width = pic->width;
+ uv_width = (width + 1) >> 1;
+ for (y = 0; y < pic->height; ++y) {
+ memcpy(pic->y + y * pic->y_stride, gray_data, width);
+ gray_data += width; // <- we could use some 'data_stride' here if needed
+ if ((y & 1) == 0) {
+ memset(pic->u + (y >> 1) * pic->uv_stride, 128, uv_width);
+ memset(pic->v + (y >> 1) * pic->uv_stride, 128, uv_width);
+ }
+ }
+ return 1;
+}
+
+int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
+ int x, y;
+ uint32_t* dst;
+ if (pic == NULL || rgb565 == NULL) return 0;
+ pic->colorspace = WEBP_YUV420;
+ pic->use_argb = 1;
+ if (!WebPPictureAlloc(pic)) return 0;
+ dst = pic->argb;
+ for (y = 0; y < pic->height; ++y) {
+ const int width = pic->width;
+ for (x = 0; x < width; ++x) {
+#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1)
+ const uint32_t rg = rgb565[2 * x + 1];
+ const uint32_t gb = rgb565[2 * x + 0];
+#else
+ const uint32_t rg = rgb565[2 * x + 0];
+ const uint32_t gb = rgb565[2 * x + 1];
+#endif
+ uint32_t r = rg & 0xf8;
+ uint32_t g = ((rg << 5) | (gb >> 3)) & 0xfc;
+ uint32_t b = (gb << 5);
+ // dithering
+ r = r | (r >> 5);
+ g = g | (g >> 6);
+ b = b | (b >> 5);
+ dst[x] = (0xffu << 24) | (r << 16) | (g << 8) | b;
+ }
+ rgb565 += 2 * width;
+ dst += pic->argb_stride;
+ }
+ return 1;
+}
+
+int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
+ int x, y;
+ uint32_t* dst;
+ if (pic == NULL || rgb4444 == NULL) return 0;
+ pic->colorspace = WEBP_YUV420;
+ pic->use_argb = 1;
+ if (!WebPPictureAlloc(pic)) return 0;
+ dst = pic->argb;
+ for (y = 0; y < pic->height; ++y) {
+ const int width = pic->width;
+ for (x = 0; x < width; ++x) {
+#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1)
+ const uint32_t rg = rgb4444[2 * x + 1];
+ const uint32_t ba = rgb4444[2 * x + 0];
+#else
+ const uint32_t rg = rgb4444[2 * x + 0];
+ const uint32_t ba = rgb4444[2 * x + 1];
+#endif
+ uint32_t r = rg & 0xf0;
+ uint32_t g = (rg << 4);
+ uint32_t b = (ba & 0xf0);
+ uint32_t a = (ba << 4);
+ // dithering
+ r = r | (r >> 4);
+ g = g | (g >> 4);
+ b = b | (b >> 4);
+ a = a | (a >> 4);
+ dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+ rgb4444 += 2 * width;
+ dst += pic->argb_stride;
+ }
+ return 1;
+}
+
+int WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
+ const uint32_t palette[], int palette_size,
+ WebPPicture* pic) {
+ int x, y;
+ uint32_t* dst;
+ // 256 as the input buffer is uint8_t.
+ assert(MAX_PALETTE_SIZE <= 256);
+ if (pic == NULL || indexed == NULL || indexed_stride < pic->width ||
+ palette == NULL || palette_size > MAX_PALETTE_SIZE || palette_size <= 0) {
+ return 0;
+ }
+ pic->use_argb = 1;
+ if (!WebPPictureAlloc(pic)) return 0;
+ dst = pic->argb;
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) {
+ // Make sure we are within the palette.
+ if (indexed[x] >= palette_size) {
+ WebPPictureFree(pic);
+ return 0;
+ }
+ dst[x] = palette[indexed[x]];
+ }
+ indexed += indexed_stride;
+ dst += pic->argb_stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+int WebPUnmultiplyARGB(WebPPicture* pic) {
+ int y;
+ uint32_t* dst;
+ if (pic == NULL || pic->use_argb != 1 || pic->argb == NULL) return 0;
+ WebPInitAlphaProcessing();
+ dst = pic->argb;
+ for (y = 0; y < pic->height; ++y) {
+ WebPMultARGBRow(dst, pic->width, /*inverse=*/1);
+ dst += pic->argb_stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
diff --git a/extras/extras.h b/extras/extras.h
new file mode 100644
index 0000000..c084682
--- /dev/null
+++ b/extras/extras.h
@@ -0,0 +1,77 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+
+#ifndef WEBP_EXTRAS_EXTRAS_H_
+#define WEBP_EXTRAS_EXTRAS_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "webp/encode.h"
+
+#define WEBP_EXTRAS_ABI_VERSION 0x0002 // MAJOR(8b) + MINOR(8b)
+
+//------------------------------------------------------------------------------
+
+// Returns the version number of the extras library, packed in hexadecimal using
+// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN int WebPGetExtrasVersion(void);
+
+//------------------------------------------------------------------------------
+// Ad-hoc colorspace importers.
+
+// Import luma sample (gray scale image) into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN int WebPImportGray(const uint8_t* gray, WebPPicture* picture);
+
+// Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
+
+// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
+
+// Import a color mapped image. The number of colors is less or equal to
+// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any,
+// will be discarded. Returns 'false' in case of error, or if indexed[] contains
+// invalid indices.
+WEBP_EXTERN int
+WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
+ const uint32_t palette[], int palette_size,
+ WebPPicture* pic);
+
+// Convert the ARGB content of 'pic' from associated to unassociated.
+// 'pic' can be for instance the result of calling of some WebPPictureImportXXX
+// functions, with pic->use_argb set to 'true'. It is assumed (and not checked)
+// that the pre-multiplied r/g/b values as less or equal than the alpha value.
+// Return false in case of error (invalid parameter, ...).
+WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic);
+
+//------------------------------------------------------------------------------
+
+// Parse a bitstream, search for VP8 (lossy) header and report a
+// rough estimation of the quality factor used for compressing the bitstream.
+// If the bitstream is in lossless format, the special value '101' is returned.
+// Otherwise (lossy bitstream), the returned value is in the range [0..100].
+// Any error (invalid bitstream, animated WebP, incomplete header, etc.)
+// will return a value of -1.
+WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
+
+//------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_EXTRAS_EXTRAS_H_
diff --git a/extras/get_disto.c b/extras/get_disto.c
new file mode 100644
index 0000000..3aa345b
--- /dev/null
+++ b/extras/get_disto.c
@@ -0,0 +1,356 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Simple tool to load two webp/png/jpg/tiff files and compute PSNR/SSIM.
+// This is mostly a wrapper around WebPPictureDistortion().
+//
+/*
+ gcc -o get_disto get_disto.c -O3 -I../ -L../examples -L../imageio \
+ -lexample_util -limageio_util -limagedec -lwebp -L/opt/local/lib \
+ -lpng -lz -ljpeg -ltiff -lm -lpthread
+*/
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "webp/encode.h"
+#include "imageio/image_dec.h"
+#include "imageio/imageio_util.h"
+#include "../examples/unicode.h"
+
+static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
+ int keep_alpha) {
+ const uint8_t* data = NULL;
+ size_t data_size = 0;
+ WebPImageReader reader = NULL;
+ int ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ if (!ok) goto End;
+
+ pic->use_argb = 1; // force ARGB
+
+#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, keep_alpha, NULL);
+ if (ok) goto End;
+#endif
+ reader = WebPGuessImageReader(data, data_size);
+ ok = reader(data, data_size, pic, keep_alpha, NULL);
+
+ End:
+ if (!ok) {
+ WFPRINTF(stderr, "Error! Could not process file %s\n",
+ (const W_CHAR*)filename);
+ }
+ free((void*)data);
+ return ok ? data_size : 0;
+}
+
+static void RescalePlane(uint8_t* plane, int width, int height,
+ int x_stride, int y_stride, int max) {
+ const uint32_t factor = (max > 0) ? (255u << 16) / max : 0;
+ int x, y;
+ for (y = 0; y < height; ++y) {
+ uint8_t* const ptr = plane + y * y_stride;
+ for (x = 0; x < width * x_stride; x += x_stride) {
+ const uint32_t diff = (ptr[x] * factor + (1 << 15)) >> 16;
+ ptr[x] = diff;
+ }
+ }
+}
+
+// Return the max absolute difference.
+static int DiffScaleChannel(uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int x_stride, int w, int h, int do_scaling) {
+ int x, y;
+ int max = 0;
+ for (y = 0; y < h; ++y) {
+ uint8_t* const ptr1 = src1 + y * stride1;
+ const uint8_t* const ptr2 = src2 + y * stride2;
+ for (x = 0; x < w * x_stride; x += x_stride) {
+ const int diff = abs(ptr1[x] - ptr2[x]);
+ if (diff > max) max = diff;
+ ptr1[x] = diff;
+ }
+ }
+
+ if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
+ return max;
+}
+
+//------------------------------------------------------------------------------
+// SSIM calculation. We re-implement these functions here, out of dsp/, to avoid
+// breaking the library's hidden visibility. This code duplication avoids the
+// bigger annoyance of having to open up internal details of libdsp...
+
+#define SSIM_KERNEL 3 // total size of the kernel: 2 * SSIM_KERNEL + 1
+
+// struct for accumulating statistical moments
+typedef struct {
+ uint32_t w; // sum(w_i) : sum of weights
+ uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i)
+ uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc.
+} DistoStats;
+
+// hat-shaped filter. Sum of coefficients is equal to 16.
+static const uint32_t kWeight[2 * SSIM_KERNEL + 1] = { 1, 2, 3, 4, 3, 2, 1 };
+
+static WEBP_INLINE double SSIMCalculation(const DistoStats* const stats) {
+ const uint32_t N = stats->w;
+ const uint32_t w2 = N * N;
+ const uint32_t C1 = 20 * w2;
+ const uint32_t C2 = 60 * w2;
+ const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6
+ const uint64_t xmxm = (uint64_t)stats->xm * stats->xm;
+ const uint64_t ymym = (uint64_t)stats->ym * stats->ym;
+ if (xmxm + ymym >= C3) {
+ const int64_t xmym = (int64_t)stats->xm * stats->ym;
+ const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative
+ const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm;
+ const uint64_t syy = (uint64_t)stats->yym * N - ymym;
+ // we descale by 8 to prevent overflow during the fnum/fden multiply.
+ const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8;
+ const uint64_t den_S = (sxx + syy + C2) >> 8;
+ const uint64_t fnum = (2 * xmym + C1) * num_S;
+ const uint64_t fden = (xmxm + ymym + C1) * den_S;
+ const double r = (double)fnum / fden;
+ assert(r >= 0. && r <= 1.0);
+ return r;
+ }
+ return 1.; // area is too dark to contribute meaningfully
+}
+
+static double SSIMGetClipped(const uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int xo, int yo, int W, int H) {
+ DistoStats stats = { 0, 0, 0, 0, 0, 0 };
+ const int ymin = (yo - SSIM_KERNEL < 0) ? 0 : yo - SSIM_KERNEL;
+ const int ymax = (yo + SSIM_KERNEL > H - 1) ? H - 1 : yo + SSIM_KERNEL;
+ const int xmin = (xo - SSIM_KERNEL < 0) ? 0 : xo - SSIM_KERNEL;
+ const int xmax = (xo + SSIM_KERNEL > W - 1) ? W - 1 : xo + SSIM_KERNEL;
+ int x, y;
+ src1 += ymin * stride1;
+ src2 += ymin * stride2;
+ for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) {
+ for (x = xmin; x <= xmax; ++x) {
+ const uint32_t w = kWeight[SSIM_KERNEL + x - xo]
+ * kWeight[SSIM_KERNEL + y - yo];
+ const uint32_t s1 = src1[x];
+ const uint32_t s2 = src2[x];
+ stats.w += w;
+ stats.xm += w * s1;
+ stats.ym += w * s2;
+ stats.xxm += w * s1 * s1;
+ stats.xym += w * s1 * s2;
+ stats.yym += w * s2 * s2;
+ }
+ }
+ return SSIMCalculation(&stats);
+}
+
+// Compute SSIM-score map. Return -1 in case of error, max diff otherwise.
+static int SSIMScaleChannel(uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int x_stride, int w, int h, int do_scaling) {
+ int x, y;
+ int max = 0;
+ uint8_t* const plane1 = (uint8_t*)malloc(2 * w * h * sizeof(*plane1));
+ uint8_t* const plane2 = plane1 + w * h;
+ if (plane1 == NULL) return -1;
+
+ // extract plane
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ plane1[x + y * w] = src1[x * x_stride + y * stride1];
+ plane2[x + y * w] = src2[x * x_stride + y * stride2];
+ }
+ }
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ const double ssim = SSIMGetClipped(plane1, w, plane2, w, x, y, w, h);
+ int diff = (int)(255 * (1. - ssim));
+ if (diff < 0) {
+ diff = 0;
+ } else if (diff > max) {
+ max = diff;
+ }
+ src1[x * x_stride + y * stride1] = (diff > 255) ? 255u : (uint8_t)diff;
+ }
+ }
+ free(plane1);
+
+ if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
+ return max;
+}
+
+// Convert an argb picture to luminance.
+static void ConvertToGray(WebPPicture* const pic) {
+ int x, y;
+ assert(pic != NULL);
+ assert(pic->use_argb);
+ for (y = 0; y < pic->height; ++y) {
+ uint32_t* const row = &pic->argb[y * pic->argb_stride];
+ for (x = 0; x < pic->width; ++x) {
+ const uint32_t argb = row[x];
+ const uint32_t r = (argb >> 16) & 0xff;
+ const uint32_t g = (argb >> 8) & 0xff;
+ const uint32_t b = (argb >> 0) & 0xff;
+ // We use BT.709 for converting to luminance.
+ const uint32_t Y = (uint32_t)(0.2126 * r + 0.7152 * g + 0.0722 * b + .5);
+ row[x] = (argb & 0xff000000u) | (Y * 0x010101u);
+ }
+ }
+}
+
+static void Help(void) {
+ fprintf(stderr,
+ "Usage: get_disto [-ssim][-psnr][-alpha] compressed.webp orig.webp\n"
+ " -ssim ..... print SSIM distortion\n"
+ " -psnr ..... print PSNR distortion (default)\n"
+ " -alpha .... preserve alpha plane\n"
+ " -h ........ this message\n"
+ " -o <file> . save the diff map as a WebP lossless file\n"
+ " -scale .... scale the difference map to fit [0..255] range\n"
+ " -gray ..... use grayscale for difference map (-scale)\n"
+ "\nSupported input formats:\n %s\n",
+ WebPGetEnabledInputFileFormats());
+}
+
+int main(int argc, const char* argv[]) {
+ WebPPicture pic1, pic2;
+ size_t size1 = 0, size2 = 0;
+ int ret = 1;
+ float disto[5];
+ int type = 0;
+ int c;
+ int help = 0;
+ int keep_alpha = 0;
+ int scale = 0;
+ int use_gray = 0;
+ const char* name1 = NULL;
+ const char* name2 = NULL;
+ const char* output = NULL;
+
+ INIT_WARGV(argc, argv);
+
+ if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
+ fprintf(stderr, "Can't init pictures\n");
+ FREE_WARGV_AND_RETURN(1);
+ }
+
+ for (c = 1; c < argc; ++c) {
+ if (!strcmp(argv[c], "-ssim")) {
+ type = 1;
+ } else if (!strcmp(argv[c], "-psnr")) {
+ type = 0;
+ } else if (!strcmp(argv[c], "-alpha")) {
+ keep_alpha = 1;
+ } else if (!strcmp(argv[c], "-scale")) {
+ scale = 1;
+ } else if (!strcmp(argv[c], "-gray")) {
+ use_gray = 1;
+ } else if (!strcmp(argv[c], "-h")) {
+ help = 1;
+ ret = 0;
+ } else if (!strcmp(argv[c], "-o")) {
+ if (++c == argc) {
+ fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
+ goto End;
+ }
+ output = (const char*)GET_WARGV(argv, c);
+ } else if (name1 == NULL) {
+ name1 = (const char*)GET_WARGV(argv, c);
+ } else {
+ name2 = (const char*)GET_WARGV(argv, c);
+ }
+ }
+ if (help || name1 == NULL || name2 == NULL) {
+ if (!help) {
+ fprintf(stderr, "Error: missing arguments.\n");
+ }
+ Help();
+ goto End;
+ }
+ size1 = ReadPicture(name1, &pic1, 1);
+ size2 = ReadPicture(name2, &pic2, 1);
+ if (size1 == 0 || size2 == 0) goto End;
+
+ if (!keep_alpha) {
+ WebPBlendAlpha(&pic1, 0x00000000);
+ WebPBlendAlpha(&pic2, 0x00000000);
+ }
+
+ if (!WebPPictureDistortion(&pic1, &pic2, type, disto)) {
+ fprintf(stderr, "Error while computing the distortion.\n");
+ goto End;
+ }
+ printf("%u %.2f %.2f %.2f %.2f %.2f [ %.2f bpp ]\n",
+ (unsigned int)size1,
+ disto[4], disto[0], disto[1], disto[2], disto[3],
+ 8.f * size1 / pic1.width / pic1.height);
+
+ if (output != NULL) {
+ uint8_t* data = NULL;
+ size_t data_size = 0;
+ if (pic1.use_argb != pic2.use_argb) {
+ fprintf(stderr, "Pictures are not in the same argb format. "
+ "Can't save the difference map.\n");
+ goto End;
+ }
+ if (pic1.use_argb) {
+ int n;
+ fprintf(stderr, "max differences per channel: ");
+ for (n = 0; n < 3; ++n) { // skip the alpha channel
+ const int range = (type == 1) ?
+ SSIMScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
+ (const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
+ 4, pic1.width, pic1.height, scale) :
+ DiffScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
+ (const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
+ 4, pic1.width, pic1.height, scale);
+ if (range < 0) fprintf(stderr, "\nError computing diff map\n");
+ fprintf(stderr, "[%d]", range);
+ }
+ fprintf(stderr, "\n");
+ if (use_gray) ConvertToGray(&pic1);
+ } else {
+ fprintf(stderr, "Can only compute the difference map in ARGB format.\n");
+ goto End;
+ }
+#if !defined(WEBP_REDUCE_CSP)
+ data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb,
+ pic1.width, pic1.height,
+ pic1.argb_stride * 4,
+ &data);
+ if (data_size == 0) {
+ fprintf(stderr, "Error during lossless encoding.\n");
+ goto End;
+ }
+ ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
+ WebPFree(data);
+ if (ret) goto End;
+#else
+ (void)data;
+ (void)data_size;
+ fprintf(stderr, "Cannot save the difference map. Please recompile "
+ "without the WEBP_REDUCE_CSP flag.\n");
+#endif // WEBP_REDUCE_CSP
+ }
+ ret = 0;
+
+ End:
+ WebPPictureFree(&pic1);
+ WebPPictureFree(&pic2);
+ FREE_WARGV_AND_RETURN(ret);
+}
diff --git a/extras/quality_estimate.c b/extras/quality_estimate.c
new file mode 100644
index 0000000..17e98d9
--- /dev/null
+++ b/extras/quality_estimate.c
@@ -0,0 +1,129 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// VP8EstimateQuality(): rough encoding quality estimate
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "extras/extras.h"
+#include "webp/decode.h"
+
+#include <math.h>
+
+//------------------------------------------------------------------------------
+
+#define INVALID_BIT_POS (1ull << 63)
+
+// In most cases, we don't need to use a full arithmetic decoder, since
+// all the header's bits are written using a uniform probability of 128.
+// We can just parse the header as if it was bits (works in 99.999% cases).
+static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb,
+ uint64_t max_size, uint64_t* const bit_pos) {
+ uint32_t val = 0;
+ if (*bit_pos + nb <= 8 * max_size) {
+ while (nb-- > 0) {
+ const uint64_t p = (*bit_pos)++;
+ const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
+ val = (val << 1) | bit;
+ }
+ } else {
+ *bit_pos = INVALID_BIT_POS;
+ }
+ return val;
+}
+
+#define GET_BIT(n) GetBit(data, (n), size, &bit_pos)
+#define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0)
+
+int VP8EstimateQuality(const uint8_t* const data, size_t size) {
+ size_t pos = 0;
+ uint64_t bit_pos;
+ uint64_t sig = 0x00;
+ int ok = 0;
+ int Q = -1;
+ WebPBitstreamFeatures features;
+
+ if (data == NULL) return -1;
+
+ if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) {
+ return -1; // invalid file
+ }
+ if (features.format == 2) return 101; // lossless
+ if (features.format == 0 || features.has_animation) return -1; // mixed
+
+ while (pos < size) {
+ sig = (sig >> 8) | ((uint64_t)data[pos++] << 40);
+ if ((sig >> 24) == 0x2a019dull) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) return -1;
+ if (pos + 4 > size) return -1;
+
+ // Skip main Header
+ // width = (data[pos + 0] | (data[pos + 1] << 8)) & 0x3fff;
+ // height = (data[pos + 2] | (data[pos + 3] << 8)) & 0x3fff;
+ pos += 4;
+ bit_pos = pos * 8;
+
+ GET_BIT(2); // colorspace + clamp type
+
+ // Segment header
+ if (GET_BIT(1)) { // use_segment_
+ int s;
+ const int update_map = GET_BIT(1);
+ if (GET_BIT(1)) { // update data
+ const int absolute_delta = GET_BIT(1);
+ int q[4] = { 0, 0, 0, 0 };
+ for (s = 0; s < 4; ++s) {
+ if (GET_BIT(1)) {
+ q[s] = GET_BIT(7);
+ if (GET_BIT(1)) q[s] = -q[s]; // sign
+ }
+ }
+ if (absolute_delta) Q = q[0]; // just use the first segment's quantizer
+ for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7); // filter strength
+ }
+ if (update_map) {
+ for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8);
+ }
+ }
+ // Filter header
+ GET_BIT(1 + 6 + 3); // simple + level + sharpness
+ if (GET_BIT(1)) { // use_lf_delta
+ if (GET_BIT(1)) { // update lf_delta?
+ int n;
+ for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6);
+ }
+ }
+ // num partitions
+ GET_BIT(2);
+
+ // ParseQuant
+ {
+ const int base_q = GET_BIT(7);
+ /* dqy1_dc = */ CONDITIONAL_SKIP(5);
+ /* dqy2_dc = */ CONDITIONAL_SKIP(5);
+ /* dqy2_ac = */ CONDITIONAL_SKIP(5);
+ /* dquv_dc = */ CONDITIONAL_SKIP(5);
+ /* dquv_ac = */ CONDITIONAL_SKIP(5);
+
+ if (Q < 0) Q = base_q;
+ }
+ if (bit_pos == INVALID_BIT_POS) return -1;
+
+ // base mapping
+ Q = (127 - Q) * 100 / 127;
+ // correction for power-law behavior in low range
+ if (Q < 80) {
+ Q = (int)(pow(Q / 80., 1. / 0.38) * 80);
+ }
+ return Q;
+}
diff --git a/extras/vwebp_sdl.c b/extras/vwebp_sdl.c
new file mode 100644
index 0000000..e9554eb
--- /dev/null
+++ b/extras/vwebp_sdl.c
@@ -0,0 +1,101 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Simple SDL-based WebP file viewer.
+// Does not support animation, just static images.
+//
+// Press 'q' to exit.
+//
+// Author: James Zern (jzern@google.com)
+
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#if defined(WEBP_HAVE_SDL)
+
+#include "webp_to_sdl.h"
+#include "webp/decode.h"
+#include "imageio/imageio_util.h"
+#include "../examples/unicode.h"
+
+#if defined(WEBP_HAVE_JUST_SDL_H)
+#include <SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+
+static void ProcessEvents(void) {
+ int done = 0;
+ SDL_Event event;
+ while (!done && SDL_WaitEvent(&event)) {
+ switch (event.type) {
+ case SDL_KEYUP:
+ switch (event.key.keysym.sym) {
+ case SDLK_q: done = 1; break;
+ default: break;
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+int main(int argc, char* argv[]) {
+ int c;
+ int ok = 0;
+
+ INIT_WARGV(argc, argv);
+
+ for (c = 1; c < argc; ++c) {
+ const char* file = NULL;
+ const uint8_t* webp = NULL;
+ size_t webp_size = 0;
+ if (!strcmp(argv[c], "-h")) {
+ printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]);
+ FREE_WARGV_AND_RETURN(0);
+ } else {
+ file = (const char*)GET_WARGV(argv, c);
+ }
+ if (file == NULL) continue;
+ if (!ImgIoUtilReadFile(file, &webp, &webp_size)) {
+ WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file);
+ goto Error;
+ }
+ if (webp_size != (size_t)(int)webp_size) {
+ free((void*)webp);
+ fprintf(stderr, "File too large.\n");
+ goto Error;
+ }
+ ok = WebPToSDL((const char*)webp, (int)webp_size);
+ free((void*)webp);
+ if (!ok) {
+ WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file);
+ goto Error;
+ }
+ ProcessEvents();
+ }
+ ok = 1;
+
+ Error:
+ SDL_Quit();
+ FREE_WARGV_AND_RETURN(ok ? 0 : 1);
+}
+
+#else // !WEBP_HAVE_SDL
+
+int main(int argc, const char* argv[]) {
+ fprintf(stderr, "SDL support not enabled in %s.\n", argv[0]);
+ (void)argc;
+ return 0;
+}
+
+#endif
diff --git a/extras/webp_quality.c b/extras/webp_quality.c
new file mode 100644
index 0000000..0a3b25f
--- /dev/null
+++ b/extras/webp_quality.c
@@ -0,0 +1,54 @@
+// Simple tool to roughly evaluate the quality encoding of a webp bitstream
+//
+// Result is a *rough* estimation of the quality. You should just consider
+// the bucket it's in (q > 80? > 50? > 20?) and not take it for face value.
+/*
+ gcc -o webp_quality webp_quality.c -O3 -I../ -L. -L../imageio \
+ -limageio_util -lwebpextras -lwebp -lm -lpthread
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extras/extras.h"
+#include "imageio/imageio_util.h"
+#include "../examples/unicode.h"
+
+int main(int argc, const char* argv[]) {
+ int c;
+ int quiet = 0;
+ int ok = 1;
+
+ INIT_WARGV(argc, argv);
+
+ for (c = 1; ok && c < argc; ++c) {
+ if (!strcmp(argv[c], "-quiet")) {
+ quiet = 1;
+ } else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
+ printf("webp_quality [-h][-quiet] webp_files...\n");
+ FREE_WARGV_AND_RETURN(0);
+ } else {
+ const char* const filename = (const char*)GET_WARGV(argv, c);
+ const uint8_t* data = NULL;
+ size_t data_size = 0;
+ int q;
+ ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ if (!ok) break;
+ q = VP8EstimateQuality(data, data_size);
+ if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename);
+ if (q < 0) {
+ fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
+ ok = 0;
+ } else {
+ if (!quiet) {
+ printf("Estimated quality factor: %d\n", q);
+ } else {
+ printf("%d\n", q); // just print the number
+ }
+ }
+ free((void*)data);
+ }
+ }
+ FREE_WARGV_AND_RETURN(ok ? 0 : 1);
+}
diff --git a/extras/webp_to_sdl.c b/extras/webp_to_sdl.c
new file mode 100644
index 0000000..1e52681
--- /dev/null
+++ b/extras/webp_to_sdl.c
@@ -0,0 +1,110 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Simple WebP-to-SDL wrapper. Useful for emscripten.
+//
+// Author: James Zern (jzern@google.com)
+
+#ifdef HAVE_CONFIG_H
+#include "src/webp/config.h"
+#endif
+
+#if defined(WEBP_HAVE_SDL)
+
+#include "webp_to_sdl.h"
+
+#include <stdio.h>
+#include "src/webp/decode.h"
+
+#if defined(WEBP_HAVE_JUST_SDL_H)
+#include <SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+
+static int init_ok = 0;
+int WebPToSDL(const char* data, unsigned int data_size) {
+ int ok = 0;
+ VP8StatusCode status;
+ WebPDecoderConfig config;
+ WebPBitstreamFeatures* const input = &config.input;
+ WebPDecBuffer* const output = &config.output;
+ SDL_Surface* screen = NULL;
+ SDL_Surface* surface = NULL;
+
+ if (!WebPInitDecoderConfig(&config)) {
+ fprintf(stderr, "Library version mismatch!\n");
+ return 0;
+ }
+
+ if (!init_ok) {
+ SDL_Init(SDL_INIT_VIDEO);
+ init_ok = 1;
+ }
+
+ status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
+ if (status != VP8_STATUS_OK) goto Error;
+
+ screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
+ if (screen == NULL) {
+ fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
+ input->width, input->height);
+ goto Error;
+ }
+
+ surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ input->width, input->height, 32,
+ 0x000000ffu, // R mask
+ 0x0000ff00u, // G mask
+ 0x00ff0000u, // B mask
+ 0xff000000u); // A mask
+
+ if (surface == NULL) {
+ fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
+ input->width, input->height);
+ goto Error;
+ }
+ if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ output->colorspace = MODE_BGRA;
+#else
+ output->colorspace = MODE_RGBA;
+#endif
+ output->width = surface->w;
+ output->height = surface->h;
+ output->u.RGBA.rgba = surface->pixels;
+ output->u.RGBA.stride = surface->pitch;
+ output->u.RGBA.size = surface->pitch * surface->h;
+ output->is_external_memory = 1;
+
+ status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config);
+ if (status != VP8_STATUS_OK) {
+ fprintf(stderr, "Error decoding image (%d)\n", status);
+ goto Error;
+ }
+
+ if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
+ if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
+ SDL_Flip(screen)) {
+ goto Error;
+ }
+
+ ok = 1;
+
+ Error:
+ SDL_FreeSurface(surface);
+ SDL_FreeSurface(screen);
+ WebPFreeDecBuffer(output);
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+
+#endif // WEBP_HAVE_SDL
diff --git a/extras/webp_to_sdl.h b/extras/webp_to_sdl.h
new file mode 100644
index 0000000..1534f2b
--- /dev/null
+++ b/extras/webp_to_sdl.h
@@ -0,0 +1,22 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Simple WebP-to-SDL wrapper. Useful for emscripten.
+//
+// Author: James Zern (jzern@google.com)
+
+#ifndef WEBP_EXTRAS_WEBP_TO_SDL_H_
+#define WEBP_EXTRAS_WEBP_TO_SDL_H_
+
+// Exports the method WebPToSDL(const char* data, int data_size) which decodes
+// a WebP bitstream into an RGBA SDL surface.
+// Return false on failure.
+extern int WebPToSDL(const char* data, unsigned int data_size);
+
+#endif // WEBP_EXTRAS_WEBP_TO_SDL_H_
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..28d39f5
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,14 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Versions for gradle
+BUILD_TOOLS_VERSION=23.0.3
+COMPILE_SDK_VERSION=23
+ANDROID_GRADLE_PLUGIN_VERSION=1.5.0
+GRADLE_DOWNLOAD_TASK_VERSION=2.1.0
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f3d88b1
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1b16c34
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..2fe81a7
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..9618d8d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/imageio/Android.mk b/imageio/Android.mk
new file mode 100644
index 0000000..aa877ce
--- /dev/null
+++ b/imageio/Android.mk
@@ -0,0 +1,66 @@
+# Ignore this file during non-NDK builds.
+ifdef NDK_ROOT
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+# libimageio_util
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ imageio_util.c \
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
+
+LOCAL_MODULE := imageio_util
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+# libimagedec
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ image_dec.c \
+ jpegdec.c \
+ metadata.c \
+ pngdec.c \
+ pnmdec.c \
+ tiffdec.c \
+ webpdec.c \
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
+LOCAL_STATIC_LIBRARIES := imageio_util
+
+LOCAL_MODULE := imagedec
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+# libimageenc
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ image_enc.c \
+
+LOCAL_CFLAGS := $(WEBP_CFLAGS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
+LOCAL_STATIC_LIBRARIES := imageio_util
+
+LOCAL_MODULE := imageenc
+
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYING $(LOCAL_PATH)/../NOTICE $(LOCAL_PATH)/../PATENTS
+include $(BUILD_STATIC_LIBRARY)
+endif # NDK_ROOT
diff --git a/imageio/Makefile.am b/imageio/Makefile.am
new file mode 100644
index 0000000..500ec7e
--- /dev/null
+++ b/imageio/Makefile.am
@@ -0,0 +1,32 @@
+AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
+noinst_LTLIBRARIES =
+noinst_LTLIBRARIES += libimageio_util.la
+if BUILD_DEMUX
+ noinst_LTLIBRARIES += libimagedec.la
+endif
+noinst_LTLIBRARIES += libimageenc.la
+
+noinst_HEADERS =
+noinst_HEADERS += ../src/webp/decode.h
+noinst_HEADERS += ../src/webp/types.h
+
+libimageio_util_la_SOURCES =
+libimageio_util_la_SOURCES += imageio_util.c imageio_util.h
+
+libimagedec_la_SOURCES =
+libimagedec_la_SOURCES += image_dec.c image_dec.h
+libimagedec_la_SOURCES += jpegdec.c jpegdec.h
+libimagedec_la_SOURCES += metadata.c metadata.h
+libimagedec_la_SOURCES += pngdec.c pngdec.h
+libimagedec_la_SOURCES += pnmdec.c pnmdec.h
+libimagedec_la_SOURCES += tiffdec.c tiffdec.h
+libimagedec_la_SOURCES += webpdec.c webpdec.h
+libimagedec_la_SOURCES += wicdec.c wicdec.h
+libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
+libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS)
+libimagedec_la_LIBADD = ../src/demux/libwebpdemux.la
+
+libimageenc_la_SOURCES =
+libimageenc_la_SOURCES += image_enc.c image_enc.h
+libimageenc_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
+libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS)
diff --git a/imageio/image_dec.c b/imageio/image_dec.c
new file mode 100644
index 0000000..5e003fa
--- /dev/null
+++ b/imageio/image_dec.c
@@ -0,0 +1,84 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Generic image-type guessing.
+
+#include "./image_dec.h"
+
+const char* WebPGetEnabledInputFileFormats(void) {
+ return "WebP"
+#ifdef WEBP_HAVE_JPEG
+ ", JPEG"
+#endif
+#ifdef WEBP_HAVE_PNG
+ ", PNG"
+#endif
+ ", PNM (PGM, PPM, PAM)"
+#ifdef WEBP_HAVE_TIFF
+ ", TIFF"
+#endif
+#ifdef HAVE_WINCODEC_H
+ ", Windows Imaging Component (WIC)"
+#endif
+ "";
+}
+
+static WEBP_INLINE uint32_t GetBE32(const uint8_t buf[]) {
+ return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
+ size_t data_size) {
+ WebPInputFileFormat format = WEBP_UNSUPPORTED_FORMAT;
+ if (data != NULL && data_size >= 12) {
+ const uint32_t magic1 = GetBE32(data + 0);
+ const uint32_t magic2 = GetBE32(data + 8);
+ if (magic1 == 0x89504E47U) {
+ format = WEBP_PNG_FORMAT;
+ } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) {
+ format = WEBP_JPEG_FORMAT;
+ } else if (magic1 == 0x49492A00 || magic1 == 0x4D4D002A) {
+ format = WEBP_TIFF_FORMAT;
+ } else if (magic1 == 0x52494646 && magic2 == 0x57454250) {
+ format = WEBP_WEBP_FORMAT;
+ } else if (((magic1 >> 24) & 0xff) == 'P') {
+ const int type = (magic1 >> 16) & 0xff;
+ // we only support 'P5 -> P7' for now.
+ if (type >= '5' && type <= '7') format = WEBP_PNM_FORMAT;
+ }
+ }
+ return format;
+}
+
+static int FailReader(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata) {
+ (void)data;
+ (void)data_size;
+ (void)pic;
+ (void)keep_alpha;
+ (void)metadata;
+ return 0;
+}
+
+WebPImageReader WebPGetImageReader(WebPInputFileFormat format) {
+ switch (format) {
+ case WEBP_PNG_FORMAT: return ReadPNG;
+ case WEBP_JPEG_FORMAT: return ReadJPEG;
+ case WEBP_TIFF_FORMAT: return ReadTIFF;
+ case WEBP_WEBP_FORMAT: return ReadWebP;
+ case WEBP_PNM_FORMAT: return ReadPNM;
+ default: return FailReader;
+ }
+}
+
+WebPImageReader WebPGuessImageReader(const uint8_t* const data,
+ size_t data_size) {
+ return WebPGetImageReader(WebPGuessImageType(data, data_size));
+}
diff --git a/imageio/image_dec.h b/imageio/image_dec.h
new file mode 100644
index 0000000..f09f564
--- /dev/null
+++ b/imageio/image_dec.h
@@ -0,0 +1,70 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// All-in-one library to decode PNG/JPEG/WebP/TIFF/WIC input images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_
+#define WEBP_IMAGEIO_IMAGE_DEC_H_
+
+#include "webp/types.h"
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "./metadata.h"
+#include "./jpegdec.h"
+#include "./pngdec.h"
+#include "./pnmdec.h"
+#include "./tiffdec.h"
+#include "./webpdec.h"
+#include "./wicdec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ WEBP_PNG_FORMAT = 0,
+ WEBP_JPEG_FORMAT,
+ WEBP_TIFF_FORMAT,
+ WEBP_WEBP_FORMAT,
+ WEBP_PNM_FORMAT,
+ WEBP_UNSUPPORTED_FORMAT
+} WebPInputFileFormat;
+
+// Returns a comma separated list of enabled input formats.
+const char* WebPGetEnabledInputFileFormats(void);
+
+// Try to infer the image format. 'data_size' should be larger than 12.
+// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely.
+WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
+ size_t data_size);
+
+// Signature for common image-reading functions (ReadPNG, ReadJPEG, ...)
+typedef int (*WebPImageReader)(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata);
+
+// Return the reader associated to a given file format.
+WebPImageReader WebPGetImageReader(WebPInputFileFormat format);
+
+// This function is similar to WebPGuessImageType(), but returns a
+// suitable reader function. The returned reader is never NULL, but
+// unknown formats will return an always-failing valid reader.
+WebPImageReader WebPGuessImageReader(const uint8_t* const data,
+ size_t data_size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_IMAGE_DEC_H_
diff --git a/imageio/image_enc.c b/imageio/image_enc.c
new file mode 100644
index 0000000..e06bcaf
--- /dev/null
+++ b/imageio/image_enc.c
@@ -0,0 +1,615 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Save image
+
+#include "./image_enc.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WEBP_HAVE_PNG
+#include <png.h>
+#include <setjmp.h> // note: this must be included *after* png.h
+#endif
+
+#ifdef HAVE_WINCODEC_H
+#ifdef __MINGW32__
+#define INITGUID // Without this GUIDs are declared extern and fail to link
+#endif
+#define CINTERFACE
+#define COBJMACROS
+#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
+ // code with COBJMACROS.
+#include <ole2.h> // CreateStreamOnHGlobal()
+#include <shlwapi.h>
+#include <tchar.h>
+#include <windows.h>
+#include <wincodec.h>
+#endif
+
+#include "./imageio_util.h"
+#include "../examples/unicode.h"
+
+//------------------------------------------------------------------------------
+// PNG
+
+#ifdef HAVE_WINCODEC_H
+
+#define IFS(fn) \
+ do { \
+ if (SUCCEEDED(hr)) { \
+ hr = (fn); \
+ if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
+ } \
+ } while (0)
+
+#ifdef __cplusplus
+#define MAKE_REFGUID(x) (x)
+#else
+#define MAKE_REFGUID(x) &(x)
+#endif
+
+static HRESULT CreateOutputStream(const char* out_file_name,
+ int write_to_mem, IStream** stream) {
+ HRESULT hr = S_OK;
+ if (write_to_mem) {
+ // Output to a memory buffer. This is freed when 'stream' is released.
+ IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
+ } else {
+ IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name,
+ STGM_WRITE | STGM_CREATE, stream));
+ }
+ if (FAILED(hr)) {
+ _ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"),
+ (const LPTSTR)out_file_name, hr);
+ }
+ return hr;
+}
+
+static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
+ REFGUID container_guid,
+ uint8_t* rgb, int stride,
+ uint32_t width, uint32_t height, int has_alpha) {
+ HRESULT hr = S_OK;
+ IWICImagingFactory* factory = NULL;
+ IWICBitmapFrameEncode* frame = NULL;
+ IWICBitmapEncoder* encoder = NULL;
+ IStream* stream = NULL;
+ WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
+ : GUID_WICPixelFormat24bppBGR;
+
+ if (out_file_name == NULL || rgb == NULL) return E_INVALIDARG;
+
+ IFS(CoInitialize(NULL));
+ IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
+ CLSCTX_INPROC_SERVER,
+ MAKE_REFGUID(IID_IWICImagingFactory),
+ (LPVOID*)&factory));
+ if (hr == REGDB_E_CLASSNOTREG) {
+ fprintf(stderr,
+ "Couldn't access Windows Imaging Component (are you running "
+ "Windows XP SP3 or newer?). PNG support not available. "
+ "Use -ppm or -pgm for available PPM and PGM formats.\n");
+ }
+ IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
+ IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
+ &encoder));
+ IFS(IWICBitmapEncoder_Initialize(encoder, stream,
+ WICBitmapEncoderNoCache));
+ IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
+ IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
+ IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
+ IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
+ IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
+ height * stride, rgb));
+ IFS(IWICBitmapFrameEncode_Commit(frame));
+ IFS(IWICBitmapEncoder_Commit(encoder));
+
+ if (SUCCEEDED(hr) && use_stdout) {
+ HGLOBAL image;
+ IFS(GetHGlobalFromStream(stream, &image));
+ if (SUCCEEDED(hr)) {
+ HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD mode;
+ const BOOL update_mode = GetConsoleMode(std_output, &mode);
+ const void* const image_mem = GlobalLock(image);
+ DWORD bytes_written = 0;
+
+ // Clear output processing if necessary, then output the image.
+ if (update_mode) SetConsoleMode(std_output, 0);
+ if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image),
+ &bytes_written, NULL) ||
+ bytes_written != GlobalSize(image)) {
+ hr = E_FAIL;
+ }
+ if (update_mode) SetConsoleMode(std_output, mode);
+ GlobalUnlock(image);
+ }
+ }
+
+ if (frame != NULL) IUnknown_Release(frame);
+ if (encoder != NULL) IUnknown_Release(encoder);
+ if (factory != NULL) IUnknown_Release(factory);
+ if (stream != NULL) IUnknown_Release(stream);
+ return hr;
+}
+
+int WebPWritePNG(const char* out_file_name, int use_stdout,
+ const WebPDecBuffer* const buffer) {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ uint8_t* const rgb = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
+
+ return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
+ MAKE_REFGUID(GUID_ContainerFormatPng),
+ rgb, stride, width, height, has_alpha));
+}
+
+#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
+static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
+ (void)unused; // remove variable-unused warning
+ longjmp(png_jmpbuf(png), 1);
+}
+
+int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
+ volatile png_structp png;
+ volatile png_infop info;
+
+ if (out_file == NULL || buffer == NULL) return 0;
+
+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, PNGErrorFunction, NULL);
+ if (png == NULL) {
+ return 0;
+ }
+ info = png_create_info_struct(png);
+ if (info == NULL) {
+ png_destroy_write_struct((png_structpp)&png, NULL);
+ return 0;
+ }
+ if (setjmp(png_jmpbuf(png))) {
+ png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
+ return 0;
+ }
+ png_init_io(png, out_file);
+ {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ png_bytep row = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
+ uint32_t y;
+
+ png_set_IHDR(png, info, width, height, 8,
+ has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ png_write_info(png, info);
+ for (y = 0; y < height; ++y) {
+ png_write_rows(png, &row, 1);
+ row += stride;
+ }
+ }
+ png_write_end(png, info);
+ png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
+ return 1;
+}
+#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
+int WebPWritePNG(FILE* fout, const WebPDecBuffer* const buffer) {
+ if (fout == NULL || buffer == NULL) return 0;
+
+ fprintf(stderr, "PNG support not compiled. Please install the libpng "
+ "development package before building.\n");
+ fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n");
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// PPM / PAM
+
+static int WritePPMPAM(FILE* fout, const WebPDecBuffer* const buffer,
+ int alpha) {
+ if (fout == NULL || buffer == NULL) {
+ return 0;
+ } else {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ const uint8_t* row = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const size_t bytes_per_px = alpha ? 4 : 3;
+ uint32_t y;
+
+ if (row == NULL) return 0;
+
+ if (alpha) {
+ fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n"
+ "TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
+ } else {
+ fprintf(fout, "P6\n%u %u\n255\n", width, height);
+ }
+ for (y = 0; y < height; ++y) {
+ if (fwrite(row, width, bytes_per_px, fout) != bytes_per_px) {
+ return 0;
+ }
+ row += stride;
+ }
+ }
+ return 1;
+}
+
+int WebPWritePPM(FILE* fout, const WebPDecBuffer* const buffer) {
+ return WritePPMPAM(fout, buffer, 0);
+}
+
+int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
+ return WritePPMPAM(fout, buffer, 1);
+}
+
+//------------------------------------------------------------------------------
+// Raw PGM
+
+// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
+int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ const uint8_t* rgba = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const uint32_t bytes_per_px = 2;
+ uint32_t y;
+
+ if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+
+ fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
+ for (y = 0; y < height; ++y) {
+ if (fwrite(rgba, width, bytes_per_px, fout) != bytes_per_px) {
+ return 0;
+ }
+ rgba += stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// BMP (see https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage)
+
+static void PutLE16(uint8_t* const dst, uint32_t value) {
+ dst[0] = (value >> 0) & 0xff;
+ dst[1] = (value >> 8) & 0xff;
+}
+
+static void PutLE32(uint8_t* const dst, uint32_t value) {
+ PutLE16(dst + 0, (value >> 0) & 0xffff);
+ PutLE16(dst + 2, (value >> 16) & 0xffff);
+}
+
+#define BMP_HEADER_SIZE 54
+#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info
+int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
+ const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
+ const int header_size =
+ BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ const uint8_t* rgba = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const uint32_t bytes_per_px = has_alpha ? 4 : 3;
+ uint32_t y;
+ const uint32_t line_size = bytes_per_px * width;
+ const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
+ const uint32_t image_size = bmp_stride * height;
+ const uint32_t total_size = image_size + header_size;
+ uint8_t bmp_header[BMP_HEADER_SIZE + BMP_HEADER_ALPHA_EXTRA_SIZE] = { 0 };
+
+ if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+
+ // bitmap file header
+ PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
+ PutLE32(bmp_header + 2, total_size); // size including header
+ PutLE32(bmp_header + 6, 0); // reserved
+ PutLE32(bmp_header + 10, header_size); // offset to pixel array
+ // bitmap info header
+ PutLE32(bmp_header + 14, header_size - 14); // DIB header size
+ PutLE32(bmp_header + 18, width); // dimensions
+ PutLE32(bmp_header + 22, height); // no vertical flip
+ PutLE16(bmp_header + 26, 1); // number of planes
+ PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
+ PutLE32(bmp_header + 30, has_alpha ? 3 : 0); // BI_BITFIELDS or BI_RGB
+ PutLE32(bmp_header + 34, image_size);
+ PutLE32(bmp_header + 38, 2400); // x pixels/meter
+ PutLE32(bmp_header + 42, 2400); // y pixels/meter
+ PutLE32(bmp_header + 46, 0); // number of palette colors
+ PutLE32(bmp_header + 50, 0); // important color count
+ if (has_alpha) { // BITMAPV3INFOHEADER complement
+ PutLE32(bmp_header + 54, 0x00ff0000); // red mask
+ PutLE32(bmp_header + 58, 0x0000ff00); // green mask
+ PutLE32(bmp_header + 62, 0x000000ff); // blue mask
+ PutLE32(bmp_header + 66, 0xff000000); // alpha mask
+ }
+
+ // TODO(skal): color profile
+
+ // write header
+ if (fwrite(bmp_header, header_size, 1, fout) != 1) {
+ return 0;
+ }
+
+ // write pixel array, bottom to top
+ for (y = 0; y < height; ++y) {
+ const uint8_t* const src = &rgba[(uint64_t)(height - 1 - y) * stride];
+ if (fwrite(src, line_size, 1, fout) != 1) {
+ return 0;
+ }
+ // write padding zeroes
+ if (bmp_stride != line_size) {
+ const uint8_t zeroes[3] = { 0 };
+ if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+#undef BMP_HEADER_SIZE
+#undef BMP_HEADER_ALPHA_EXTRA_SIZE
+
+//------------------------------------------------------------------------------
+// TIFF
+
+#define NUM_IFD_ENTRIES 15
+#define EXTRA_DATA_SIZE 16
+// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
+#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
+#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
+
+int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
+ const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ const uint8_t* rgba = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const uint8_t bytes_per_px = has_alpha ? 4 : 3;
+ const uint8_t assoc_alpha =
+ WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
+ // For non-alpha case, we omit tag 0x152 (ExtraSamples).
+ const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
+ : NUM_IFD_ENTRIES - 1;
+ uint8_t tiff_header[TIFF_HEADER_SIZE] = {
+ 0x49, 0x49, 0x2a, 0x00, // little endian signature
+ 8, 0, 0, 0, // offset to the unique IFD that follows
+ // IFD (offset = 8). Entries must be written in increasing tag order.
+ num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
+ 0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
+ 0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
+ 0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
+ EXTRA_DATA_OFFSET + 0, 0, 0, 0,
+ 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
+ 0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
+ 0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
+ TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
+ 0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
+ 0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
+ bytes_per_px, 0, 0, 0,
+ 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
+ 0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
+ 0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
+ EXTRA_DATA_OFFSET + 8, 0, 0, 0,
+ 0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
+ EXTRA_DATA_OFFSET + 8, 0, 0, 0,
+ 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
+ 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
+ 0x52, 0x01, 3, 0, 1, 0, 0, 0,
+ assoc_alpha, 0, 0, 0, // 178: ExtraSamples: rgbA/RGBA
+ 0, 0, 0, 0, // 190: IFD terminator
+ // EXTRA_DATA_OFFSET:
+ 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
+ 72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
+ };
+ uint32_t y;
+
+ if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+
+ // Fill placeholders in IFD:
+ PutLE32(tiff_header + 10 + 8, width);
+ PutLE32(tiff_header + 22 + 8, height);
+ PutLE32(tiff_header + 106 + 8, height);
+ PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
+ if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
+
+ // write header
+ if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
+ return 0;
+ }
+ // write pixel values
+ for (y = 0; y < height; ++y) {
+ if (fwrite(rgba, bytes_per_px, width, fout) != width) {
+ return 0;
+ }
+ rgba += stride;
+ }
+
+ return 1;
+}
+
+#undef TIFF_HEADER_SIZE
+#undef EXTRA_DATA_OFFSET
+#undef EXTRA_DATA_SIZE
+#undef NUM_IFD_ENTRIES
+
+//------------------------------------------------------------------------------
+// Raw Alpha
+
+int WebPWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
+ if (fout == NULL || buffer == NULL) {
+ return 0;
+ } else {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ const uint8_t* a = buffer->u.YUVA.a;
+ const int a_stride = buffer->u.YUVA.a_stride;
+ uint32_t y;
+
+ if (a == NULL) return 0;
+
+ fprintf(fout, "P5\n%u %u\n255\n", width, height);
+ for (y = 0; y < height; ++y) {
+ if (fwrite(a, width, 1, fout) != 1) return 0;
+ a += a_stride;
+ }
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// PGM with IMC4 layout
+
+int WebPWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
+ if (fout == NULL || buffer == NULL) {
+ return 0;
+ } else {
+ const int width = buffer->width;
+ const int height = buffer->height;
+ const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
+ const uint8_t* src_y = yuv->y;
+ const uint8_t* src_u = yuv->u;
+ const uint8_t* src_v = yuv->v;
+ const uint8_t* src_a = yuv->a;
+ const int uv_width = (width + 1) / 2;
+ const int uv_height = (height + 1) / 2;
+ const int a_height = (src_a != NULL) ? height : 0;
+ int ok = 1;
+ int y;
+
+ if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
+
+ fprintf(fout, "P5\n%d %d\n255\n",
+ (width + 1) & ~1, height + uv_height + a_height);
+ for (y = 0; ok && y < height; ++y) {
+ ok &= (fwrite(src_y, width, 1, fout) == 1);
+ if (width & 1) fputc(0, fout); // padding byte
+ src_y += yuv->y_stride;
+ }
+ for (y = 0; ok && y < uv_height; ++y) {
+ ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
+ ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
+ src_u += yuv->u_stride;
+ src_v += yuv->v_stride;
+ }
+ for (y = 0; ok && y < a_height; ++y) {
+ ok &= (fwrite(src_a, width, 1, fout) == 1);
+ if (width & 1) fputc(0, fout); // padding byte
+ src_a += yuv->a_stride;
+ }
+ return ok;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Raw YUV(A) planes
+
+int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
+ if (fout == NULL || buffer == NULL) {
+ return 0;
+ } else {
+ const int width = buffer->width;
+ const int height = buffer->height;
+ const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
+ const uint8_t* src_y = yuv->y;
+ const uint8_t* src_u = yuv->u;
+ const uint8_t* src_v = yuv->v;
+ const uint8_t* src_a = yuv->a;
+ const int uv_width = (width + 1) / 2;
+ const int uv_height = (height + 1) / 2;
+ const int a_height = (src_a != NULL) ? height : 0;
+ int ok = 1;
+ int y;
+
+ if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
+
+ for (y = 0; ok && y < height; ++y) {
+ ok &= (fwrite(src_y, width, 1, fout) == 1);
+ src_y += yuv->y_stride;
+ }
+ for (y = 0; ok && y < uv_height; ++y) {
+ ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
+ src_u += yuv->u_stride;
+ }
+ for (y = 0; ok && y < uv_height; ++y) {
+ ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
+ src_v += yuv->v_stride;
+ }
+ for (y = 0; ok && y < a_height; ++y) {
+ ok &= (fwrite(src_a, width, 1, fout) == 1);
+ src_a += yuv->a_stride;
+ }
+ return ok;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Generic top-level call
+
+int WebPSaveImage(const WebPDecBuffer* const buffer,
+ WebPOutputFileFormat format,
+ const char* const out_file_name) {
+ FILE* fout = NULL;
+ int needs_open_file = 1;
+ const int use_stdout =
+ (out_file_name != NULL) && !WSTRCMP(out_file_name, "-");
+ int ok = 1;
+
+ if (buffer == NULL || out_file_name == NULL) return 0;
+
+#ifdef HAVE_WINCODEC_H
+ needs_open_file = (format != PNG);
+#endif
+
+ if (needs_open_file) {
+ fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout)
+ : WFOPEN(out_file_name, "wb");
+ if (fout == NULL) {
+ WFPRINTF(stderr, "Error opening output file %s\n",
+ (const W_CHAR*)out_file_name);
+ return 0;
+ }
+ }
+
+ if (format == PNG ||
+ format == RGBA || format == BGRA || format == ARGB ||
+ format == rgbA || format == bgrA || format == Argb) {
+#ifdef HAVE_WINCODEC_H
+ ok &= WebPWritePNG(out_file_name, use_stdout, buffer);
+#else
+ ok &= WebPWritePNG(fout, buffer);
+#endif
+ } else if (format == PAM) {
+ ok &= WebPWritePAM(fout, buffer);
+ } else if (format == PPM || format == RGB || format == BGR) {
+ ok &= WebPWritePPM(fout, buffer);
+ } else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) {
+ ok &= WebPWrite16bAsPGM(fout, buffer);
+ } else if (format == BMP) {
+ ok &= WebPWriteBMP(fout, buffer);
+ } else if (format == TIFF) {
+ ok &= WebPWriteTIFF(fout, buffer);
+ } else if (format == RAW_YUV) {
+ ok &= WebPWriteYUV(fout, buffer);
+ } else if (format == PGM || format == YUV || format == YUVA) {
+ ok &= WebPWritePGM(fout, buffer);
+ } else if (format == ALPHA_PLANE_ONLY) {
+ ok &= WebPWriteAlphaPlane(fout, buffer);
+ }
+ if (fout != NULL && fout != stdout) {
+ fclose(fout);
+ }
+ return ok;
+}
diff --git a/imageio/image_enc.h b/imageio/image_enc.h
new file mode 100644
index 0000000..d31e4bd
--- /dev/null
+++ b/imageio/image_enc.h
@@ -0,0 +1,96 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// All-in-one library to save PNG/JPEG/WebP/TIFF/WIC images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_IMAGEIO_IMAGE_ENC_H_
+#define WEBP_IMAGEIO_IMAGE_ENC_H_
+
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "webp/types.h"
+#include "webp/decode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Output types
+typedef enum {
+ PNG = 0,
+ PAM,
+ PPM,
+ PGM,
+ BMP,
+ TIFF,
+ RAW_YUV,
+ ALPHA_PLANE_ONLY, // this is for experimenting only
+ // forced colorspace output (for testing, mostly)
+ RGB, RGBA, BGR, BGRA, ARGB,
+ RGBA_4444, RGB_565,
+ rgbA, bgrA, Argb, rgbA_4444,
+ YUV, YUVA
+} WebPOutputFileFormat;
+
+// General all-purpose call.
+// Most formats expect a 'buffer' containing RGBA-like samples, except
+// RAW_YUV, YUV and YUVA formats.
+// If 'out_file_name' is "-", data is saved to stdout.
+// Returns false if an error occurred, true otherwise.
+int WebPSaveImage(const WebPDecBuffer* const buffer,
+ WebPOutputFileFormat format, const char* const out_file_name);
+
+// Save to PNG.
+#ifdef HAVE_WINCODEC_H
+int WebPWritePNG(const char* out_file_name, int use_stdout,
+ const struct WebPDecBuffer* const buffer);
+#else
+int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer);
+#endif
+
+// Save to PPM format (RGB, no alpha)
+int WebPWritePPM(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save to PAM format (= PPM + alpha)
+int WebPWritePAM(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save 16b mode (RGBA4444, RGB565, ...) for debugging purposes.
+int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save as BMP
+int WebPWriteBMP(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save as TIFF
+int WebPWriteTIFF(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save the ALPHA plane (only) as a PGM
+int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save as YUV samples as PGM format (using IMC4 layout).
+// See: https://www.fourcc.org/yuv.php#IMC4.
+// (very convenient format for viewing the samples, esp. for odd dimensions).
+int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save YUV(A) planes sequentially (raw dump)
+int WebPWriteYUV(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+// Save 16b mode (RGBA4444, RGB565, ...) as PGM format, for debugging purposes.
+int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_IMAGE_ENC_H_
diff --git a/imageio/imageio_util.c b/imageio/imageio_util.c
new file mode 100644
index 0000000..df37137
--- /dev/null
+++ b/imageio/imageio_util.c
@@ -0,0 +1,162 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Utility functions used by the image decoders.
+//
+
+#include "./imageio_util.h"
+
+#if defined(_WIN32)
+#include <fcntl.h> // for _O_BINARY
+#include <io.h> // for _setmode()
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include "../examples/unicode.h"
+
+// -----------------------------------------------------------------------------
+// File I/O
+
+FILE* ImgIoUtilSetBinaryMode(FILE* file) {
+#if defined(_WIN32)
+ if (_setmode(_fileno(file), _O_BINARY) == -1) {
+ fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
+ return NULL;
+ }
+#endif
+ return file;
+}
+
+int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
+ static const size_t kBlockSize = 16384; // default initial size
+ size_t max_size = 0;
+ size_t size = 0;
+ uint8_t* input = NULL;
+
+ if (data == NULL || data_size == NULL) return 0;
+ *data = NULL;
+ *data_size = 0;
+
+ if (!ImgIoUtilSetBinaryMode(stdin)) return 0;
+
+ while (!feof(stdin)) {
+ // We double the buffer size each time and read as much as possible.
+ const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
+ // we allocate one extra byte for the \0 terminator
+ void* const new_data = realloc(input, max_size + extra_size + 1);
+ if (new_data == NULL) goto Error;
+ input = (uint8_t*)new_data;
+ max_size += extra_size;
+ size += fread(input + size, 1, extra_size, stdin);
+ if (size < max_size) break;
+ }
+ if (ferror(stdin)) goto Error;
+ if (input != NULL) input[size] = '\0'; // convenient 0-terminator
+ *data = input;
+ *data_size = size;
+ return 1;
+
+ Error:
+ free(input);
+ fprintf(stderr, "Could not read from stdin\n");
+ return 0;
+}
+
+int ImgIoUtilReadFile(const char* const file_name,
+ const uint8_t** data, size_t* data_size) {
+ int ok;
+ uint8_t* file_data;
+ size_t file_size;
+ FILE* in;
+ const int from_stdin = (file_name == NULL) || !WSTRCMP(file_name, "-");
+
+ if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
+
+ if (data == NULL || data_size == NULL) return 0;
+ *data = NULL;
+ *data_size = 0;
+
+ in = WFOPEN(file_name, "rb");
+ if (in == NULL) {
+ WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)file_name);
+ return 0;
+ }
+ fseek(in, 0, SEEK_END);
+ file_size = ftell(in);
+ fseek(in, 0, SEEK_SET);
+ // we allocate one extra byte for the \0 terminator
+ file_data = (uint8_t*)WebPMalloc(file_size + 1);
+ if (file_data == NULL) {
+ fclose(in);
+ WFPRINTF(stderr, "memory allocation failure when reading file %s\n",
+ (const W_CHAR*)file_name);
+ return 0;
+ }
+ ok = (fread(file_data, file_size, 1, in) == 1);
+ fclose(in);
+
+ if (!ok) {
+ WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n",
+ (int)file_size, (const W_CHAR*)file_name);
+ WebPFree(file_data);
+ return 0;
+ }
+ file_data[file_size] = '\0'; // convenient 0-terminator
+ *data = file_data;
+ *data_size = file_size;
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+int ImgIoUtilWriteFile(const char* const file_name,
+ const uint8_t* data, size_t data_size) {
+ int ok;
+ FILE* out;
+ const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-");
+
+ if (data == NULL) {
+ return 0;
+ }
+ out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb");
+ if (out == NULL) {
+ WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
+ (const W_CHAR*)file_name);
+ return 0;
+ }
+ ok = (fwrite(data, data_size, 1, out) == 1);
+ if (out != stdout) fclose(out);
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ while (height-- > 0) {
+ memcpy(dst, src, width * sizeof(*dst));
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) {
+ const uint64_t total_size = stride * height;
+ int ok = (total_size == (size_t)total_size);
+ // check that 'stride' is representable as int:
+ ok = ok && ((uint64_t)(int)stride == stride);
+#if defined(WEBP_MAX_IMAGE_SIZE)
+ ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
+#endif
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/imageio_util.h b/imageio/imageio_util.h
new file mode 100644
index 0000000..f135f56
--- /dev/null
+++ b/imageio/imageio_util.h
@@ -0,0 +1,64 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Utility functions used by the image decoders.
+//
+
+#ifndef WEBP_IMAGEIO_IMAGEIO_UTIL_H_
+#define WEBP_IMAGEIO_IMAGEIO_UTIL_H_
+
+#include <stdio.h>
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// File I/O
+
+// Reopen file in binary (O_BINARY) mode.
+// Returns 'file' on success, NULL otherwise.
+FILE* ImgIoUtilSetBinaryMode(FILE* file);
+
+// Allocates storage for entire file 'file_name' and returns contents and size
+// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
+// be deleted using WebPFree().
+// Note: for convenience, the data will be null-terminated with an extra byte
+// (not accounted for in *data_size), in case the file is text and intended
+// to be used as a C-string.
+// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
+// the function ImgIoUtilReadFromStdin().
+int ImgIoUtilReadFile(const char* const file_name,
+ const uint8_t** data, size_t* data_size);
+
+// Same as ImgIoUtilReadFile(), but reads until EOF from stdin instead.
+int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size);
+
+// Write a data segment into a file named 'file_name'. Returns true if ok.
+// If 'file_name' is NULL or equal to "-", output is written to stdout.
+int ImgIoUtilWriteFile(const char* const file_name,
+ const uint8_t* data, size_t data_size);
+
+//------------------------------------------------------------------------------
+
+// Copy width x height pixels from 'src' to 'dst' honoring the strides.
+void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height);
+
+//------------------------------------------------------------------------------
+
+// Returns 0 in case of overflow, memory over-allocation or excessive dimension.
+int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_IMAGEIO_UTIL_H_
diff --git a/imageio/jpegdec.c b/imageio/jpegdec.c
new file mode 100644
index 0000000..74a4c09
--- /dev/null
+++ b/imageio/jpegdec.c
@@ -0,0 +1,364 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// JPEG decode.
+
+#include "./jpegdec.h"
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef WEBP_HAVE_JPEG
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "webp/encode.h"
+#include "./imageio_util.h"
+#include "./metadata.h"
+
+// -----------------------------------------------------------------------------
+// Metadata processing
+
+#ifndef JPEG_APP1
+# define JPEG_APP1 (JPEG_APP0 + 1)
+#endif
+#ifndef JPEG_APP2
+# define JPEG_APP2 (JPEG_APP0 + 2)
+#endif
+
+typedef struct {
+ const uint8_t* data;
+ size_t data_length;
+ int seq; // this segment's sequence number [1, 255] for use in reassembly.
+} ICCPSegment;
+
+static void SaveMetadataMarkers(j_decompress_ptr dinfo) {
+ const unsigned int max_marker_length = 0xffff;
+ jpeg_save_markers(dinfo, JPEG_APP1, max_marker_length); // Exif/XMP
+ jpeg_save_markers(dinfo, JPEG_APP2, max_marker_length); // ICC profile
+}
+
+static int CompareICCPSegments(const void* a, const void* b) {
+ const ICCPSegment* s1 = (const ICCPSegment*)a;
+ const ICCPSegment* s2 = (const ICCPSegment*)b;
+ return s1->seq - s2->seq;
+}
+
+// Extract ICC profile segments from the marker list in 'dinfo', reassembling
+// and storing them in 'iccp'.
+// Returns true on success and false for memory errors and corrupt profiles.
+static int StoreICCP(j_decompress_ptr dinfo, MetadataPayload* const iccp) {
+ // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files
+ static const char kICCPSignature[] = "ICC_PROFILE";
+ static const size_t kICCPSignatureLength = 12; // signature includes '\0'
+ static const size_t kICCPSkipLength = 14; // signature + seq & count
+ int expected_count = 0;
+ int actual_count = 0;
+ int seq_max = 0;
+ size_t total_size = 0;
+ ICCPSegment iccp_segments[255];
+ jpeg_saved_marker_ptr marker;
+
+ memset(iccp_segments, 0, sizeof(iccp_segments));
+ for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker->marker == JPEG_APP2 &&
+ marker->data_length > kICCPSkipLength &&
+ !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) {
+ // ICC_PROFILE\0<seq><count>; 'seq' starts at 1.
+ const int seq = marker->data[kICCPSignatureLength];
+ const int count = marker->data[kICCPSignatureLength + 1];
+ const size_t segment_size = marker->data_length - kICCPSkipLength;
+ ICCPSegment* segment;
+
+ if (segment_size == 0 || count == 0 || seq == 0) {
+ fprintf(stderr, "[ICCP] size (%d) / count (%d) / sequence number (%d)"
+ " cannot be 0!\n",
+ (int)segment_size, seq, count);
+ return 0;
+ }
+
+ if (expected_count == 0) {
+ expected_count = count;
+ } else if (expected_count != count) {
+ fprintf(stderr, "[ICCP] Inconsistent segment count (%d / %d)!\n",
+ expected_count, count);
+ return 0;
+ }
+
+ segment = iccp_segments + seq - 1;
+ if (segment->data_length != 0) {
+ fprintf(stderr, "[ICCP] Duplicate segment number (%d)!\n" , seq);
+ return 0;
+ }
+
+ segment->data = marker->data + kICCPSkipLength;
+ segment->data_length = segment_size;
+ segment->seq = seq;
+ total_size += segment_size;
+ if (seq > seq_max) seq_max = seq;
+ ++actual_count;
+ }
+ }
+
+ if (actual_count == 0) return 1;
+ if (seq_max != actual_count) {
+ fprintf(stderr, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n",
+ actual_count, seq_max);
+ return 0;
+ }
+ if (expected_count != actual_count) {
+ fprintf(stderr, "[ICCP] Segment count: %d does not match expected: %d!\n",
+ actual_count, expected_count);
+ return 0;
+ }
+
+ // The segments may appear out of order in the file, sort them based on
+ // sequence number before assembling the payload.
+ qsort(iccp_segments, actual_count, sizeof(*iccp_segments),
+ CompareICCPSegments);
+
+ iccp->bytes = (uint8_t*)malloc(total_size);
+ if (iccp->bytes == NULL) return 0;
+ iccp->size = total_size;
+
+ {
+ int i;
+ size_t offset = 0;
+ for (i = 0; i < seq_max; ++i) {
+ memcpy(iccp->bytes + offset,
+ iccp_segments[i].data, iccp_segments[i].data_length);
+ offset += iccp_segments[i].data_length;
+ }
+ }
+ return 1;
+}
+
+// Returns true on success and false for memory errors and corrupt profiles.
+// The caller must use MetadataFree() on 'metadata' in all cases.
+static int ExtractMetadataFromJPEG(j_decompress_ptr dinfo,
+ Metadata* const metadata) {
+ static const struct {
+ int marker;
+ const char* signature;
+ size_t signature_length;
+ size_t storage_offset;
+ } kJPEGMetadataMap[] = {
+ // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ...
+ { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) },
+ // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG
+ // TODO(jzern) Add support for 'ExtendedXMP'
+ { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) },
+ { 0, NULL, 0, 0 },
+ };
+ jpeg_saved_marker_ptr marker;
+ // Treat ICC profiles separately as they may be segmented and out of order.
+ if (!StoreICCP(dinfo, &metadata->iccp)) return 0;
+
+ for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
+ int i;
+ for (i = 0; kJPEGMetadataMap[i].marker != 0; ++i) {
+ if (marker->marker == kJPEGMetadataMap[i].marker &&
+ marker->data_length > kJPEGMetadataMap[i].signature_length &&
+ !memcmp(marker->data, kJPEGMetadataMap[i].signature,
+ kJPEGMetadataMap[i].signature_length)) {
+ MetadataPayload* const payload =
+ (MetadataPayload*)((uint8_t*)metadata +
+ kJPEGMetadataMap[i].storage_offset);
+
+ if (payload->bytes == NULL) {
+ const char* marker_data = (const char*)marker->data +
+ kJPEGMetadataMap[i].signature_length;
+ const size_t marker_data_length =
+ marker->data_length - kJPEGMetadataMap[i].signature_length;
+ if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0;
+ } else {
+ fprintf(stderr, "Ignoring additional '%s' marker\n",
+ kJPEGMetadataMap[i].signature);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+#undef JPEG_APP1
+#undef JPEG_APP2
+
+// -----------------------------------------------------------------------------
+// JPEG decoding
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+static void my_error_exit(j_common_ptr dinfo) {
+ struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
+ fprintf(stderr, "libjpeg error: ");
+ dinfo->err->output_message(dinfo);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+typedef struct {
+ struct jpeg_source_mgr pub;
+ const uint8_t* data;
+ size_t data_size;
+} JPEGReadContext;
+
+static void ContextInit(j_decompress_ptr cinfo) {
+ JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
+ ctx->pub.next_input_byte = ctx->data;
+ ctx->pub.bytes_in_buffer = ctx->data_size;
+}
+
+static boolean ContextFill(j_decompress_ptr cinfo) {
+ // we shouldn't get here.
+ ERREXIT(cinfo, JERR_FILE_READ);
+ return FALSE;
+}
+
+static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
+ JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
+ size_t jump = (size_t)jump_size;
+ if (jump > ctx->pub.bytes_in_buffer) { // Don't overflow the buffer.
+ jump = ctx->pub.bytes_in_buffer;
+ }
+ ctx->pub.bytes_in_buffer -= jump;
+ ctx->pub.next_input_byte += jump;
+}
+
+static void ContextTerm(j_decompress_ptr cinfo) {
+ (void)cinfo;
+}
+
+static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo,
+ JPEGReadContext* const ctx) {
+ cinfo->src = (struct jpeg_source_mgr*)ctx;
+ ctx->pub.init_source = ContextInit;
+ ctx->pub.fill_input_buffer = ContextFill;
+ ctx->pub.skip_input_data = ContextSkip;
+ ctx->pub.resync_to_restart = jpeg_resync_to_restart;
+ ctx->pub.term_source = ContextTerm;
+ ctx->pub.bytes_in_buffer = 0;
+ ctx->pub.next_input_byte = NULL;
+}
+
+int ReadJPEG(const uint8_t* const data, size_t data_size,
+ WebPPicture* const pic, int keep_alpha,
+ Metadata* const metadata) {
+ volatile int ok = 0;
+ int width, height;
+ int64_t stride;
+ volatile struct jpeg_decompress_struct dinfo;
+ struct my_error_mgr jerr;
+ uint8_t* volatile rgb = NULL;
+ JSAMPROW buffer[1];
+ JPEGReadContext ctx;
+
+ if (data == NULL || data_size == 0 || pic == NULL) return 0;
+
+ (void)keep_alpha;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.data = data;
+ ctx.data_size = data_size;
+
+ memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety
+ dinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer)) {
+ Error:
+ MetadataFree(metadata);
+ jpeg_destroy_decompress((j_decompress_ptr)&dinfo);
+ goto End;
+ }
+
+ jpeg_create_decompress((j_decompress_ptr)&dinfo);
+ ContextSetup(&dinfo, &ctx);
+ if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo);
+ jpeg_read_header((j_decompress_ptr)&dinfo, TRUE);
+
+ dinfo.out_color_space = JCS_RGB;
+ dinfo.do_fancy_upsampling = TRUE;
+
+ jpeg_start_decompress((j_decompress_ptr)&dinfo);
+
+ if (dinfo.output_components != 3) {
+ goto Error;
+ }
+
+ width = dinfo.output_width;
+ height = dinfo.output_height;
+ stride = (int64_t)dinfo.output_width * dinfo.output_components * sizeof(*rgb);
+
+ if (stride != (int)stride ||
+ !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
+ goto Error;
+ }
+
+ rgb = (uint8_t*)malloc((size_t)stride * height);
+ if (rgb == NULL) {
+ goto Error;
+ }
+ buffer[0] = (JSAMPLE*)rgb;
+
+ while (dinfo.output_scanline < dinfo.output_height) {
+ if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) {
+ goto Error;
+ }
+ buffer[0] += stride;
+ }
+
+ if (metadata != NULL) {
+ ok = ExtractMetadataFromJPEG((j_decompress_ptr)&dinfo, metadata);
+ if (!ok) {
+ fprintf(stderr, "Error extracting JPEG metadata!\n");
+ goto Error;
+ }
+ }
+
+ jpeg_finish_decompress((j_decompress_ptr)&dinfo);
+ jpeg_destroy_decompress((j_decompress_ptr)&dinfo);
+
+ // WebP conversion.
+ pic->width = width;
+ pic->height = height;
+ ok = WebPPictureImportRGB(pic, rgb, (int)stride);
+ if (!ok) {
+ pic->width = 0; // WebPPictureImportRGB() barely touches 'pic' on failure.
+ pic->height = 0; // Just reset dimensions but keep any 'custom_ptr' etc.
+ MetadataFree(metadata); // In case the caller forgets to free it on error.
+ }
+
+ End:
+ free(rgb);
+ return ok;
+}
+#else // !WEBP_HAVE_JPEG
+int ReadJPEG(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata) {
+ (void)data;
+ (void)data_size;
+ (void)pic;
+ (void)keep_alpha;
+ (void)metadata;
+ fprintf(stderr, "JPEG support not compiled. Please install the libjpeg "
+ "development package before building.\n");
+ return 0;
+}
+#endif // WEBP_HAVE_JPEG
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/jpegdec.h b/imageio/jpegdec.h
new file mode 100644
index 0000000..effc14f
--- /dev/null
+++ b/imageio/jpegdec.h
@@ -0,0 +1,37 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// JPEG decode.
+
+#ifndef WEBP_IMAGEIO_JPEGDEC_H_
+#define WEBP_IMAGEIO_JPEGDEC_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+// Reads a JPEG from 'data', returning the decoded output in 'pic'.
+// The output is RGB or YUV depending on pic->use_argb value.
+// Returns true on success.
+// 'keep_alpha' has no effect, but is kept for coherence with other signatures
+// for image readers.
+int ReadJPEG(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_JPEGDEC_H_
diff --git a/imageio/metadata.c b/imageio/metadata.c
new file mode 100644
index 0000000..936f2f4
--- /dev/null
+++ b/imageio/metadata.c
@@ -0,0 +1,49 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Metadata types and functions.
+//
+
+#include "./metadata.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "webp/types.h"
+
+void MetadataInit(Metadata* const metadata) {
+ if (metadata == NULL) return;
+ memset(metadata, 0, sizeof(*metadata));
+}
+
+void MetadataPayloadDelete(MetadataPayload* const payload) {
+ if (payload == NULL) return;
+ free(payload->bytes);
+ payload->bytes = NULL;
+ payload->size = 0;
+}
+
+void MetadataFree(Metadata* const metadata) {
+ if (metadata == NULL) return;
+ MetadataPayloadDelete(&metadata->exif);
+ MetadataPayloadDelete(&metadata->iccp);
+ MetadataPayloadDelete(&metadata->xmp);
+}
+
+int MetadataCopy(const char* metadata, size_t metadata_len,
+ MetadataPayload* const payload) {
+ if (metadata == NULL || metadata_len == 0 || payload == NULL) return 0;
+ payload->bytes = (uint8_t*)malloc(metadata_len);
+ if (payload->bytes == NULL) return 0;
+ payload->size = metadata_len;
+ memcpy(payload->bytes, metadata, metadata_len);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/metadata.h b/imageio/metadata.h
new file mode 100644
index 0000000..1d5be91
--- /dev/null
+++ b/imageio/metadata.h
@@ -0,0 +1,47 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// Metadata types and functions.
+//
+
+#ifndef WEBP_IMAGEIO_METADATA_H_
+#define WEBP_IMAGEIO_METADATA_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct MetadataPayload {
+ uint8_t* bytes;
+ size_t size;
+} MetadataPayload;
+
+typedef struct Metadata {
+ MetadataPayload exif;
+ MetadataPayload iccp;
+ MetadataPayload xmp;
+} Metadata;
+
+#define METADATA_OFFSET(x) offsetof(Metadata, x)
+
+void MetadataInit(Metadata* const metadata);
+void MetadataPayloadDelete(MetadataPayload* const payload);
+void MetadataFree(Metadata* const metadata);
+
+// Stores 'metadata' to 'payload->bytes', returns false on allocation error.
+int MetadataCopy(const char* metadata, size_t metadata_len,
+ MetadataPayload* const payload);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_METADATA_H_
diff --git a/imageio/pngdec.c b/imageio/pngdec.c
new file mode 100644
index 0000000..6a1543b
--- /dev/null
+++ b/imageio/pngdec.c
@@ -0,0 +1,374 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// PNG decode.
+
+#include "./pngdec.h"
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef WEBP_HAVE_PNG
+#ifndef PNG_USER_MEM_SUPPORTED
+#define PNG_USER_MEM_SUPPORTED // for png_create_read_struct_2
+#endif
+#include <png.h>
+#include <setjmp.h> // note: this must be included *after* png.h
+#include <stdlib.h>
+#include <string.h>
+
+#include "webp/encode.h"
+#include "./imageio_util.h"
+#include "./metadata.h"
+
+#define LOCAL_PNG_VERSION ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR)
+#define LOCAL_PNG_PREREQ(maj, min) \
+ (LOCAL_PNG_VERSION >= (((maj) << 8) | (min)))
+
+static void PNGAPI error_function(png_structp png, png_const_charp error) {
+ if (error != NULL) fprintf(stderr, "libpng error: %s\n", error);
+ longjmp(png_jmpbuf(png), 1);
+}
+
+#if LOCAL_PNG_PREREQ(1,4)
+typedef png_alloc_size_t LocalPngAllocSize;
+#else
+typedef png_size_t LocalPngAllocSize;
+#endif
+
+static png_voidp MallocFunc(png_structp png_ptr, LocalPngAllocSize size) {
+ (void)png_ptr;
+ if (size != (size_t)size) return NULL;
+ if (!ImgIoUtilCheckSizeArgumentsOverflow(size, 1)) return NULL;
+ return (png_voidp)malloc((size_t)size);
+}
+
+static void FreeFunc(png_structp png_ptr, png_voidp ptr) {
+ (void)png_ptr;
+ free(ptr);
+}
+
+// Converts the NULL terminated 'hexstring' which contains 2-byte character
+// representations of hex values to raw data.
+// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs,
+// e.g., 7af2..., separated by any number of newlines.
+// 'expected_length' is the anticipated processed size.
+// On success the raw buffer is returned with its length equivalent to
+// 'expected_length'. NULL is returned if the processed length is less than
+// 'expected_length' or any character aside from those above is encountered.
+// The returned buffer must be freed by the caller.
+static uint8_t* HexStringToBytes(const char* hexstring,
+ size_t expected_length) {
+ const char* src = hexstring;
+ size_t actual_length = 0;
+ uint8_t* const raw_data = (uint8_t*)malloc(expected_length);
+ uint8_t* dst;
+
+ if (raw_data == NULL) return NULL;
+
+ for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) {
+ char* end;
+ char val[3];
+ if (*src == '\n') continue;
+ val[0] = *src++;
+ val[1] = *src;
+ val[2] = '\0';
+ *dst++ = (uint8_t)strtol(val, &end, 16);
+ if (end != val + 2) break;
+ ++actual_length;
+ }
+
+ if (actual_length != expected_length) {
+ free(raw_data);
+ return NULL;
+ }
+ return raw_data;
+}
+
+static int ProcessRawProfile(const char* profile, size_t profile_len,
+ MetadataPayload* const payload) {
+ const char* src = profile;
+ char* end;
+ int expected_length;
+
+ if (profile == NULL || profile_len == 0) return 0;
+
+ // ImageMagick formats 'raw profiles' as
+ // '\n<name>\n<length>(%8lu)\n<hex payload>\n'.
+ if (*src != '\n') {
+ fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n",
+ *src);
+ return 0;
+ }
+ ++src;
+ // skip the profile name and extract the length.
+ while (*src != '\0' && *src++ != '\n') {}
+ expected_length = (int)strtol(src, &end, 10);
+ if (*end != '\n') {
+ fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n",
+ *end);
+ return 0;
+ }
+ ++end;
+
+ // 'end' now points to the profile payload.
+ payload->bytes = HexStringToBytes(end, expected_length);
+ if (payload->bytes == NULL) return 0;
+ payload->size = expected_length;
+ return 1;
+}
+
+static const struct {
+ const char* name;
+ int (*process)(const char* profile, size_t profile_len,
+ MetadataPayload* const payload);
+ size_t storage_offset;
+} kPNGMetadataMap[] = {
+ // https://exiftool.org/TagNames/PNG.html#TextualData
+ // See also: ExifTool on CPAN.
+ { "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) },
+ { "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
+ // Exiftool puts exif data in APP1 chunk, too.
+ { "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) },
+ // XMP Specification Part 3, Section 3 #PNG
+ { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) },
+ { NULL, NULL, 0 },
+};
+
+// Looks for metadata at both the beginning and end of the PNG file, giving
+// preference to the head.
+// Returns true on success. The caller must use MetadataFree() on 'metadata' in
+// all cases.
+static int ExtractMetadataFromPNG(png_structp png,
+ png_infop const head_info,
+ png_infop const end_info,
+ Metadata* const metadata) {
+ int p;
+
+ for (p = 0; p < 2; ++p) {
+ png_infop const info = (p == 0) ? head_info : end_info;
+ png_textp text = NULL;
+ const png_uint_32 num = png_get_text(png, info, &text, NULL);
+ png_uint_32 i;
+ // Look for EXIF / XMP metadata.
+ for (i = 0; i < num; ++i, ++text) {
+ int j;
+ for (j = 0; kPNGMetadataMap[j].name != NULL; ++j) {
+ if (!strcmp(text->key, kPNGMetadataMap[j].name)) {
+ MetadataPayload* const payload =
+ (MetadataPayload*)((uint8_t*)metadata +
+ kPNGMetadataMap[j].storage_offset);
+ png_size_t text_length;
+ switch (text->compression) {
+#ifdef PNG_iTXt_SUPPORTED
+ case PNG_ITXT_COMPRESSION_NONE:
+ case PNG_ITXT_COMPRESSION_zTXt:
+ text_length = text->itxt_length;
+ break;
+#endif
+ case PNG_TEXT_COMPRESSION_NONE:
+ case PNG_TEXT_COMPRESSION_zTXt:
+ default:
+ text_length = text->text_length;
+ break;
+ }
+ if (payload->bytes != NULL) {
+ fprintf(stderr, "Ignoring additional '%s'\n", text->key);
+ } else if (!kPNGMetadataMap[j].process(text->text, text_length,
+ payload)) {
+ fprintf(stderr, "Failed to process: '%s'\n", text->key);
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ // Look for an ICC profile.
+ {
+ png_charp name;
+ int comp_type;
+#if LOCAL_PNG_PREREQ(1,5)
+ png_bytep profile;
+#else
+ png_charp profile;
+#endif
+ png_uint_32 len;
+
+ if (png_get_iCCP(png, info,
+ &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) {
+ if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+typedef struct {
+ const uint8_t* data;
+ size_t data_size;
+ png_size_t offset;
+} PNGReadContext;
+
+static void ReadFunc(png_structp png_ptr, png_bytep data, png_size_t length) {
+ PNGReadContext* const ctx = (PNGReadContext*)png_get_io_ptr(png_ptr);
+ if (ctx->data_size - ctx->offset < length) {
+ png_error(png_ptr, "ReadFunc: invalid read length (overflow)!");
+ }
+ memcpy(data, ctx->data + ctx->offset, length);
+ ctx->offset += length;
+}
+
+int ReadPNG(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata) {
+ volatile png_structp png = NULL;
+ volatile png_infop info = NULL;
+ volatile png_infop end_info = NULL;
+ PNGReadContext context = { NULL, 0, 0 };
+ int color_type, bit_depth, interlaced;
+ int has_alpha;
+ int num_passes;
+ int p;
+ volatile int ok = 0;
+ png_uint_32 width, height, y;
+ int64_t stride;
+ uint8_t* volatile rgb = NULL;
+
+ if (data == NULL || data_size == 0 || pic == NULL) return 0;
+
+ context.data = data;
+ context.data_size = data_size;
+
+ png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
+ NULL, MallocFunc, FreeFunc);
+ if (png == NULL) goto End;
+
+ png_set_error_fn(png, 0, error_function, NULL);
+ if (setjmp(png_jmpbuf(png))) {
+ Error:
+ MetadataFree(metadata);
+ goto End;
+ }
+
+#if LOCAL_PNG_PREREQ(1,5) || \
+ (LOCAL_PNG_PREREQ(1,4) && PNG_LIBPNG_VER_RELEASE >= 1)
+ // If it looks like the bitstream is going to need more memory than libpng's
+ // internal limit (default: 8M), try to (reasonably) raise it.
+ if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
+ png_set_chunk_malloc_max(png, data_size);
+ }
+#endif
+
+ info = png_create_info_struct(png);
+ if (info == NULL) goto Error;
+ end_info = png_create_info_struct(png);
+ if (end_info == NULL) goto Error;
+
+ png_set_read_fn(png, &context, ReadFunc);
+ png_read_info(png, info);
+ if (!png_get_IHDR(png, info,
+ &width, &height, &bit_depth, &color_type, &interlaced,
+ NULL, NULL)) goto Error;
+
+ png_set_strip_16(png);
+ png_set_packing(png);
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ png_set_palette_to_rgb(png);
+ }
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ if (bit_depth < 8) {
+ png_set_expand_gray_1_2_4_to_8(png);
+ }
+ png_set_gray_to_rgb(png);
+ }
+ if (png_get_valid(png, info, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(png);
+ has_alpha = 1;
+ } else {
+ has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
+ }
+
+ // Apply gamma correction if needed.
+ {
+ double image_gamma = 1 / 2.2, screen_gamma = 2.2;
+ int srgb_intent;
+ if (png_get_sRGB(png, info, &srgb_intent) ||
+ png_get_gAMA(png, info, &image_gamma)) {
+ png_set_gamma(png, screen_gamma, image_gamma);
+ }
+ }
+
+ if (!keep_alpha) {
+ png_set_strip_alpha(png);
+ has_alpha = 0;
+ }
+
+ num_passes = png_set_interlace_handling(png);
+ png_read_update_info(png, info);
+
+ stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
+ if (stride != (int)stride ||
+ !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
+ goto Error;
+ }
+
+ rgb = (uint8_t*)malloc((size_t)stride * height);
+ if (rgb == NULL) goto Error;
+ for (p = 0; p < num_passes; ++p) {
+ png_bytep row = rgb;
+ for (y = 0; y < height; ++y) {
+ png_read_rows(png, &row, NULL, 1);
+ row += stride;
+ }
+ }
+ png_read_end(png, end_info);
+
+ if (metadata != NULL &&
+ !ExtractMetadataFromPNG(png, info, end_info, metadata)) {
+ fprintf(stderr, "Error extracting PNG metadata!\n");
+ goto Error;
+ }
+
+ pic->width = (int)width;
+ pic->height = (int)height;
+ ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride)
+ : WebPPictureImportRGB(pic, rgb, (int)stride);
+
+ if (!ok) {
+ goto Error;
+ }
+
+ End:
+ if (png != NULL) {
+ png_destroy_read_struct((png_structpp)&png,
+ (png_infopp)&info, (png_infopp)&end_info);
+ }
+ free(rgb);
+ return ok;
+}
+#else // !WEBP_HAVE_PNG
+int ReadPNG(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata) {
+ (void)data;
+ (void)data_size;
+ (void)pic;
+ (void)keep_alpha;
+ (void)metadata;
+ fprintf(stderr, "PNG support not compiled. Please install the libpng "
+ "development package before building.\n");
+ return 0;
+}
+#endif // WEBP_HAVE_PNG
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/pngdec.h b/imageio/pngdec.h
new file mode 100644
index 0000000..e0a6122
--- /dev/null
+++ b/imageio/pngdec.h
@@ -0,0 +1,37 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// PNG decode.
+
+#ifndef WEBP_IMAGEIO_PNGDEC_H_
+#define WEBP_IMAGEIO_PNGDEC_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+// Reads a PNG from 'data', returning the decoded output in 'pic'.
+// Output is RGBA or YUVA, depending on pic->use_argb value.
+// If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA
+// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
+// Returns true on success.
+int ReadPNG(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_PNGDEC_H_
diff --git a/imageio/pnmdec.c b/imageio/pnmdec.c
new file mode 100644
index 0000000..0d592c3
--- /dev/null
+++ b/imageio/pnmdec.c
@@ -0,0 +1,301 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// (limited) PNM decoder
+
+#include "./pnmdec.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "webp/encode.h"
+#include "./imageio_util.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+typedef enum {
+ WIDTH_FLAG = 1 << 0,
+ HEIGHT_FLAG = 1 << 1,
+ DEPTH_FLAG = 1 << 2,
+ MAXVAL_FLAG = 1 << 3,
+ TUPLE_FLAG = 1 << 4,
+ ALL_NEEDED_FLAGS = WIDTH_FLAG | HEIGHT_FLAG | DEPTH_FLAG | MAXVAL_FLAG
+} PNMFlags;
+
+typedef struct {
+ const uint8_t* data;
+ size_t data_size;
+ int width, height;
+ int bytes_per_px;
+ int depth; // 1 (grayscale), 2 (grayscale + alpha), 3 (rgb), 4 (rgba)
+ int max_value;
+ int type; // 5, 6 or 7
+ int seen_flags;
+} PNMInfo;
+
+// -----------------------------------------------------------------------------
+// PNM decoding
+
+#define MAX_LINE_SIZE 1024
+static const size_t kMinPNMHeaderSize = 3;
+
+static size_t ReadLine(const uint8_t* const data, size_t off, size_t data_size,
+ char out[MAX_LINE_SIZE + 1], size_t* const out_size) {
+ size_t i = 0;
+ *out_size = 0;
+ redo:
+ for (i = 0; i < MAX_LINE_SIZE && off < data_size; ++i) {
+ out[i] = data[off++];
+ if (out[i] == '\n') break;
+ }
+ if (off < data_size) {
+ if (i == 0) goto redo; // empty line
+ if (out[0] == '#') goto redo; // skip comment
+ }
+ out[i] = 0; // safety sentinel
+ *out_size = i;
+ return off;
+}
+
+static size_t FlagError(const char flag[]) {
+ fprintf(stderr, "PAM header error: flags '%s' already seen.\n", flag);
+ return 0;
+}
+
+// inspired from http://netpbm.sourceforge.net/doc/pam.html
+static size_t ReadPAMFields(PNMInfo* const info, size_t off) {
+ char out[MAX_LINE_SIZE + 1];
+ size_t out_size;
+ int tmp;
+ int expected_depth = -1;
+ assert(info != NULL);
+ while (1) {
+ off = ReadLine(info->data, off, info->data_size, out, &out_size);
+ if (off == 0) return 0;
+ if (sscanf(out, "WIDTH %d", &tmp) == 1) {
+ if (info->seen_flags & WIDTH_FLAG) return FlagError("WIDTH");
+ info->seen_flags |= WIDTH_FLAG;
+ info->width = tmp;
+ } else if (sscanf(out, "HEIGHT %d", &tmp) == 1) {
+ if (info->seen_flags & HEIGHT_FLAG) return FlagError("HEIGHT");
+ info->seen_flags |= HEIGHT_FLAG;
+ info->height = tmp;
+ } else if (sscanf(out, "DEPTH %d", &tmp) == 1) {
+ if (info->seen_flags & DEPTH_FLAG) return FlagError("DEPTH");
+ info->seen_flags |= DEPTH_FLAG;
+ info->depth = tmp;
+ } else if (sscanf(out, "MAXVAL %d", &tmp) == 1) {
+ if (info->seen_flags & MAXVAL_FLAG) return FlagError("MAXVAL");
+ info->seen_flags |= MAXVAL_FLAG;
+ info->max_value = tmp;
+ } else if (!strcmp(out, "TUPLTYPE RGB_ALPHA")) {
+ expected_depth = 4;
+ info->seen_flags |= TUPLE_FLAG;
+ } else if (!strcmp(out, "TUPLTYPE RGB")) {
+ expected_depth = 3;
+ info->seen_flags |= TUPLE_FLAG;
+ } else if (!strcmp(out, "TUPLTYPE GRAYSCALE_ALPHA")) {
+ expected_depth = 2;
+ info->seen_flags |= TUPLE_FLAG;
+ } else if (!strcmp(out, "TUPLTYPE GRAYSCALE")) {
+ expected_depth = 1;
+ info->seen_flags |= TUPLE_FLAG;
+ } else if (!strcmp(out, "ENDHDR")) {
+ break;
+ } else {
+ static const char kEllipsis[] = " ...";
+ const size_t kLen = strlen(kEllipsis) + 1; // +1 = trailing \0
+ int i;
+ if (out_size > 20) snprintf(out + 20 - kLen, kLen, kEllipsis);
+ for (i = 0; i < (int)strlen(out); ++i) {
+ // isprint() might trigger a "char-subscripts" warning if given a char.
+ if (!isprint((int)out[i])) out[i] = ' ';
+ }
+ fprintf(stderr, "PAM header error: unrecognized entry [%s]\n", out);
+ return 0;
+ }
+ }
+ if (!(info->seen_flags & ALL_NEEDED_FLAGS)) {
+ fprintf(stderr, "PAM header error: missing tags%s%s%s%s\n",
+ (info->seen_flags & WIDTH_FLAG) ? "" : " WIDTH",
+ (info->seen_flags & HEIGHT_FLAG) ? "" : " HEIGHT",
+ (info->seen_flags & DEPTH_FLAG) ? "" : " DEPTH",
+ (info->seen_flags & MAXVAL_FLAG) ? "" : " MAXVAL");
+ return 0;
+ }
+ if (expected_depth != -1 && info->depth != expected_depth) {
+ fprintf(stderr, "PAM header error: expected DEPTH %d but got DEPTH %d\n",
+ expected_depth, info->depth);
+ return 0;
+ }
+ return off;
+}
+
+static size_t ReadHeader(PNMInfo* const info) {
+ size_t off = 0;
+ char out[MAX_LINE_SIZE + 1];
+ size_t out_size;
+ if (info == NULL) return 0;
+ if (info->data == NULL || info->data_size < kMinPNMHeaderSize) return 0;
+
+ info->width = info->height = 0;
+ info->type = -1;
+ info->seen_flags = 0;
+ info->bytes_per_px = 0;
+ info->depth = 0;
+ info->max_value = 0;
+
+ off = ReadLine(info->data, off, info->data_size, out, &out_size);
+ if (off == 0 || sscanf(out, "P%d", &info->type) != 1) return 0;
+ if (info->type == 7) {
+ off = ReadPAMFields(info, off);
+ } else {
+ off = ReadLine(info->data, off, info->data_size, out, &out_size);
+ if (off == 0 || sscanf(out, "%d %d", &info->width, &info->height) != 2) {
+ return 0;
+ }
+ off = ReadLine(info->data, off, info->data_size, out, &out_size);
+ if (off == 0 || sscanf(out, "%d", &info->max_value) != 1) return 0;
+
+ // finish initializing missing fields
+ info->depth = (info->type == 5) ? 1 : 3;
+ }
+ // perform some basic numerical validation
+ if (info->width <= 0 || info->height <= 0 ||
+ info->type <= 0 || info->type >= 9 ||
+ info->depth <= 0 || info->depth > 4 ||
+ info->max_value <= 0 || info->max_value >= 65536) {
+ return 0;
+ }
+ info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1);
+ return off;
+}
+
+int ReadPNM(const uint8_t* const data, size_t data_size,
+ WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata) {
+ int ok = 0;
+ int i, j;
+ uint64_t stride, pixel_bytes, sample_size, depth;
+ uint8_t* rgb = NULL, *tmp_rgb;
+ size_t offset;
+ PNMInfo info;
+
+ info.data = data;
+ info.data_size = data_size;
+ offset = ReadHeader(&info);
+ if (offset == 0) {
+ fprintf(stderr, "Error parsing PNM header.\n");
+ goto End;
+ }
+
+ if (info.type < 5 || info.type > 7) {
+ fprintf(stderr, "Unsupported P%d PNM format.\n", info.type);
+ goto End;
+ }
+
+ // Some basic validations.
+ if (pic == NULL) goto End;
+ if (info.width > WEBP_MAX_DIMENSION || info.height > WEBP_MAX_DIMENSION) {
+ fprintf(stderr, "Invalid %dx%d dimension for PNM\n",
+ info.width, info.height);
+ goto End;
+ }
+
+ pixel_bytes = (uint64_t)info.width * info.height * info.bytes_per_px;
+ if (data_size < offset + pixel_bytes) {
+ fprintf(stderr, "Truncated PNM file (P%d).\n", info.type);
+ goto End;
+ }
+ sample_size = (info.max_value > 255) ? 2 : 1;
+ // final depth
+ depth = (info.depth == 1 || info.depth == 3 || !keep_alpha) ? 3 : 4;
+ stride = depth * info.width;
+ if (stride != (size_t)stride ||
+ !ImgIoUtilCheckSizeArgumentsOverflow(stride, info.height)) {
+ goto End;
+ }
+
+ rgb = (uint8_t*)malloc((size_t)stride * info.height);
+ if (rgb == NULL) goto End;
+
+ // Convert input.
+ // We only optimize for the sample_size=1, max_value=255, depth=1 case.
+ tmp_rgb = rgb;
+ for (j = 0; j < info.height; ++j) {
+ const uint8_t* in = data + offset;
+ offset += info.bytes_per_px * info.width;
+ assert(offset <= data_size);
+ if (info.max_value == 255 && info.depth >= 3) {
+ // RGB or RGBA
+ if (info.depth == 3 || keep_alpha) {
+ memcpy(tmp_rgb, in, info.depth * info.width * sizeof(*in));
+ } else {
+ assert(info.depth == 4 && !keep_alpha);
+ for (i = 0; i < info.width; ++i) {
+ tmp_rgb[3 * i + 0] = in[4 * i + 0];
+ tmp_rgb[3 * i + 1] = in[4 * i + 1];
+ tmp_rgb[3 * i + 2] = in[4 * i + 2];
+ }
+ }
+ } else {
+ // Unoptimized case, we need to handle non-trivial operations:
+ // * convert 16b to 8b (if max_value > 255)
+ // * rescale to [0..255] range (if max_value != 255)
+ // * drop the alpha channel (if keep_alpha is false)
+ const uint32_t round = info.max_value / 2;
+ int k = 0;
+ for (i = 0; i < info.width * info.depth; ++i) {
+ uint32_t v = (sample_size == 2) ? 256u * in[2 * i + 0] + in[2 * i + 1]
+ : in[i];
+ if (info.max_value != 255) v = (v * 255u + round) / info.max_value;
+ if (v > 255u) v = 255u;
+ if (info.depth > 2) {
+ if (!keep_alpha && info.depth == 4 && (i % 4) == 3) {
+ // skip alpha
+ } else {
+ tmp_rgb[k] = v;
+ k += 1;
+ }
+ } else if (info.depth == 1 || (i % 2) == 0) {
+ tmp_rgb[k + 0] = tmp_rgb[k + 1] = tmp_rgb[k + 2] = v;
+ k += 3;
+ } else if (keep_alpha && info.depth == 2) {
+ tmp_rgb[k] = v;
+ k += 1;
+ } else {
+ // skip alpha
+ }
+ }
+ }
+ tmp_rgb += stride;
+ }
+
+ // WebP conversion.
+ pic->width = info.width;
+ pic->height = info.height;
+ ok = (depth == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
+ : WebPPictureImportRGB(pic, rgb, (int)stride);
+ if (!ok) goto End;
+
+ ok = 1;
+ End:
+ free((void*)rgb);
+
+ (void)metadata;
+ (void)keep_alpha;
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/pnmdec.h b/imageio/pnmdec.h
new file mode 100644
index 0000000..c4d5823
--- /dev/null
+++ b/imageio/pnmdec.h
@@ -0,0 +1,37 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// partial PNM format decoder (ppm/pgm)
+
+#ifndef WEBP_IMAGEIO_PNMDEC_H_
+#define WEBP_IMAGEIO_PNMDEC_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+// Reads a PNM file from 'data', returning the decoded output in 'pic'.
+// The output is RGB or YUV depending on pic->use_argb value.
+// Returns true on success.
+// 'metadata' has no effect, but is kept for coherence with other signatures
+// for image readers.
+int ReadPNM(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_PNMDEC_H_
diff --git a/imageio/tiffdec.c b/imageio/tiffdec.c
new file mode 100644
index 0000000..d711fa4
--- /dev/null
+++ b/imageio/tiffdec.c
@@ -0,0 +1,293 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// TIFF decode.
+
+#include "./tiffdec.h"
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WEBP_HAVE_TIFF
+#include <tiffio.h>
+
+#include "webp/encode.h"
+#include "./imageio_util.h"
+#include "./metadata.h"
+
+static const struct {
+ ttag_t tag;
+ size_t storage_offset;
+} kTIFFMetadataMap[] = {
+ { TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) },
+ { TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) },
+ { 0, 0 },
+};
+
+// Returns true on success. The caller must use MetadataFree() on 'metadata' in
+// all cases.
+static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
+ int i;
+ toff_t exif_ifd_offset;
+
+ for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) {
+ MetadataPayload* const payload =
+ (MetadataPayload*)((uint8_t*)metadata +
+ kTIFFMetadataMap[i].storage_offset);
+ void* tag_data;
+ uint32_t tag_data_len;
+
+ if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
+ !MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
+ return 0;
+ }
+ }
+
+ // TODO(jzern): To extract the raw EXIF directory some parsing of it would be
+ // necessary to determine the overall size. In addition, value offsets in
+ // individual directory entries may need to be updated as, depending on the
+ // type, they are file based.
+ // Exif 2.2 Section 4.6.2 Tag Structure
+ // TIFF Revision 6.0 Part 1 Section 2 TIFF Structure #Image File Directory
+ if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &exif_ifd_offset)) {
+ fprintf(stderr, "Warning: EXIF extraction from TIFF is unsupported.\n");
+ }
+ return 1;
+}
+
+// Ad-hoc structure to supply read-from-memory functionalities.
+typedef struct {
+ const uint8_t* data;
+ toff_t size;
+ toff_t pos;
+} MyData;
+
+static int MyClose(thandle_t opaque) {
+ (void)opaque;
+ return 0;
+}
+
+static toff_t MySize(thandle_t opaque) {
+ const MyData* const my_data = (MyData*)opaque;
+ return my_data->size;
+}
+
+static toff_t MySeek(thandle_t opaque, toff_t offset, int whence) {
+ MyData* const my_data = (MyData*)opaque;
+ offset += (whence == SEEK_CUR) ? my_data->pos
+ : (whence == SEEK_SET) ? 0
+ : my_data->size;
+ if (offset > my_data->size) return (toff_t)-1;
+ my_data->pos = offset;
+ return offset;
+}
+
+static int MyMapFile(thandle_t opaque, void** base, toff_t* size) {
+ (void)opaque;
+ (void)base;
+ (void)size;
+ return 0;
+}
+static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) {
+ (void)opaque;
+ (void)base;
+ (void)size;
+}
+
+static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
+ MyData* const my_data = (MyData*)opaque;
+ if (my_data->pos + size > my_data->size) {
+ size = (tsize_t)(my_data->size - my_data->pos);
+ }
+ if (size > 0) {
+ memcpy(dst, my_data->data + my_data->pos, size);
+ my_data->pos += size;
+ }
+ return size;
+}
+
+// Unmultiply Argb data. Taken from dsp/alpha_processing
+// (we don't want to force a dependency to a libdspdec library).
+#define MFIX 24 // 24bit fixed-point arithmetic
+#define HALF ((1u << MFIX) >> 1)
+
+static uint32_t Unmult(uint8_t x, uint32_t mult) {
+ const uint32_t v = (x * mult + HALF) >> MFIX;
+ return (v > 255u) ? 255u : v;
+}
+
+static WEBP_INLINE uint32_t GetScale(uint32_t a) {
+ return (255u << MFIX) / a;
+}
+
+#undef MFIX
+#undef HALF
+
+static void MultARGBRow(uint8_t* ptr, int width) {
+ int x;
+ for (x = 0; x < width; ++x, ptr += 4) {
+ const uint32_t alpha = ptr[3];
+ if (alpha < 255) {
+ if (alpha == 0) { // alpha == 0
+ ptr[0] = ptr[1] = ptr[2] = 0;
+ } else {
+ const uint32_t scale = GetScale(alpha);
+ ptr[0] = Unmult(ptr[0], scale);
+ ptr[1] = Unmult(ptr[1], scale);
+ ptr[2] = Unmult(ptr[2], scale);
+ }
+ }
+ }
+}
+
+int ReadTIFF(const uint8_t* const data, size_t data_size,
+ WebPPicture* const pic, int keep_alpha,
+ Metadata* const metadata) {
+ MyData my_data = { data, (toff_t)data_size, 0 };
+ TIFF* tif;
+ uint32_t image_width, image_height, tile_width, tile_height;
+ uint64_t stride;
+ uint16_t samples_per_px = 0;
+ uint16_t extra_samples = 0;
+ uint16_t* extra_samples_ptr = NULL;
+ uint32_t* raster;
+ int64_t alloc_size;
+ int ok = 0;
+ tdir_t dircount;
+
+ if (data == NULL || data_size == 0 || data_size > INT_MAX || pic == NULL) {
+ return 0;
+ }
+
+ tif = TIFFClientOpen("Memory", "r", &my_data,
+ MyRead, MyRead, MySeek, MyClose,
+ MySize, MyMapFile, MyUnmapFile);
+ if (tif == NULL) {
+ fprintf(stderr, "Error! Cannot parse TIFF file\n");
+ return 0;
+ }
+
+ dircount = TIFFNumberOfDirectories(tif);
+ if (dircount > 1) {
+ fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
+ "Only the first will be used, %d will be ignored.\n",
+ dircount - 1);
+ }
+ if (!TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_px)) {
+ fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
+ goto End;
+ }
+ if (!(samples_per_px == 1 || samples_per_px == 3 || samples_per_px == 4)) {
+ goto End; // not supported
+ }
+
+ if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) &&
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) {
+ fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
+ goto End;
+ }
+ stride = (uint64_t)image_width * sizeof(*raster);
+ if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) {
+ fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n",
+ image_width, image_height);
+ goto End;
+ }
+
+ // According to spec, a tile can be bigger than the image. However it should
+ // be a multiple of 16 and not way too large, so check that it's not more
+ // than twice the image size, for dimensions above some arbitrary minimum
+ // 32. We also check that they respect WebP's dimension and memory limit.
+ // Note that a tile can be 6byte/px in some cases. Here we assume
+ // 4byte/px with sizeof(*raster), to be conservative.
+ if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) {
+ if ((tile_width > 32 && tile_width / 2 > image_width) ||
+ (tile_height > 32 && tile_height / 2 > image_height) ||
+ !ImgIoUtilCheckSizeArgumentsOverflow(
+ (uint64_t)tile_width * sizeof(*raster), tile_height)) {
+ fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n",
+ tile_width, tile_height);
+ goto End;
+ }
+ }
+
+ if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
+ &extra_samples, &extra_samples_ptr)) {
+ fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
+ goto End;
+ }
+
+ // _Tiffmalloc uses a signed type for size.
+ alloc_size = (int64_t)(stride * image_height);
+ if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
+
+ raster = (uint32_t*)_TIFFmalloc((tsize_t)alloc_size);
+ if (raster != NULL) {
+ if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
+ ORIENTATION_TOPLEFT, 1)) {
+ pic->width = image_width;
+ pic->height = image_height;
+ // TIFF data is ABGR
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, image_width * image_height);
+#endif
+ // if we have an alpha channel, we must un-multiply from rgbA to RGBA
+ if (extra_samples == 1 && extra_samples_ptr != NULL &&
+ extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) {
+ uint32_t y;
+ uint8_t* tmp = (uint8_t*)raster;
+ for (y = 0; y < image_height; ++y) {
+ MultARGBRow(tmp, image_width);
+ tmp += stride;
+ }
+ }
+ ok = keep_alpha
+ ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride)
+ : WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride);
+ }
+ _TIFFfree(raster);
+ } else {
+ fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
+ }
+
+ if (ok) {
+ if (metadata != NULL) {
+ ok = ExtractMetadataFromTIFF(tif, metadata);
+ if (!ok) {
+ fprintf(stderr, "Error extracting TIFF metadata!\n");
+ MetadataFree(metadata);
+ WebPPictureFree(pic);
+ }
+ }
+ }
+ End:
+ TIFFClose(tif);
+ return ok;
+}
+#else // !WEBP_HAVE_TIFF
+int ReadTIFF(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata) {
+ (void)data;
+ (void)data_size;
+ (void)pic;
+ (void)keep_alpha;
+ (void)metadata;
+ fprintf(stderr, "TIFF support not compiled. Please install the libtiff "
+ "development package before building.\n");
+ return 0;
+}
+#endif // WEBP_HAVE_TIFF
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/tiffdec.h b/imageio/tiffdec.h
new file mode 100644
index 0000000..0c8becc
--- /dev/null
+++ b/imageio/tiffdec.h
@@ -0,0 +1,37 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// TIFF decode.
+
+#ifndef WEBP_IMAGEIO_TIFFDEC_H_
+#define WEBP_IMAGEIO_TIFFDEC_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+// Reads a TIFF from 'data', returning the decoded output in 'pic'.
+// Output is RGBA or YUVA, depending on pic->use_argb value.
+// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
+// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
+// Returns true on success.
+int ReadTIFF(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_TIFFDEC_H_
diff --git a/imageio/webpdec.c b/imageio/webpdec.c
new file mode 100644
index 0000000..aed60e1
--- /dev/null
+++ b/imageio/webpdec.c
@@ -0,0 +1,244 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// WebP decode.
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "./webpdec.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "webp/decode.h"
+#include "webp/demux.h"
+#include "webp/encode.h"
+#include "../examples/unicode.h"
+#include "./imageio_util.h"
+#include "./metadata.h"
+
+//------------------------------------------------------------------------------
+// WebP decoding
+
+static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
+ "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
+ "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
+};
+
+static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
+ if (config->input.has_animation) {
+ fprintf(stderr,
+ "Error! Decoding of an animated WebP file is not supported.\n"
+ " Use webpmux to extract the individual frames or\n"
+ " vwebp to view this image.\n");
+ }
+}
+
+void PrintWebPError(const char* const in_file, int status) {
+ WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file);
+ fprintf(stderr, "Status: %d", status);
+ if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
+ fprintf(stderr, "(%s)", kStatusMessages[status]);
+ }
+ fprintf(stderr, "\n");
+}
+
+int LoadWebP(const char* const in_file,
+ const uint8_t** data, size_t* data_size,
+ WebPBitstreamFeatures* bitstream) {
+ VP8StatusCode status;
+ WebPBitstreamFeatures local_features;
+ if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
+
+ if (bitstream == NULL) {
+ bitstream = &local_features;
+ }
+
+ status = WebPGetFeatures(*data, *data_size, bitstream);
+ if (status != VP8_STATUS_OK) {
+ WebPFree((void*)*data);
+ *data = NULL;
+ *data_size = 0;
+ PrintWebPError(in_file, status);
+ return 0;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
+ WebPDecoderConfig* const config) {
+ if (config == NULL) return VP8_STATUS_INVALID_PARAM;
+ PrintAnimationWarning(config);
+ return WebPDecode(data, data_size, config);
+}
+
+VP8StatusCode DecodeWebPIncremental(
+ const uint8_t* const data, size_t data_size,
+ WebPDecoderConfig* const config) {
+ VP8StatusCode status = VP8_STATUS_OK;
+ if (config == NULL) return VP8_STATUS_INVALID_PARAM;
+
+ PrintAnimationWarning(config);
+
+ // Decoding call.
+ {
+ WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
+ if (idec == NULL) {
+ fprintf(stderr, "Failed during WebPIDecode().\n");
+ return VP8_STATUS_OUT_OF_MEMORY;
+ } else {
+ status = WebPIUpdate(idec, data, data_size);
+ WebPIDelete(idec);
+ }
+ }
+ return status;
+}
+
+// -----------------------------------------------------------------------------
+// Metadata
+
+static int ExtractMetadata(const uint8_t* const data, size_t data_size,
+ Metadata* const metadata) {
+ WebPData webp_data = { data, data_size };
+ WebPDemuxer* const demux = WebPDemux(&webp_data);
+ WebPChunkIterator chunk_iter;
+ uint32_t flags;
+
+ if (demux == NULL) return 0;
+ assert(metadata != NULL);
+
+ flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
+
+ if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
+ MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
+ &metadata->iccp);
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ }
+ if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
+ MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
+ &metadata->exif);
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ }
+ if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
+ MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
+ &metadata->xmp);
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ }
+ WebPDemuxDelete(demux);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+int ReadWebP(const uint8_t* const data, size_t data_size,
+ WebPPicture* const pic,
+ int keep_alpha, Metadata* const metadata) {
+ int ok = 0;
+ VP8StatusCode status = VP8_STATUS_OK;
+ WebPDecoderConfig config;
+ WebPDecBuffer* const output_buffer = &config.output;
+ WebPBitstreamFeatures* const bitstream = &config.input;
+
+ if (data == NULL || data_size == 0 || pic == NULL) return 0;
+
+ if (!WebPInitDecoderConfig(&config)) {
+ fprintf(stderr, "Library version mismatch!\n");
+ return 0;
+ }
+
+ status = WebPGetFeatures(data, data_size, bitstream);
+ if (status != VP8_STATUS_OK) {
+ PrintWebPError("input data", status);
+ return 0;
+ }
+
+ do {
+ const int has_alpha = keep_alpha && bitstream->has_alpha;
+ uint64_t stride;
+ pic->width = bitstream->width;
+ pic->height = bitstream->height;
+ if (pic->use_argb) {
+ stride = (uint64_t)bitstream->width * 4;
+ } else {
+ stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
+ pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
+ }
+
+ if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
+ status = VP8_STATUS_OUT_OF_MEMORY;
+ break;
+ }
+
+ ok = WebPPictureAlloc(pic);
+ if (!ok) {
+ status = VP8_STATUS_OUT_OF_MEMORY;
+ break;
+ }
+ if (pic->use_argb) {
+#ifdef WORDS_BIGENDIAN
+ output_buffer->colorspace = MODE_ARGB;
+#else
+ output_buffer->colorspace = MODE_BGRA;
+#endif
+ output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
+ output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
+ output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
+ } else {
+ output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
+ output_buffer->u.YUVA.y = pic->y;
+ output_buffer->u.YUVA.u = pic->u;
+ output_buffer->u.YUVA.v = pic->v;
+ output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL;
+ output_buffer->u.YUVA.y_stride = pic->y_stride;
+ output_buffer->u.YUVA.u_stride = pic->uv_stride;
+ output_buffer->u.YUVA.v_stride = pic->uv_stride;
+ output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0;
+ output_buffer->u.YUVA.y_size = pic->height * pic->y_stride;
+ output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride;
+ output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride;
+ output_buffer->u.YUVA.a_size = pic->height * pic->a_stride;
+ }
+ output_buffer->is_external_memory = 1;
+
+ status = DecodeWebP(data, data_size, &config);
+ ok = (status == VP8_STATUS_OK);
+ if (ok && !keep_alpha && pic->use_argb) {
+ // Need to wipe out the alpha value, as requested.
+ int x, y;
+ uint32_t* argb = pic->argb;
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
+ argb += pic->argb_stride;
+ }
+ }
+ } while (0); // <- so we can 'break' out of the loop
+
+ if (status != VP8_STATUS_OK) {
+ PrintWebPError("input data", status);
+ ok = 0;
+ }
+
+ WebPFreeDecBuffer(output_buffer);
+
+ if (ok && metadata != NULL) {
+ ok = ExtractMetadata(data, data_size, metadata);
+ if (!ok) {
+ PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
+ }
+ }
+ if (!ok) WebPPictureFree(pic);
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/webpdec.h b/imageio/webpdec.h
new file mode 100644
index 0000000..d329d41
--- /dev/null
+++ b/imageio/webpdec.h
@@ -0,0 +1,67 @@
+// 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.
+// -----------------------------------------------------------------------------
+//
+// WebP decode.
+
+#ifndef WEBP_IMAGEIO_WEBPDEC_H_
+#define WEBP_IMAGEIO_WEBPDEC_H_
+
+#include "webp/decode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+//------------------------------------------------------------------------------
+// WebP decoding
+
+// Prints an informative error message regarding decode failure of 'in_file'.
+// 'status' is treated as a VP8StatusCode and if valid will be printed as a
+// text string.
+void PrintWebPError(const char* const in_file, int status);
+
+// Reads a WebP from 'in_file', returning the contents and size in 'data' and
+// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures().
+// Returns true on success.
+int LoadWebP(const char* const in_file,
+ const uint8_t** data, size_t* data_size,
+ WebPBitstreamFeatures* bitstream);
+
+// Decodes the WebP contained in 'data'.
+// 'config' is a structure previously initialized by WebPInitDecoderConfig().
+// 'config->output' should have the desired colorspace selected.
+// Returns the decoder status. On success 'config->output' will contain the
+// decoded picture.
+VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
+ WebPDecoderConfig* const config);
+
+// Same as DecodeWebP(), but using the incremental decoder.
+VP8StatusCode DecodeWebPIncremental(
+ const uint8_t* const data, size_t data_size,
+ WebPDecoderConfig* const config);
+
+//------------------------------------------------------------------------------
+
+// Decodes a WebP contained in 'data', returning the decoded output in 'pic'.
+// Output is RGBA or YUVA, depending on pic->use_argb value.
+// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
+// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
+// Returns true on success.
+int ReadWebP(const uint8_t* const data, size_t data_size,
+ struct WebPPicture* const pic,
+ int keep_alpha, struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_WEBPDEC_H_
diff --git a/imageio/wicdec.c b/imageio/wicdec.c
new file mode 100644
index 0000000..42001c6
--- /dev/null
+++ b/imageio/wicdec.c
@@ -0,0 +1,413 @@
+// Copyright 2013 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.
+// -----------------------------------------------------------------------------
+//
+// Windows Imaging Component (WIC) decode.
+
+#include "./wicdec.h"
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_WINCODEC_H
+#ifdef __MINGW32__
+#define INITGUID // Without this GUIDs are declared extern and fail to link
+#endif
+#define CINTERFACE
+#define COBJMACROS
+#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
+ // code with COBJMACROS.
+#include <ole2.h> // CreateStreamOnHGlobal()
+#include <shlwapi.h>
+#include <tchar.h>
+#include <windows.h>
+#include <wincodec.h>
+
+#include "../examples/unicode.h"
+#include "./imageio_util.h"
+#include "./metadata.h"
+#include "webp/encode.h"
+
+#define IFS(fn) \
+ do { \
+ if (SUCCEEDED(hr)) { \
+ hr = (fn); \
+ if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
+ } \
+ } while (0)
+
+// modified version of DEFINE_GUID from guiddef.h.
+#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ static const GUID name = \
+ { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+
+#ifdef __cplusplus
+#define MAKE_REFGUID(x) (x)
+#else
+#define MAKE_REFGUID(x) &(x)
+#endif
+
+typedef struct WICFormatImporter {
+ const GUID* pixel_format;
+ int bytes_per_pixel;
+ int (*import)(WebPPicture* const, const uint8_t* const, int);
+} WICFormatImporter;
+
+// From Microsoft SDK 7.0a -- wincodec.h
+// Create local copies for compatibility when building against earlier
+// versions of the SDK.
+WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_,
+ 0x6fddc324, 0x4e03, 0x4bfe,
+ 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
+WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
+ 0x6fddc324, 0x4e03, 0x4bfe,
+ 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
+WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
+ 0x6fddc324, 0x4e03, 0x4bfe,
+ 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
+WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
+ 0xf5c7ad2d, 0x6a8d, 0x43dd,
+ 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
+WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppBGRA_,
+ 0x1562ff7c, 0xd352, 0x46f9,
+ 0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
+WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
+ 0x6fddc324, 0x4e03, 0x4bfe,
+ 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
+
+static HRESULT OpenInputStream(const char* filename, IStream** stream) {
+ HRESULT hr = S_OK;
+ if (!WSTRCMP(filename, "-")) {
+ const uint8_t* data = NULL;
+ size_t data_size = 0;
+ const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
+ if (ok) {
+ HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
+ if (image != NULL) {
+ void* const image_mem = GlobalLock(image);
+ if (image_mem != NULL) {
+ memcpy(image_mem, data, data_size);
+ GlobalUnlock(image);
+ IFS(CreateStreamOnHGlobal(image, TRUE, stream));
+ } else {
+ hr = E_FAIL;
+ }
+ } else {
+ hr = E_OUTOFMEMORY;
+ }
+ free((void*)data);
+ } else {
+ hr = E_FAIL;
+ }
+ } else {
+ IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream));
+ }
+
+ if (FAILED(hr)) {
+ _ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"),
+ (const LPTSTR)filename, hr);
+ }
+ return hr;
+}
+
+// -----------------------------------------------------------------------------
+// Metadata processing
+
+// Stores the first non-zero sized color profile from 'frame' to 'iccp'.
+// Returns an HRESULT to indicate success or failure. The caller is responsible
+// for freeing 'iccp->bytes' in either case.
+static HRESULT ExtractICCP(IWICImagingFactory* const factory,
+ IWICBitmapFrameDecode* const frame,
+ MetadataPayload* const iccp) {
+ HRESULT hr = S_OK;
+ UINT i, count;
+ IWICColorContext** color_contexts;
+
+ IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
+ if (FAILED(hr) || count == 0) {
+ // Treat unsupported operation as a non-fatal error. See crbug.com/webp/506.
+ return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr;
+ }
+
+ color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
+ if (color_contexts == NULL) return E_OUTOFMEMORY;
+ for (i = 0; SUCCEEDED(hr) && i < count; ++i) {
+ IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i]));
+ }
+
+ if (SUCCEEDED(hr)) {
+ UINT num_color_contexts;
+ IFS(IWICBitmapFrameDecode_GetColorContexts(frame,
+ count, color_contexts,
+ &num_color_contexts));
+ assert(FAILED(hr) || num_color_contexts <= count);
+ for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
+ WICColorContextType type;
+ IFS(IWICColorContext_GetType(color_contexts[i], &type));
+ if (SUCCEEDED(hr) && type == WICColorContextProfile) {
+ UINT size;
+ IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
+ 0, NULL, &size));
+ if (SUCCEEDED(hr) && size > 0) {
+ iccp->bytes = (uint8_t*)malloc(size);
+ if (iccp->bytes == NULL) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ iccp->size = size;
+ IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
+ (UINT)iccp->size, iccp->bytes,
+ &size));
+ if (SUCCEEDED(hr) && size != iccp->size) {
+ fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n",
+ size, (uint32_t)iccp->size);
+ iccp->size = size;
+ }
+ break;
+ }
+ }
+ }
+ }
+ for (i = 0; i < count; ++i) {
+ if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]);
+ }
+ free(color_contexts);
+ return hr;
+}
+
+static HRESULT ExtractMetadata(IWICImagingFactory* const factory,
+ IWICBitmapFrameDecode* const frame,
+ Metadata* const metadata) {
+ // TODO(jzern): add XMP/EXIF extraction.
+ const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp);
+ if (FAILED(hr)) MetadataFree(metadata);
+ return hr;
+}
+
+// -----------------------------------------------------------------------------
+
+static int HasPalette(GUID pixel_format) {
+ return (IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed)));
+}
+
+static int HasAlpha(IWICImagingFactory* const factory,
+ IWICBitmapDecoder* const decoder,
+ IWICBitmapFrameDecode* const frame,
+ GUID pixel_format) {
+ int has_alpha;
+ if (HasPalette(pixel_format)) {
+ IWICPalette* frame_palette = NULL;
+ IWICPalette* global_palette = NULL;
+ BOOL frame_palette_has_alpha = FALSE;
+ BOOL global_palette_has_alpha = FALSE;
+
+ // A palette may exist at the frame or container level,
+ // check IWICPalette::HasAlpha() for both if present.
+ if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) &&
+ SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) {
+ IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha);
+ }
+ if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) &&
+ SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) {
+ IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha);
+ }
+ has_alpha = frame_palette_has_alpha || global_palette_has_alpha;
+
+ if (frame_palette != NULL) IUnknown_Release(frame_palette);
+ if (global_palette != NULL) IUnknown_Release(global_palette);
+ } else {
+ has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat64bppRGBA_)) ||
+ IsEqualGUID(MAKE_REFGUID(pixel_format),
+ MAKE_REFGUID(GUID_WICPixelFormat64bppBGRA_));
+ }
+ return has_alpha;
+}
+
+int ReadPictureWithWIC(const char* const filename,
+ WebPPicture* const pic, int keep_alpha,
+ Metadata* const metadata) {
+ // From Microsoft SDK 6.0a -- ks.h
+ // Define a local copy to avoid link errors under mingw.
+ WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ static const WICFormatImporter kAlphaFormatImporters[] = {
+ { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA },
+ { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA },
+ { NULL, 0, NULL },
+ };
+ static const WICFormatImporter kNonAlphaFormatImporters[] = {
+ { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR },
+ { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB },
+ { NULL, 0, NULL },
+ };
+ HRESULT hr = S_OK;
+ IWICBitmapFrameDecode* frame = NULL;
+ IWICFormatConverter* converter = NULL;
+ IWICImagingFactory* factory = NULL;
+ IWICBitmapDecoder* decoder = NULL;
+ IStream* stream = NULL;
+ UINT frame_count = 0;
+ UINT width = 0, height = 0;
+ BYTE* rgb = NULL;
+ WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
+ const WICFormatImporter* importer = NULL;
+ GUID src_container_format = GUID_NULL_;
+ // From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h
+ WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_,
+ 0xe094b0e2, 0x67f2, 0x45b3,
+ 0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3);
+ static const GUID* kAlphaContainers[] = {
+ &GUID_ContainerFormatBmp,
+ &GUID_ContainerFormatPng,
+ &GUID_ContainerFormatTiff,
+ &GUID_ContainerFormatWebp_,
+ NULL
+ };
+ int has_alpha = 0;
+ int64_t stride;
+
+ if (filename == NULL || pic == NULL) return 0;
+
+ IFS(CoInitialize(NULL));
+ IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
+ CLSCTX_INPROC_SERVER,
+ MAKE_REFGUID(IID_IWICImagingFactory),
+ (LPVOID*)&factory));
+ if (hr == REGDB_E_CLASSNOTREG) {
+ fprintf(stderr,
+ "Couldn't access Windows Imaging Component (are you running "
+ "Windows XP SP3 or newer?). Most formats not available. "
+ "Use -s for the available YUV input.\n");
+ }
+ // Prepare for image decoding.
+ IFS(OpenInputStream(filename, &stream));
+ IFS(IWICImagingFactory_CreateDecoderFromStream(
+ factory, stream, NULL,
+ WICDecodeMetadataCacheOnDemand, &decoder));
+ IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
+ if (SUCCEEDED(hr)) {
+ if (frame_count == 0) {
+ fprintf(stderr, "No frame found in input file.\n");
+ hr = E_FAIL;
+ } else if (frame_count > 1) {
+ // WIC will be tried before native WebP decoding so avoid duplicating the
+ // error message.
+ hr = E_FAIL;
+ }
+ }
+ IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
+ IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
+ IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format));
+
+ if (SUCCEEDED(hr) && keep_alpha) {
+ const GUID** guid;
+ for (guid = kAlphaContainers; *guid != NULL; ++guid) {
+ if (IsEqualGUID(MAKE_REFGUID(src_container_format),
+ MAKE_REFGUID(**guid))) {
+ has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format);
+ break;
+ }
+ }
+ }
+
+ // Prepare for pixel format conversion (if necessary).
+ IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter));
+
+ for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters;
+ hr == S_OK && importer->import != NULL; ++importer) {
+ BOOL can_convert;
+ const HRESULT cchr = IWICFormatConverter_CanConvert(
+ converter,
+ MAKE_REFGUID(src_pixel_format),
+ MAKE_REFGUID(*importer->pixel_format),
+ &can_convert);
+ if (SUCCEEDED(cchr) && can_convert) break;
+ }
+ if (importer->import == NULL) hr = E_FAIL;
+
+ IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame,
+ importer->pixel_format,
+ WICBitmapDitherTypeNone,
+ NULL, 0.0, WICBitmapPaletteTypeCustom));
+
+ // Decode.
+ IFS(IWICFormatConverter_GetSize(converter, &width, &height));
+ stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb);
+ if (stride != (int)stride ||
+ !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr)) {
+ rgb = (BYTE*)malloc((size_t)stride * height);
+ if (rgb == NULL)
+ hr = E_OUTOFMEMORY;
+ }
+ IFS(IWICFormatConverter_CopyPixels(converter, NULL,
+ (UINT)stride, (UINT)stride * height, rgb));
+
+ // WebP conversion.
+ if (SUCCEEDED(hr)) {
+ int ok;
+ pic->width = width;
+ pic->height = height;
+ pic->use_argb = 1; // For WIC, we always force to argb
+ ok = importer->import(pic, rgb, (int)stride);
+ if (!ok) hr = E_FAIL;
+ }
+ if (SUCCEEDED(hr)) {
+ if (metadata != NULL) {
+ hr = ExtractMetadata(factory, frame, metadata);
+ if (FAILED(hr)) {
+ fprintf(stderr, "Error extracting image metadata using WIC!\n");
+ }
+ }
+ }
+
+ // Cleanup.
+ if (converter != NULL) IUnknown_Release(converter);
+ if (frame != NULL) IUnknown_Release(frame);
+ if (decoder != NULL) IUnknown_Release(decoder);
+ if (factory != NULL) IUnknown_Release(factory);
+ if (stream != NULL) IUnknown_Release(stream);
+ free(rgb);
+ return SUCCEEDED(hr);
+}
+#else // !HAVE_WINCODEC_H
+int ReadPictureWithWIC(const char* const filename,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata) {
+ (void)filename;
+ (void)pic;
+ (void)keep_alpha;
+ (void)metadata;
+ fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. "
+ "Visual Studio and mingw-w64 builds support WIC. Make sure "
+ "wincodec.h detection is working correctly if using autoconf "
+ "and HAVE_WINCODEC_H is defined before building.\n");
+ return 0;
+}
+#endif // HAVE_WINCODEC_H
+
+// -----------------------------------------------------------------------------
diff --git a/imageio/wicdec.h b/imageio/wicdec.h
new file mode 100644
index 0000000..d9eeca8
--- /dev/null
+++ b/imageio/wicdec.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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.
+// -----------------------------------------------------------------------------
+//
+// Windows Imaging Component (WIC) decode.
+
+#ifndef WEBP_IMAGEIO_WICDEC_H_
+#define WEBP_IMAGEIO_WICDEC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Metadata;
+struct WebPPicture;
+
+// Reads an image from 'filename', returning the decoded output in 'pic'.
+// If 'keep_alpha' is true and the image has an alpha channel, the output is
+// RGBA otherwise it will be RGB. pic->use_argb is always forced to true.
+// Returns true on success.
+int ReadPictureWithWIC(const char* const filename,
+ struct WebPPicture* const pic, int keep_alpha,
+ struct Metadata* const metadata);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_IMAGEIO_WICDEC_H_
diff --git a/include/webp/decode.h b/include/webp/decode.h
deleted file mode 100644
index d982475..0000000
--- a/include/webp/decode.h
+++ /dev/null
@@ -1,503 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Main decoding functions for WebP images.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_WEBP_DECODE_H_
-#define WEBP_WEBP_DECODE_H_
-
-#include "./types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b)
-
-// Note: forward declaring enumerations is not allowed in (strict) C and C++,
-// the types are left here for reference.
-// typedef enum VP8StatusCode VP8StatusCode;
-// typedef enum WEBP_CSP_MODE WEBP_CSP_MODE;
-typedef struct WebPRGBABuffer WebPRGBABuffer;
-typedef struct WebPYUVABuffer WebPYUVABuffer;
-typedef struct WebPDecBuffer WebPDecBuffer;
-typedef struct WebPIDecoder WebPIDecoder;
-typedef struct WebPBitstreamFeatures WebPBitstreamFeatures;
-typedef struct WebPDecoderOptions WebPDecoderOptions;
-typedef struct WebPDecoderConfig WebPDecoderConfig;
-
-// Return the decoder's version number, packed in hexadecimal using 8bits for
-// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN int WebPGetDecoderVersion(void);
-
-// Retrieve basic header information: width, height.
-// This function will also validate the header, returning true on success,
-// false otherwise. '*width' and '*height' are only valid on successful return.
-// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
-// Note: The following chunk sequences (before the raw VP8/VP8L data) are
-// considered valid by this function:
-// RIFF + VP8(L)
-// RIFF + VP8X + (optional chunks) + VP8(L)
-// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
-// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
-WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
-// with the dimensions in *width and *height. The ordering of samples in
-// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
-// The returned pointer should be deleted calling WebPFree().
-// Returns NULL in case of error.
-WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
-// If the bitstream contains transparency, it is ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
-
-// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
-// returned is the Y samples buffer. Upon return, *u and *v will point to
-// the U and V chroma data. These U and V buffers need NOT be passed to
-// WebPFree(), unlike the returned Y luma one. The dimension of the U and V
-// planes are both (*width + 1) / 2 and (*height + 1)/ 2.
-// Upon return, the Y buffer has a stride returned as '*stride', while U and V
-// have a common stride returned as '*uv_stride'.
-// Return NULL in case of error.
-// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
-WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
- int* width, int* height,
- uint8_t** u, uint8_t** v,
- int* stride, int* uv_stride);
-
-// These five functions are variants of the above ones, that decode the image
-// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
-// available in this buffer is indicated by 'output_buffer_size'. If this
-// storage is not sufficient (or an error occurred), NULL is returned.
-// Otherwise, output_buffer is returned, for convenience.
-// The parameter 'output_stride' specifies the distance (in bytes)
-// between scanlines. Hence, output_buffer_size is expected to be at least
-// output_stride x picture-height.
-WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
- const uint8_t* data, size_t data_size,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
- const uint8_t* data, size_t data_size,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
- const uint8_t* data, size_t data_size,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-
-// RGB and BGR variants. Here too the transparency information, if present,
-// will be dropped and ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
- const uint8_t* data, size_t data_size,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
- const uint8_t* data, size_t data_size,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-
-// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
-// into pre-allocated luma/chroma plane buffers. This function requires the
-// strides to be passed: one for the luma plane and one for each of the
-// chroma ones. The size of each plane buffer is passed as 'luma_size',
-// 'u_size' and 'v_size' respectively.
-// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
-// during decoding (or because some buffers were found to be too small).
-WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
- const uint8_t* data, size_t data_size,
- uint8_t* luma, size_t luma_size, int luma_stride,
- uint8_t* u, size_t u_size, int u_stride,
- uint8_t* v, size_t v_size, int v_stride);
-
-//------------------------------------------------------------------------------
-// Output colorspaces and buffer
-
-// Colorspaces
-// Note: the naming describes the byte-ordering of packed samples in memory.
-// For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,...
-// Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels.
-// RGBA-4444 and RGB-565 colorspaces are represented by following byte-order:
-// RGBA-4444: [r3 r2 r1 r0 g3 g2 g1 g0], [b3 b2 b1 b0 a3 a2 a1 a0], ...
-// RGB-565: [r4 r3 r2 r1 r0 g5 g4 g3], [g2 g1 g0 b4 b3 b2 b1 b0], ...
-// In the case WEBP_SWAP_16BITS_CSP is defined, the bytes are swapped for
-// these two modes:
-// RGBA-4444: [b3 b2 b1 b0 a3 a2 a1 a0], [r3 r2 r1 r0 g3 g2 g1 g0], ...
-// RGB-565: [g2 g1 g0 b4 b3 b2 b1 b0], [r4 r3 r2 r1 r0 g5 g4 g3], ...
-
-typedef enum WEBP_CSP_MODE {
- MODE_RGB = 0, MODE_RGBA = 1,
- MODE_BGR = 2, MODE_BGRA = 3,
- MODE_ARGB = 4, MODE_RGBA_4444 = 5,
- MODE_RGB_565 = 6,
- // RGB-premultiplied transparent modes (alpha value is preserved)
- MODE_rgbA = 7,
- MODE_bgrA = 8,
- MODE_Argb = 9,
- MODE_rgbA_4444 = 10,
- // YUV modes must come after RGB ones.
- MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0
- MODE_LAST = 13
-} WEBP_CSP_MODE;
-
-// Some useful macros:
-static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) {
- return (mode == MODE_rgbA || mode == MODE_bgrA || mode == MODE_Argb ||
- mode == MODE_rgbA_4444);
-}
-
-static WEBP_INLINE int WebPIsAlphaMode(WEBP_CSP_MODE mode) {
- return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
- mode == MODE_RGBA_4444 || mode == MODE_YUVA ||
- WebPIsPremultipliedMode(mode));
-}
-
-static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) {
- return (mode < MODE_YUV);
-}
-
-//------------------------------------------------------------------------------
-// WebPDecBuffer: Generic structure for describing the output sample buffer.
-
-struct WebPRGBABuffer { // view as RGBA
- uint8_t* rgba; // pointer to RGBA samples
- int stride; // stride in bytes from one scanline to the next.
- size_t size; // total size of the *rgba buffer.
-};
-
-struct WebPYUVABuffer { // view as YUVA
- uint8_t* y, *u, *v, *a; // pointer to luma, chroma U/V, alpha samples
- int y_stride; // luma stride
- int u_stride, v_stride; // chroma strides
- int a_stride; // alpha stride
- size_t y_size; // luma plane size
- size_t u_size, v_size; // chroma planes size
- size_t a_size; // alpha-plane size
-};
-
-// Output buffer
-struct WebPDecBuffer {
- WEBP_CSP_MODE colorspace; // Colorspace.
- int width, height; // Dimensions.
- int is_external_memory; // If non-zero, 'internal_memory' pointer is not
- // used. If value is '2' or more, the external
- // memory is considered 'slow' and multiple
- // read/write will be avoided.
- union {
- WebPRGBABuffer RGBA;
- WebPYUVABuffer YUVA;
- } u; // Nameless union of buffer parameters.
- uint32_t pad[4]; // padding for later use
-
- uint8_t* private_memory; // Internally allocated memory (only when
- // is_external_memory is 0). Should not be used
- // externally, but accessed via the buffer union.
-};
-
-// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
-
-// Initialize the structure as empty. Must be called before any other use.
-// Returns false in case of version mismatch
-static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
- return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION);
-}
-
-// Free any memory associated with the buffer. Must always be called last.
-// Note: doesn't free the 'buffer' structure itself.
-WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
-
-//------------------------------------------------------------------------------
-// Enumeration of the status codes
-
-typedef enum VP8StatusCode {
- VP8_STATUS_OK = 0,
- VP8_STATUS_OUT_OF_MEMORY,
- VP8_STATUS_INVALID_PARAM,
- VP8_STATUS_BITSTREAM_ERROR,
- VP8_STATUS_UNSUPPORTED_FEATURE,
- VP8_STATUS_SUSPENDED,
- VP8_STATUS_USER_ABORT,
- VP8_STATUS_NOT_ENOUGH_DATA
-} VP8StatusCode;
-
-//------------------------------------------------------------------------------
-// Incremental decoding
-//
-// This API allows streamlined decoding of partial data.
-// Picture can be incrementally decoded as data become available thanks to the
-// WebPIDecoder object. This object can be left in a SUSPENDED state if the
-// picture is only partially decoded, pending additional input.
-// Code example:
-//
-// WebPInitDecBuffer(&output_buffer);
-// output_buffer.colorspace = mode;
-// ...
-// WebPIDecoder* idec = WebPINewDecoder(&output_buffer);
-// while (additional_data_is_available) {
-// // ... (get additional data in some new_data[] buffer)
-// status = WebPIAppend(idec, new_data, new_data_size);
-// if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
-// break; // an error occurred.
-// }
-//
-// // The above call decodes the current available buffer.
-// // Part of the image can now be refreshed by calling
-// // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
-// }
-// WebPIDelete(idec);
-
-// Creates a new incremental decoder with the supplied buffer parameter.
-// This output_buffer can be passed NULL, in which case a default output buffer
-// is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer'
-// is kept, which means that the lifespan of 'output_buffer' must be larger than
-// that of the returned WebPIDecoder object.
-// The supplied 'output_buffer' content MUST NOT be changed between calls to
-// WebPIAppend() or WebPIUpdate() unless 'output_buffer.is_external_memory' is
-// not set to 0. In such a case, it is allowed to modify the pointers, size and
-// stride of output_buffer.u.RGBA or output_buffer.u.YUVA, provided they remain
-// within valid bounds.
-// All other fields of WebPDecBuffer MUST remain constant between calls.
-// Returns NULL if the allocation failed.
-WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
-
-// This function allocates and initializes an incremental-decoder object, which
-// will output the RGB/A samples specified by 'csp' into a preallocated
-// buffer 'output_buffer'. The size of this buffer is at least
-// 'output_buffer_size' and the stride (distance in bytes between two scanlines)
-// is specified by 'output_stride'.
-// Additionally, output_buffer can be passed NULL in which case the output
-// buffer will be allocated automatically when the decoding starts. The
-// colorspace 'csp' is taken into account for allocating this buffer. All other
-// parameters are ignored.
-// Returns NULL if the allocation failed, or if some parameters are invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewRGB(
- WEBP_CSP_MODE csp,
- uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-
-// This function allocates and initializes an incremental-decoder object, which
-// will output the raw luma/chroma samples into a preallocated planes if
-// supplied. The luma plane is specified by its pointer 'luma', its size
-// 'luma_size' and its stride 'luma_stride'. Similarly, the chroma-u plane
-// is specified by the 'u', 'u_size' and 'u_stride' parameters, and the chroma-v
-// plane by 'v' and 'v_size'. And same for the alpha-plane. The 'a' pointer
-// can be pass NULL in case one is not interested in the transparency plane.
-// Conversely, 'luma' can be passed NULL if no preallocated planes are supplied.
-// In this case, the output buffer will be automatically allocated (using
-// MODE_YUVA) when decoding starts. All parameters are then ignored.
-// Returns NULL if the allocation failed or if a parameter is invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
- uint8_t* luma, size_t luma_size, int luma_stride,
- uint8_t* u, size_t u_size, int u_stride,
- uint8_t* v, size_t v_size, int v_stride,
- uint8_t* a, size_t a_size, int a_stride);
-
-// Deprecated version of the above, without the alpha plane.
-// Kept for backward compatibility.
-WEBP_EXTERN WebPIDecoder* WebPINewYUV(
- uint8_t* luma, size_t luma_size, int luma_stride,
- uint8_t* u, size_t u_size, int u_stride,
- uint8_t* v, size_t v_size, int v_stride);
-
-// Deletes the WebPIDecoder object and associated memory. Must always be called
-// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
-WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec);
-
-// Copies and decodes the next available data. Returns VP8_STATUS_OK when
-// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
-// data is expected. Returns error in other cases.
-WEBP_EXTERN VP8StatusCode WebPIAppend(
- WebPIDecoder* idec, const uint8_t* data, size_t data_size);
-
-// A variant of the above function to be used when data buffer contains
-// partial data from the beginning. In this case data buffer is not copied
-// to the internal memory.
-// Note that the value of the 'data' pointer can change between calls to
-// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
-WEBP_EXTERN VP8StatusCode WebPIUpdate(
- WebPIDecoder* idec, const uint8_t* data, size_t data_size);
-
-// Returns the RGB/A image decoded so far. Returns NULL if output params
-// are not initialized yet. The RGB/A output type corresponds to the colorspace
-// specified during call to WebPINewDecoder() or WebPINewRGB().
-// *last_y is the index of last decoded row in raster scan order. Some pointers
-// (*last_y, *width etc.) can be NULL if corresponding information is not
-// needed. The values in these pointers are only valid on successful (non-NULL)
-// return.
-WEBP_EXTERN uint8_t* WebPIDecGetRGB(
- const WebPIDecoder* idec, int* last_y,
- int* width, int* height, int* stride);
-
-// Same as above function to get a YUVA image. Returns pointer to the luma
-// plane or NULL in case of error. If there is no alpha information
-// the alpha pointer '*a' will be returned NULL.
-WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
- const WebPIDecoder* idec, int* last_y,
- uint8_t** u, uint8_t** v, uint8_t** a,
- int* width, int* height, int* stride, int* uv_stride, int* a_stride);
-
-// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the
-// alpha information (if present). Kept for backward compatibility.
-static WEBP_INLINE uint8_t* WebPIDecGetYUV(
- const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v,
- int* width, int* height, int* stride, int* uv_stride) {
- return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height,
- stride, uv_stride, NULL);
-}
-
-// Generic call to retrieve information about the displayable area.
-// If non NULL, the left/right/width/height pointers are filled with the visible
-// rectangular area so far.
-// Returns NULL in case the incremental decoder object is in an invalid state.
-// Otherwise returns the pointer to the internal representation. This structure
-// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
-WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
- const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
-
-//------------------------------------------------------------------------------
-// Advanced decoding parametrization
-//
-// Code sample for using the advanced decoding API
-/*
- // A) Init a configuration object
- WebPDecoderConfig config;
- CHECK(WebPInitDecoderConfig(&config));
-
- // B) optional: retrieve the bitstream's features.
- CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
-
- // C) Adjust 'config', if needed
- config.no_fancy_upsampling = 1;
- config.output.colorspace = MODE_BGRA;
- // etc.
-
- // Note that you can also make config.output point to an externally
- // supplied memory buffer, provided it's big enough to store the decoded
- // picture. Otherwise, config.output will just be used to allocate memory
- // and store the decoded picture.
-
- // D) Decode!
- CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);
-
- // E) Decoded image is now in config.output (and config.output.u.RGBA)
-
- // F) Reclaim memory allocated in config's object. It's safe to call
- // this function even if the memory is external and wasn't allocated
- // by WebPDecode().
- WebPFreeDecBuffer(&config.output);
-*/
-
-// Features gathered from the bitstream
-struct WebPBitstreamFeatures {
- int width; // Width in pixels, as read from the bitstream.
- int height; // Height in pixels, as read from the bitstream.
- int has_alpha; // True if the bitstream contains an alpha channel.
- int has_animation; // True if the bitstream is an animation.
- int format; // 0 = undefined (/mixed), 1 = lossy, 2 = lossless
-
- uint32_t pad[5]; // padding for later use
-};
-
-// Internal, version-checked, entry point
-WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(
- const uint8_t*, size_t, WebPBitstreamFeatures*, int);
-
-// Retrieve features from the bitstream. The *features structure is filled
-// with information gathered from the bitstream.
-// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
-// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the
-// features from headers. Returns error in other cases.
-// Note: The following chunk sequences (before the raw VP8/VP8L data) are
-// considered valid by this function:
-// RIFF + VP8(L)
-// RIFF + VP8X + (optional chunks) + VP8(L)
-// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
-// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
-static WEBP_INLINE VP8StatusCode WebPGetFeatures(
- const uint8_t* data, size_t data_size,
- WebPBitstreamFeatures* features) {
- return WebPGetFeaturesInternal(data, data_size, features,
- WEBP_DECODER_ABI_VERSION);
-}
-
-// Decoding options
-struct WebPDecoderOptions {
- int bypass_filtering; // if true, skip the in-loop filtering
- int no_fancy_upsampling; // if true, use faster pointwise upsampler
- int use_cropping; // if true, cropping is applied _first_
- int crop_left, crop_top; // top-left position for cropping.
- // Will be snapped to even values.
- int crop_width, crop_height; // dimension of the cropping area
- int use_scaling; // if true, scaling is applied _afterward_
- int scaled_width, scaled_height; // final resolution
- int use_threads; // if true, use multi-threaded decoding
- int dithering_strength; // dithering strength (0=Off, 100=full)
- int flip; // if true, flip output vertically
- int alpha_dithering_strength; // alpha dithering strength in [0..100]
-
- uint32_t pad[5]; // padding for later use
-};
-
-// Main object storing the configuration for advanced decoding.
-struct WebPDecoderConfig {
- WebPBitstreamFeatures input; // Immutable bitstream features (optional)
- WebPDecBuffer output; // Output buffer (can point to external mem)
- WebPDecoderOptions options; // Decoding options
-};
-
-// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
-
-// Initialize the configuration as empty. This function must always be
-// called first, unless WebPGetFeatures() is to be called.
-// Returns false in case of mismatched version.
-static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
- return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
-}
-
-// Instantiate a new incremental decoder object with the requested
-// configuration. The bitstream can be passed using 'data' and 'data_size'
-// parameter, in which case the features will be parsed and stored into
-// config->input. Otherwise, 'data' can be NULL and no parsing will occur.
-// Note that 'config' can be NULL too, in which case a default configuration
-// is used. If 'config' is not NULL, it must outlive the WebPIDecoder object
-// as some references to its fields will be used. No internal copy of 'config'
-// is made.
-// The return WebPIDecoder object must always be deleted calling WebPIDelete().
-// Returns NULL in case of error (and config->status will then reflect
-// the error condition, if available).
-WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
-
-// Non-incremental version. This version decodes the full data at once, taking
-// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
-// if the decoding was successful). Note that 'config' cannot be NULL.
-WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_DECODE_H_
diff --git a/include/webp/demux.h b/include/webp/demux.h
deleted file mode 100644
index 846eeb1..0000000
--- a/include/webp/demux.h
+++ /dev/null
@@ -1,363 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Demux API.
-// Enables extraction of image and extended format data from WebP files.
-
-// Code Example: Demuxing WebP data to extract all the frames, ICC profile
-// and EXIF/XMP metadata.
-/*
- WebPDemuxer* demux = WebPDemux(&webp_data);
-
- uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
- uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
- // ... (Get information about the features present in the WebP file).
- uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
-
- // ... (Iterate over all frames).
- WebPIterator iter;
- if (WebPDemuxGetFrame(demux, 1, &iter)) {
- do {
- // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(),
- // ... and get other frame properties like width, height, offsets etc.
- // ... see 'struct WebPIterator' below for more info).
- } while (WebPDemuxNextFrame(&iter));
- WebPDemuxReleaseIterator(&iter);
- }
-
- // ... (Extract metadata).
- WebPChunkIterator chunk_iter;
- if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter);
- // ... (Consume the ICC profile in 'chunk_iter.chunk').
- WebPDemuxReleaseChunkIterator(&chunk_iter);
- if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter);
- // ... (Consume the EXIF metadata in 'chunk_iter.chunk').
- WebPDemuxReleaseChunkIterator(&chunk_iter);
- if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter);
- // ... (Consume the XMP metadata in 'chunk_iter.chunk').
- WebPDemuxReleaseChunkIterator(&chunk_iter);
- WebPDemuxDelete(demux);
-*/
-
-#ifndef WEBP_WEBP_DEMUX_H_
-#define WEBP_WEBP_DEMUX_H_
-
-#include "./decode.h" // for WEBP_CSP_MODE
-#include "./mux_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WEBP_DEMUX_ABI_VERSION 0x0107 // MAJOR(8b) + MINOR(8b)
-
-// Note: forward declaring enumerations is not allowed in (strict) C and C++,
-// the types are left here for reference.
-// typedef enum WebPDemuxState WebPDemuxState;
-// typedef enum WebPFormatFeature WebPFormatFeature;
-typedef struct WebPDemuxer WebPDemuxer;
-typedef struct WebPIterator WebPIterator;
-typedef struct WebPChunkIterator WebPChunkIterator;
-typedef struct WebPAnimInfo WebPAnimInfo;
-typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions;
-
-//------------------------------------------------------------------------------
-
-// Returns the version number of the demux library, packed in hexadecimal using
-// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN int WebPGetDemuxVersion(void);
-
-//------------------------------------------------------------------------------
-// Life of a Demux object
-
-typedef enum WebPDemuxState {
- WEBP_DEMUX_PARSE_ERROR = -1, // An error occurred while parsing.
- WEBP_DEMUX_PARSING_HEADER = 0, // Not enough data to parse full header.
- WEBP_DEMUX_PARSED_HEADER = 1, // Header parsing complete,
- // data may be available.
- WEBP_DEMUX_DONE = 2 // Entire file has been parsed.
-} WebPDemuxState;
-
-// Internal, version-checked, entry point
-WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
- const WebPData*, int, WebPDemuxState*, int);
-
-// Parses the full WebP file given by 'data'. For single images the WebP file
-// header alone or the file header and the chunk header may be absent.
-// Returns a WebPDemuxer object on successful parse, NULL otherwise.
-static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
- return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
-}
-
-// Parses the possibly incomplete WebP file given by 'data'.
-// If 'state' is non-NULL it will be set to indicate the status of the demuxer.
-// Returns NULL in case of error or if there isn't enough data to start parsing;
-// and a WebPDemuxer object on successful parse.
-// Note that WebPDemuxer keeps internal pointers to 'data' memory segment.
-// If this data is volatile, the demuxer object should be deleted (by calling
-// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data.
-// This is usually an inexpensive operation.
-static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
- const WebPData* data, WebPDemuxState* state) {
- return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
-}
-
-// Frees memory associated with 'dmux'.
-WEBP_EXTERN void WebPDemuxDelete(WebPDemuxer* dmux);
-
-//------------------------------------------------------------------------------
-// Data/information extraction.
-
-typedef enum WebPFormatFeature {
- WEBP_FF_FORMAT_FLAGS, // bit-wise combination of WebPFeatureFlags
- // corresponding to the 'VP8X' chunk (if present).
- WEBP_FF_CANVAS_WIDTH,
- WEBP_FF_CANVAS_HEIGHT,
- WEBP_FF_LOOP_COUNT, // only relevant for animated file
- WEBP_FF_BACKGROUND_COLOR, // idem.
- WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
- // In case of a partial demux, this is the number
- // of frames seen so far, with the last frame
- // possibly being partial.
-} WebPFormatFeature;
-
-// Get the 'feature' value from the 'dmux'.
-// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
-// returned a state > WEBP_DEMUX_PARSING_HEADER.
-// If 'feature' is WEBP_FF_FORMAT_FLAGS, the returned value is a bit-wise
-// combination of WebPFeatureFlags values.
-// If 'feature' is WEBP_FF_LOOP_COUNT, WEBP_FF_BACKGROUND_COLOR, the returned
-// value is only meaningful if the bitstream is animated.
-WEBP_EXTERN uint32_t WebPDemuxGetI(
- const WebPDemuxer* dmux, WebPFormatFeature feature);
-
-//------------------------------------------------------------------------------
-// Frame iteration.
-
-struct WebPIterator {
- int frame_num;
- int num_frames; // equivalent to WEBP_FF_FRAME_COUNT.
- int x_offset, y_offset; // offset relative to the canvas.
- int width, height; // dimensions of this frame.
- int duration; // display duration in milliseconds.
- WebPMuxAnimDispose dispose_method; // dispose method for the frame.
- int complete; // true if 'fragment' contains a full frame. partial images
- // may still be decoded with the WebP incremental decoder.
- WebPData fragment; // The frame given by 'frame_num'. Note for historical
- // reasons this is called a fragment.
- int has_alpha; // True if the frame contains transparency.
- WebPMuxAnimBlend blend_method; // Blend operation for the frame.
-
- uint32_t pad[2]; // padding for later use.
- void* private_; // for internal use only.
-};
-
-// Retrieves frame 'frame_number' from 'dmux'.
-// 'iter->fragment' points to the frame on return from this function.
-// Setting 'frame_number' equal to 0 will return the last frame of the image.
-// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
-// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
-// NOTE: 'dmux' must persist for the lifetime of 'iter'.
-WEBP_EXTERN int WebPDemuxGetFrame(
- const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
-
-// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
-// previous ('iter->frame_num' - 1) frame. These functions do not loop.
-// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
-
-// Releases any memory associated with 'iter'.
-// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
-// iter. Also, must be called before destroying the associated WebPDemuxer with
-// WebPDemuxDelete().
-WEBP_EXTERN void WebPDemuxReleaseIterator(WebPIterator* iter);
-
-//------------------------------------------------------------------------------
-// Chunk iteration.
-
-struct WebPChunkIterator {
- // The current and total number of chunks with the fourcc given to
- // WebPDemuxGetChunk().
- int chunk_num;
- int num_chunks;
- WebPData chunk; // The payload of the chunk.
-
- uint32_t pad[6]; // padding for later use
- void* private_;
-};
-
-// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from
-// 'dmux'.
-// 'fourcc' is a character array containing the fourcc of the chunk to return,
-// e.g., "ICCP", "XMP ", "EXIF", etc.
-// Setting 'chunk_number' equal to 0 will return the last chunk in a set.
-// Returns true if the chunk is found, false otherwise. Image related chunk
-// payloads are accessed through WebPDemuxGetFrame() and related functions.
-// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
-// NOTE: 'dmux' must persist for the lifetime of the iterator.
-WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
- const char fourcc[4], int chunk_number,
- WebPChunkIterator* iter);
-
-// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
-// ('iter->chunk_num' - 1) chunk. These functions do not loop.
-// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
-
-// Releases any memory associated with 'iter'.
-// Must be called before destroying the associated WebPDemuxer with
-// WebPDemuxDelete().
-WEBP_EXTERN void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
-
-//------------------------------------------------------------------------------
-// WebPAnimDecoder API
-//
-// This API allows decoding (possibly) animated WebP images.
-//
-// Code Example:
-/*
- WebPAnimDecoderOptions dec_options;
- WebPAnimDecoderOptionsInit(&dec_options);
- // Tune 'dec_options' as needed.
- WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
- WebPAnimInfo anim_info;
- WebPAnimDecoderGetInfo(dec, &anim_info);
- for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
- while (WebPAnimDecoderHasMoreFrames(dec)) {
- uint8_t* buf;
- int timestamp;
- WebPAnimDecoderGetNext(dec, &buf, ×tamp);
- // ... (Render 'buf' based on 'timestamp').
- // ... (Do NOT free 'buf', as it is owned by 'dec').
- }
- WebPAnimDecoderReset(dec);
- }
- const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
- // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
- WebPAnimDecoderDelete(dec);
-*/
-
-typedef struct WebPAnimDecoder WebPAnimDecoder; // Main opaque object.
-
-// Global options.
-struct WebPAnimDecoderOptions {
- // Output colorspace. Only the following modes are supported:
- // MODE_RGBA, MODE_BGRA, MODE_rgbA and MODE_bgrA.
- WEBP_CSP_MODE color_mode;
- int use_threads; // If true, use multi-threaded decoding.
- uint32_t padding[7]; // Padding for later use.
-};
-
-// Internal, version-checked, entry point.
-WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
- WebPAnimDecoderOptions*, int);
-
-// Should always be called, to initialize a fresh WebPAnimDecoderOptions
-// structure before modification. Returns false in case of version mismatch.
-// WebPAnimDecoderOptionsInit() must have succeeded before using the
-// 'dec_options' object.
-static WEBP_INLINE int WebPAnimDecoderOptionsInit(
- WebPAnimDecoderOptions* dec_options) {
- return WebPAnimDecoderOptionsInitInternal(dec_options,
- WEBP_DEMUX_ABI_VERSION);
-}
-
-// Internal, version-checked, entry point.
-WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
- const WebPData*, const WebPAnimDecoderOptions*, int);
-
-// Creates and initializes a WebPAnimDecoder object.
-// Parameters:
-// webp_data - (in) WebP bitstream. This should remain unchanged during the
-// lifetime of the output WebPAnimDecoder object.
-// dec_options - (in) decoding options. Can be passed NULL to choose
-// reasonable defaults (in particular, color mode MODE_RGBA
-// will be picked).
-// Returns:
-// A pointer to the newly created WebPAnimDecoder object, or NULL in case of
-// parsing error, invalid option or memory error.
-static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
- const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) {
- return WebPAnimDecoderNewInternal(webp_data, dec_options,
- WEBP_DEMUX_ABI_VERSION);
-}
-
-// Global information about the animation..
-struct WebPAnimInfo {
- uint32_t canvas_width;
- uint32_t canvas_height;
- uint32_t loop_count;
- uint32_t bgcolor;
- uint32_t frame_count;
- uint32_t pad[4]; // padding for later use
-};
-
-// Get global information about the animation.
-// Parameters:
-// dec - (in) decoder instance to get information from.
-// info - (out) global information fetched from the animation.
-// Returns:
-// True on success.
-WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
- WebPAnimInfo* info);
-
-// Fetch the next frame from 'dec' based on options supplied to
-// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
-// 'canvas_width * 4 * canvas_height', and not just the frame sub-rectangle. The
-// returned buffer 'buf' is valid only until the next call to
-// WebPAnimDecoderGetNext(), WebPAnimDecoderReset() or WebPAnimDecoderDelete().
-// Parameters:
-// dec - (in/out) decoder instance from which the next frame is to be fetched.
-// buf - (out) decoded frame.
-// timestamp - (out) timestamp of the frame in milliseconds.
-// Returns:
-// False if any of the arguments are NULL, or if there is a parsing or
-// decoding error, or if there are no more frames. Otherwise, returns true.
-WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
- uint8_t** buf, int* timestamp);
-
-// Check if there are more frames left to decode.
-// Parameters:
-// dec - (in) decoder instance to be checked.
-// Returns:
-// True if 'dec' is not NULL and some frames are yet to be decoded.
-// Otherwise, returns false.
-WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
-
-// Resets the WebPAnimDecoder object, so that next call to
-// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
-// helpful when all frames need to be decoded multiple times (e.g.
-// info.loop_count times) without destroying and recreating the 'dec' object.
-// Parameters:
-// dec - (in/out) decoder instance to be reset
-WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
-
-// Grab the internal demuxer object.
-// Getting the demuxer object can be useful if one wants to use operations only
-// available through demuxer; e.g. to get XMP/EXIF/ICC metadata. The returned
-// demuxer object is owned by 'dec' and is valid only until the next call to
-// WebPAnimDecoderDelete().
-//
-// Parameters:
-// dec - (in) decoder instance from which the demuxer object is to be fetched.
-WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
- const WebPAnimDecoder* dec);
-
-// Deletes the WebPAnimDecoder object.
-// Parameters:
-// dec - (in/out) decoder instance to be deleted
-WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_DEMUX_H_
diff --git a/include/webp/encode.h b/include/webp/encode.h
deleted file mode 100644
index b4c599d..0000000
--- a/include/webp/encode.h
+++ /dev/null
@@ -1,552 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// WebP encoder: main interface
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_WEBP_ENCODE_H_
-#define WEBP_WEBP_ENCODE_H_
-
-#include "./types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WEBP_ENCODER_ABI_VERSION 0x020f // MAJOR(8b) + MINOR(8b)
-
-// Note: forward declaring enumerations is not allowed in (strict) C and C++,
-// the types are left here for reference.
-// typedef enum WebPImageHint WebPImageHint;
-// typedef enum WebPEncCSP WebPEncCSP;
-// typedef enum WebPPreset WebPPreset;
-// typedef enum WebPEncodingError WebPEncodingError;
-typedef struct WebPConfig WebPConfig;
-typedef struct WebPPicture WebPPicture; // main structure for I/O
-typedef struct WebPAuxStats WebPAuxStats;
-typedef struct WebPMemoryWriter WebPMemoryWriter;
-
-// Return the encoder's version number, packed in hexadecimal using 8bits for
-// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN int WebPGetEncoderVersion(void);
-
-//------------------------------------------------------------------------------
-// One-stop-shop call! No questions asked:
-
-// Returns the size of the compressed data (pointed to by *output), or 0 if
-// an error occurred. The compressed data must be released by the caller
-// using the call 'WebPFree(*output)'.
-// These functions compress using the lossy format, and the quality_factor
-// can go from 0 (smaller output, lower quality) to 100 (best quality,
-// larger output).
-WEBP_EXTERN size_t WebPEncodeRGB(const uint8_t* rgb,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeBGR(const uint8_t* bgr,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeRGBA(const uint8_t* rgba,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
-
-// These functions are the equivalent of the above, but compressing in a
-// lossless manner. Files are usually larger than lossy format, but will
-// not suffer any compression loss.
-// Note these functions, like the lossy versions, use the library's default
-// settings. For lossless this means 'exact' is disabled. RGB values in
-// transparent areas will be modified to improve compression. To avoid this,
-// use WebPEncode() and set WebPConfig::exact to 1.
-WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb,
- int width, int height, int stride,
- uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeLosslessBGR(const uint8_t* bgr,
- int width, int height, int stride,
- uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeLosslessRGBA(const uint8_t* rgba,
- int width, int height, int stride,
- uint8_t** output);
-WEBP_EXTERN size_t WebPEncodeLosslessBGRA(const uint8_t* bgra,
- int width, int height, int stride,
- uint8_t** output);
-
-//------------------------------------------------------------------------------
-// Coding parameters
-
-// Image characteristics hint for the underlying encoder.
-typedef enum WebPImageHint {
- WEBP_HINT_DEFAULT = 0, // default preset.
- WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot
- WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting
- WEBP_HINT_GRAPH, // Discrete tone image (graph, map-tile etc).
- WEBP_HINT_LAST
-} WebPImageHint;
-
-// Compression parameters.
-struct WebPConfig {
- int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
- float quality; // between 0 and 100. For lossy, 0 gives the smallest
- // size and 100 the largest. For lossless, this
- // parameter is the amount of effort put into the
- // compression: 0 is the fastest but gives larger
- // files compared to the slowest, but best, 100.
- int method; // quality/speed trade-off (0=fast, 6=slower-better)
-
- WebPImageHint image_hint; // Hint for image type (lossless only for now).
-
- int target_size; // if non-zero, set the desired target size in bytes.
- // Takes precedence over the 'compression' parameter.
- float target_PSNR; // if non-zero, specifies the minimal distortion to
- // try to achieve. Takes precedence over target_size.
- int segments; // maximum number of segments to use, in [1..4]
- int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum.
- int filter_strength; // range: [0 = off .. 100 = strongest]
- int filter_sharpness; // range: [0 = off .. 7 = least sharp]
- int filter_type; // filtering type: 0 = simple, 1 = strong (only used
- // if filter_strength > 0 or autofilter > 0)
- int autofilter; // Auto adjust filter's strength [0 = off, 1 = on]
- int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
- // 1 = compressed with WebP lossless). Default is 1.
- int alpha_filtering; // Predictive filtering method for alpha plane.
- // 0: none, 1: fast, 2: best. Default if 1.
- int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
- // Default is 100.
- int pass; // number of entropy-analysis passes (in [1..10]).
-
- int show_compressed; // if true, export the compressed picture back.
- // In-loop filtering is not applied.
- int preprocessing; // preprocessing filter:
- // 0=none, 1=segment-smooth, 2=pseudo-random dithering
- int partitions; // log2(number of token partitions) in [0..3]. Default
- // is set to 0 for easier progressive decoding.
- int partition_limit; // quality degradation allowed to fit the 512k limit
- // on prediction modes coding (0: no degradation,
- // 100: maximum possible degradation).
- int emulate_jpeg_size; // If true, compression parameters will be remapped
- // to better match the expected output size from
- // JPEG compression. Generally, the output size will
- // be similar but the degradation will be lower.
- int thread_level; // If non-zero, try and use multi-threaded encoding.
- int low_memory; // If set, reduce memory usage (but increase CPU use).
-
- int near_lossless; // Near lossless encoding [0 = max loss .. 100 = off
- // (default)].
- int exact; // if non-zero, preserve the exact RGB values under
- // transparent area. Otherwise, discard this invisible
- // RGB information for better compression. The default
- // value is 0.
-
- int use_delta_palette; // reserved for future lossless feature
- int use_sharp_yuv; // if needed, use sharp (and slow) RGB->YUV conversion
-
- int qmin; // minimum permissible quality factor
- int qmax; // maximum permissible quality factor
-};
-
-// Enumerate some predefined settings for WebPConfig, depending on the type
-// of source picture. These presets are used when calling WebPConfigPreset().
-typedef enum WebPPreset {
- WEBP_PRESET_DEFAULT = 0, // default preset.
- WEBP_PRESET_PICTURE, // digital picture, like portrait, inner shot
- WEBP_PRESET_PHOTO, // outdoor photograph, with natural lighting
- WEBP_PRESET_DRAWING, // hand or line drawing, with high-contrast details
- WEBP_PRESET_ICON, // small-sized colorful images
- WEBP_PRESET_TEXT // text-like
-} WebPPreset;
-
-// Internal, version-checked, entry point
-WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
-
-// Should always be called, to initialize a fresh WebPConfig structure before
-// modification. Returns false in case of version mismatch. WebPConfigInit()
-// must have succeeded before using the 'config' object.
-// Note that the default values are lossless=0 and quality=75.
-static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
- return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
- WEBP_ENCODER_ABI_VERSION);
-}
-
-// This function will initialize the configuration according to a predefined
-// set of parameters (referred to by 'preset') and a given quality factor.
-// This function can be called as a replacement to WebPConfigInit(). Will
-// return false in case of error.
-static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
- WebPPreset preset, float quality) {
- return WebPConfigInitInternal(config, preset, quality,
- WEBP_ENCODER_ABI_VERSION);
-}
-
-// Activate the lossless compression mode with the desired efficiency level
-// between 0 (fastest, lowest compression) and 9 (slower, best compression).
-// A good default level is '6', providing a fair tradeoff between compression
-// speed and final compressed size.
-// This function will overwrite several fields from config: 'method', 'quality'
-// and 'lossless'. Returns false in case of parameter error.
-WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level);
-
-// Returns true if 'config' is non-NULL and all configuration parameters are
-// within their valid ranges.
-WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
-
-//------------------------------------------------------------------------------
-// Input / Output
-// Structure for storing auxiliary statistics.
-
-struct WebPAuxStats {
- int coded_size; // final size
-
- float PSNR[5]; // peak-signal-to-noise ratio for Y/U/V/All/Alpha
- int block_count[3]; // number of intra4/intra16/skipped macroblocks
- int header_bytes[2]; // approximate number of bytes spent for header
- // and mode-partition #0
- int residual_bytes[3][4]; // approximate number of bytes spent for
- // DC/AC/uv coefficients for each (0..3) segments.
- int segment_size[4]; // number of macroblocks in each segments
- int segment_quant[4]; // quantizer values for each segments
- int segment_level[4]; // filtering strength for each segments [0..63]
-
- int alpha_data_size; // size of the transparency data
- int layer_data_size; // size of the enhancement layer data
-
- // lossless encoder statistics
- uint32_t lossless_features; // bit0:predictor bit1:cross-color transform
- // bit2:subtract-green bit3:color indexing
- int histogram_bits; // number of precision bits of histogram
- int transform_bits; // precision bits for transform
- int cache_bits; // number of bits for color cache lookup
- int palette_size; // number of color in palette, if used
- int lossless_size; // final lossless size
- int lossless_hdr_size; // lossless header (transform, huffman etc) size
- int lossless_data_size; // lossless image data size
-
- uint32_t pad[2]; // padding for later use
-};
-
-// Signature for output function. Should return true if writing was successful.
-// data/data_size is the segment of data to write, and 'picture' is for
-// reference (and so one can make use of picture->custom_ptr).
-typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
- const WebPPicture* picture);
-
-// WebPMemoryWrite: a special WebPWriterFunction that writes to memory using
-// the following WebPMemoryWriter object (to be set as a custom_ptr).
-struct WebPMemoryWriter {
- uint8_t* mem; // final buffer (of size 'max_size', larger than 'size').
- size_t size; // final size
- size_t max_size; // total capacity
- uint32_t pad[1]; // padding for later use
-};
-
-// The following must be called first before any use.
-WEBP_EXTERN void WebPMemoryWriterInit(WebPMemoryWriter* writer);
-
-// The following must be called to deallocate writer->mem memory. The 'writer'
-// object itself is not deallocated.
-WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
-// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
-// completion, writer.mem and writer.size will hold the coded data.
-// writer.mem must be freed by calling WebPMemoryWriterClear.
-WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size,
- const WebPPicture* picture);
-
-// Progress hook, called from time to time to report progress. It can return
-// false to request an abort of the encoding process, or true otherwise if
-// everything is OK.
-typedef int (*WebPProgressHook)(int percent, const WebPPicture* picture);
-
-// Color spaces.
-typedef enum WebPEncCSP {
- // chroma sampling
- WEBP_YUV420 = 0, // 4:2:0
- WEBP_YUV420A = 4, // alpha channel variant
- WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors
- WEBP_CSP_ALPHA_BIT = 4 // bit that is set if alpha is present
-} WebPEncCSP;
-
-// Encoding error conditions.
-typedef enum WebPEncodingError {
- VP8_ENC_OK = 0,
- VP8_ENC_ERROR_OUT_OF_MEMORY, // memory error allocating objects
- VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, // memory error while flushing bits
- VP8_ENC_ERROR_NULL_PARAMETER, // a pointer parameter is NULL
- VP8_ENC_ERROR_INVALID_CONFIGURATION, // configuration is invalid
- VP8_ENC_ERROR_BAD_DIMENSION, // picture has invalid width/height
- VP8_ENC_ERROR_PARTITION0_OVERFLOW, // partition is bigger than 512k
- VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M
- VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes
- VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G
- VP8_ENC_ERROR_USER_ABORT, // abort request by user
- VP8_ENC_ERROR_LAST // list terminator. always last.
-} WebPEncodingError;
-
-// maximum width/height allowed (inclusive), in pixels
-#define WEBP_MAX_DIMENSION 16383
-
-// Main exchange structure (input samples, output bytes, statistics)
-//
-// Once WebPPictureInit() has been called, it's ok to make all the INPUT fields
-// (use_argb, y/u/v, argb, ...) point to user-owned data, even if
-// WebPPictureAlloc() has been called. Depending on the value use_argb,
-// it's guaranteed that either *argb or *y/*u/*v content will be kept untouched.
-struct WebPPicture {
- // INPUT
- //////////////
- // Main flag for encoder selecting between ARGB or YUV input.
- // It is recommended to use ARGB input (*argb, argb_stride) for lossless
- // compression, and YUV input (*y, *u, *v, etc.) for lossy compression
- // since these are the respective native colorspace for these formats.
- int use_argb;
-
- // YUV input (mostly used for input to lossy compression)
- WebPEncCSP colorspace; // colorspace: should be YUV420 for now (=Y'CbCr).
- int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION)
- uint8_t* y, *u, *v; // pointers to luma/chroma planes.
- int y_stride, uv_stride; // luma/chroma strides.
- uint8_t* a; // pointer to the alpha plane
- int a_stride; // stride of the alpha plane
- uint32_t pad1[2]; // padding for later use
-
- // ARGB input (mostly used for input to lossless compression)
- uint32_t* argb; // Pointer to argb (32 bit) plane.
- int argb_stride; // This is stride in pixels units, not bytes.
- uint32_t pad2[3]; // padding for later use
-
- // OUTPUT
- ///////////////
- // Byte-emission hook, to store compressed bytes as they are ready.
- WebPWriterFunction writer; // can be NULL
- void* custom_ptr; // can be used by the writer.
-
- // map for extra information (only for lossy compression mode)
- int extra_info_type; // 1: intra type, 2: segment, 3: quant
- // 4: intra-16 prediction mode,
- // 5: chroma prediction mode,
- // 6: bit cost, 7: distortion
- uint8_t* extra_info; // if not NULL, points to an array of size
- // ((width + 15) / 16) * ((height + 15) / 16) that
- // will be filled with a macroblock map, depending
- // on extra_info_type.
-
- // STATS AND REPORTS
- ///////////////////////////
- // Pointer to side statistics (updated only if not NULL)
- WebPAuxStats* stats;
-
- // Error code for the latest error encountered during encoding
- WebPEncodingError error_code;
-
- // If not NULL, report progress during encoding.
- WebPProgressHook progress_hook;
-
- void* user_data; // this field is free to be set to any value and
- // used during callbacks (like progress-report e.g.).
-
- uint32_t pad3[3]; // padding for later use
-
- // Unused for now
- uint8_t* pad4, *pad5;
- uint32_t pad6[8]; // padding for later use
-
- // PRIVATE FIELDS
- ////////////////////
- void* memory_; // row chunk of memory for yuva planes
- void* memory_argb_; // and for argb too.
- void* pad7[2]; // padding for later use
-};
-
-// Internal, version-checked, entry point
-WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
-
-// Should always be called, to initialize the structure. Returns false in case
-// of version mismatch. WebPPictureInit() must have succeeded before using the
-// 'picture' object.
-// Note that, by default, use_argb is false and colorspace is WEBP_YUV420.
-static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
- return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
-}
-
-//------------------------------------------------------------------------------
-// WebPPicture utils
-
-// Convenience allocation / deallocation based on picture->width/height:
-// Allocate y/u/v buffers as per colorspace/width/height specification.
-// Note! This function will free the previous buffer if needed.
-// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
-
-// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
-// Note that this function does _not_ free the memory used by the 'picture'
-// object itself.
-// Besides memory (which is reclaimed) all other fields of 'picture' are
-// preserved.
-WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
-
-// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst
-// will fully own the copied pixels (this is not a view). The 'dst' picture need
-// not be initialized as its content is overwritten.
-// Returns false in case of memory allocation error.
-WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
-
-// Compute the single distortion for packed planes of samples.
-// 'src' will be compared to 'ref', and the raw distortion stored into
-// '*distortion'. The refined metric (log(MSE), log(1 - ssim),...' will be
-// stored in '*result'.
-// 'x_step' is the horizontal stride (in bytes) between samples.
-// 'src/ref_stride' is the byte distance between rows.
-// Returns false in case of error (bad parameter, memory allocation error, ...).
-WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
- const uint8_t* ref, size_t ref_stride,
- int width, int height,
- size_t x_step,
- int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
- float* distortion, float* result);
-
-// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
-// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
-// always performed using ARGB samples. Hence if the input is YUV(A), the
-// picture will be internally converted to ARGB (just for the measurement).
-// Warning: this function is rather CPU-intensive.
-WEBP_EXTERN int WebPPictureDistortion(
- const WebPPicture* src, const WebPPicture* ref,
- int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
- float result[5]);
-
-// self-crops a picture to the rectangle defined by top/left/width/height.
-// Returns false in case of memory allocation error, or if the rectangle is
-// outside of the source picture.
-// The rectangle for the view is defined by the top-left corner pixel
-// coordinates (left, top) as well as its width and height. This rectangle
-// must be fully be comprised inside the 'src' source picture. If the source
-// picture uses the YUV420 colorspace, the top and left coordinates will be
-// snapped to even values.
-WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
- int left, int top, int width, int height);
-
-// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
-// is defined by the top-left corner pixel coordinates (left, top) as well
-// as its width and height. This rectangle must be fully be comprised inside
-// the 'src' source picture. If the source picture uses the YUV420 colorspace,
-// the top and left coordinates will be snapped to even values.
-// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed
-// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so,
-// the original dimension will be lost). Picture 'dst' need not be initialized
-// with WebPPictureInit() if it is different from 'src', since its content will
-// be overwritten.
-// Returns false in case of memory allocation error or invalid parameters.
-WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst);
-
-// Returns true if the 'picture' is actually a view and therefore does
-// not own the memory for pixels.
-WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
-
-// Rescale a picture to new dimension width x height.
-// If either 'width' or 'height' (but not both) is 0 the corresponding
-// dimension will be calculated preserving the aspect ratio.
-// No gamma correction is applied.
-// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
-
-// Colorspace conversion function to import RGB samples.
-// Previous buffer will be free'd, if any.
-// *rgb buffer should have a size of at least height * rgb_stride.
-// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureImportRGB(
- WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
-// Same, but for RGBA buffer.
-WEBP_EXTERN int WebPPictureImportRGBA(
- WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
-// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
-// input buffer ignoring the alpha channel. Avoids needing to copy the data
-// to a temporary 24-bit RGB buffer to import the RGB only.
-WEBP_EXTERN int WebPPictureImportRGBX(
- WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
-
-// Variants of the above, but taking BGR(A|X) input.
-WEBP_EXTERN int WebPPictureImportBGR(
- WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
-WEBP_EXTERN int WebPPictureImportBGRA(
- WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
-WEBP_EXTERN int WebPPictureImportBGRX(
- WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
-
-// Converts picture->argb data to the YUV420A format. The 'colorspace'
-// parameter is deprecated and should be equal to WEBP_YUV420.
-// Upon return, picture->use_argb is set to false. The presence of real
-// non-opaque transparent values is detected, and 'colorspace' will be
-// adjusted accordingly. Note that this method is lossy.
-// Returns false in case of error.
-WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture,
- WebPEncCSP /*colorspace = WEBP_YUV420*/);
-
-// Same as WebPPictureARGBToYUVA(), but the conversion is done using
-// pseudo-random dithering with a strength 'dithering' between
-// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
-// for photographic picture.
-WEBP_EXTERN int WebPPictureARGBToYUVADithered(
- WebPPicture* picture, WebPEncCSP colorspace, float dithering);
-
-// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
-// Downsampling is handled with extra care in case of color clipping. This
-// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
-// and sharper YUV representation.
-// Returns false in case of error.
-WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
-// kept for backward compatibility:
-WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
-
-// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
-// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
-// ARGB incurs a small loss too.
-// Note that the use of this colorspace is discouraged if one has access to the
-// raw ARGB samples, since using YUV420 is comparatively lossy.
-// Returns false in case of error.
-WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
-
-// Helper function: given a width x height plane of RGBA or YUV(A) samples
-// clean-up or smoothen the YUV or RGB samples under fully transparent area,
-// to help compressibility (no guarantee, though).
-WEBP_EXTERN void WebPCleanupTransparentArea(WebPPicture* picture);
-
-// Scan the picture 'picture' for the presence of non fully opaque alpha values.
-// Returns true in such case. Otherwise returns false (indicating that the
-// alpha plane can be ignored altogether e.g.).
-WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture);
-
-// Remove the transparency information (if present) by blending the color with
-// the background color 'background_rgb' (specified as 24bit RGB triplet).
-// After this call, all alpha values are reset to 0xff.
-WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
-
-//------------------------------------------------------------------------------
-// Main call
-
-// Main encoding call, after config and picture have been initialized.
-// 'picture' must be less than 16384x16384 in dimension (cf WEBP_MAX_DIMENSION),
-// and the 'config' object must be a valid one.
-// Returns false in case of error, true otherwise.
-// In case of error, picture->error_code is updated accordingly.
-// 'picture' can hold the source samples in both YUV(A) or ARGB input, depending
-// on the value of 'picture->use_argb'. It is highly recommended to use
-// the former for lossy encoding, and the latter for lossless encoding
-// (when config.lossless is true). Automatic conversion from one format to
-// another is provided but they both incur some loss.
-WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_ENCODE_H_
diff --git a/include/webp/extras.h b/include/webp/extras.h
deleted file mode 100644
index 1c24be2..0000000
--- a/include/webp/extras.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-
-#ifndef WEBP_WEBP_EXTRAS_H_
-#define WEBP_WEBP_EXTRAS_H_
-
-#include "./types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "./encode.h"
-
-#define WEBP_EXTRAS_ABI_VERSION 0x0000 // MAJOR(8b) + MINOR(8b)
-
-//------------------------------------------------------------------------------
-
-// Returns the version number of the extras library, packed in hexadecimal using
-// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN(int) WebPGetExtrasVersion(void);
-
-//------------------------------------------------------------------------------
-// Ad-hoc colorspace importers.
-
-// Import luma sample (gray scale image) into 'picture'. The 'picture'
-// width and height must be set prior to calling this function.
-WEBP_EXTERN(int) WebPImportGray(const uint8_t* gray, WebPPicture* picture);
-
-// Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
-// width and height must be set prior to calling this function.
-WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
-
-// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
-// width and height must be set prior to calling this function.
-WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_WEBP_EXTRAS_H_ */
diff --git a/include/webp/format_constants.h b/include/webp/format_constants.h
deleted file mode 100644
index eca6981..0000000
--- a/include/webp/format_constants.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Internal header for constants related to WebP file format.
-//
-// Author: Urvang (urvang@google.com)
-
-#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_
-#define WEBP_WEBP_FORMAT_CONSTANTS_H_
-
-// Create fourcc of the chunk from the chunk tag characters.
-#define MKFOURCC(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (uint32_t)(d) << 24)
-
-// VP8 related constants.
-#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data.
-#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition
-#define VP8_MAX_PARTITION_SIZE (1 << 24) // max size for token partition
-#define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data.
-
-// VP8L related constants.
-#define VP8L_SIGNATURE_SIZE 1 // VP8L signature size.
-#define VP8L_MAGIC_BYTE 0x2f // VP8L signature byte.
-#define VP8L_IMAGE_SIZE_BITS 14 // Number of bits used to store
- // width and height.
-#define VP8L_VERSION_BITS 3 // 3 bits reserved for version.
-#define VP8L_VERSION 0 // version 0
-#define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header.
-
-#define MAX_PALETTE_SIZE 256
-#define MAX_CACHE_BITS 11
-#define HUFFMAN_CODES_PER_META_CODE 5
-#define ARGB_BLACK 0xff000000
-
-#define DEFAULT_CODE_LENGTH 8
-#define MAX_ALLOWED_CODE_LENGTH 15
-
-#define NUM_LITERAL_CODES 256
-#define NUM_LENGTH_CODES 24
-#define NUM_DISTANCE_CODES 40
-#define CODE_LENGTH_CODES 19
-
-#define MIN_HUFFMAN_BITS 2 // min number of Huffman bits
-#define MAX_HUFFMAN_BITS 9 // max number of Huffman bits
-
-#define TRANSFORM_PRESENT 1 // The bit to be written when next data
- // to be read is a transform.
-#define NUM_TRANSFORMS 4 // Maximum number of allowed transform
- // in a bitstream.
-typedef enum {
- PREDICTOR_TRANSFORM = 0,
- CROSS_COLOR_TRANSFORM = 1,
- SUBTRACT_GREEN = 2,
- COLOR_INDEXING_TRANSFORM = 3
-} VP8LImageTransformType;
-
-// Alpha related constants.
-#define ALPHA_HEADER_LEN 1
-#define ALPHA_NO_COMPRESSION 0
-#define ALPHA_LOSSLESS_COMPRESSION 1
-#define ALPHA_PREPROCESSED_LEVELS 1
-
-// Mux related constants.
-#define TAG_SIZE 4 // Size of a chunk tag (e.g. "VP8L").
-#define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size.
-#define CHUNK_HEADER_SIZE 8 // Size of a chunk header.
-#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP").
-#define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk.
-#define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk.
-#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
-
-#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
-#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
-#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count
-#define MAX_DURATION (1 << 24) // maximum duration
-#define MAX_POSITION_OFFSET (1 << 24) // maximum frame x/y offset
-
-// Maximum chunk payload is such that adding the header and padding won't
-// overflow a uint32_t.
-#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
-
-#endif // WEBP_WEBP_FORMAT_CONSTANTS_H_
diff --git a/include/webp/mux.h b/include/webp/mux.h
deleted file mode 100644
index 7d27489..0000000
--- a/include/webp/mux.h
+++ /dev/null
@@ -1,530 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// RIFF container manipulation and encoding for WebP images.
-//
-// Authors: Urvang (urvang@google.com)
-// Vikas (vikasa@google.com)
-
-#ifndef WEBP_WEBP_MUX_H_
-#define WEBP_WEBP_MUX_H_
-
-#include "./mux_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WEBP_MUX_ABI_VERSION 0x0108 // MAJOR(8b) + MINOR(8b)
-
-//------------------------------------------------------------------------------
-// Mux API
-//
-// This API allows manipulation of WebP container images containing features
-// like color profile, metadata, animation.
-//
-// Code Example#1: Create a WebPMux object with image data, color profile and
-// XMP metadata.
-/*
- int copy_data = 0;
- WebPMux* mux = WebPMuxNew();
- // ... (Prepare image data).
- WebPMuxSetImage(mux, &image, copy_data);
- // ... (Prepare ICCP color profile data).
- WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
- // ... (Prepare XMP metadata).
- WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
- // Get data from mux in WebP RIFF format.
- WebPMuxAssemble(mux, &output_data);
- WebPMuxDelete(mux);
- // ... (Consume output_data; e.g. write output_data.bytes to file).
- WebPDataClear(&output_data);
-*/
-
-// Code Example#2: Get image and color profile data from a WebP file.
-/*
- int copy_data = 0;
- // ... (Read data from file).
- WebPMux* mux = WebPMuxCreate(&data, copy_data);
- WebPMuxGetFrame(mux, 1, &image);
- // ... (Consume image; e.g. call WebPDecode() to decode the data).
- WebPMuxGetChunk(mux, "ICCP", &icc_profile);
- // ... (Consume icc_data).
- WebPMuxDelete(mux);
- WebPFree(data);
-*/
-
-// Note: forward declaring enumerations is not allowed in (strict) C and C++,
-// the types are left here for reference.
-// typedef enum WebPMuxError WebPMuxError;
-// typedef enum WebPChunkId WebPChunkId;
-typedef struct WebPMux WebPMux; // main opaque object.
-typedef struct WebPMuxFrameInfo WebPMuxFrameInfo;
-typedef struct WebPMuxAnimParams WebPMuxAnimParams;
-typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
-
-// Error codes
-typedef enum WebPMuxError {
- WEBP_MUX_OK = 1,
- WEBP_MUX_NOT_FOUND = 0,
- WEBP_MUX_INVALID_ARGUMENT = -1,
- WEBP_MUX_BAD_DATA = -2,
- WEBP_MUX_MEMORY_ERROR = -3,
- WEBP_MUX_NOT_ENOUGH_DATA = -4
-} WebPMuxError;
-
-// IDs for different types of chunks.
-typedef enum WebPChunkId {
- WEBP_CHUNK_VP8X, // VP8X
- WEBP_CHUNK_ICCP, // ICCP
- WEBP_CHUNK_ANIM, // ANIM
- WEBP_CHUNK_ANMF, // ANMF
- WEBP_CHUNK_DEPRECATED, // (deprecated from FRGM)
- WEBP_CHUNK_ALPHA, // ALPH
- WEBP_CHUNK_IMAGE, // VP8/VP8L
- WEBP_CHUNK_EXIF, // EXIF
- WEBP_CHUNK_XMP, // XMP
- WEBP_CHUNK_UNKNOWN, // Other chunks.
- WEBP_CHUNK_NIL
-} WebPChunkId;
-
-//------------------------------------------------------------------------------
-
-// Returns the version number of the mux library, packed in hexadecimal using
-// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN int WebPGetMuxVersion(void);
-
-//------------------------------------------------------------------------------
-// Life of a Mux object
-
-// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPNewInternal(int);
-
-// Creates an empty mux object.
-// Returns:
-// A pointer to the newly created empty mux object.
-// Or NULL in case of memory error.
-static WEBP_INLINE WebPMux* WebPMuxNew(void) {
- return WebPNewInternal(WEBP_MUX_ABI_VERSION);
-}
-
-// Deletes the mux object.
-// Parameters:
-// mux - (in/out) object to be deleted
-WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
-
-//------------------------------------------------------------------------------
-// Mux creation.
-
-// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int);
-
-// Creates a mux object from raw data given in WebP RIFF format.
-// Parameters:
-// bitstream - (in) the bitstream data in WebP RIFF format
-// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
-// Returns:
-// A pointer to the mux object created from given data - on success.
-// NULL - In case of invalid data or memory error.
-static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
- int copy_data) {
- return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION);
-}
-
-//------------------------------------------------------------------------------
-// Non-image chunks.
-
-// Note: Only non-image related chunks should be managed through chunk APIs.
-// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH").
-// To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(),
-// WebPMuxGetFrame() and WebPMuxDeleteFrame().
-
-// Adds a chunk with id 'fourcc' and data 'chunk_data' in the mux object.
-// Any existing chunk(s) with the same id will be removed.
-// Parameters:
-// mux - (in/out) object to which the chunk is to be added
-// fourcc - (in) a character array containing the fourcc of the given chunk;
-// e.g., "ICCP", "XMP ", "EXIF" etc.
-// chunk_data - (in) the chunk data to be added
-// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
-// or if fourcc corresponds to an image chunk.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxSetChunk(
- WebPMux* mux, const char fourcc[4], const WebPData* chunk_data,
- int copy_data);
-
-// Gets a reference to the data of the chunk with id 'fourcc' in the mux object.
-// The caller should NOT free the returned data.
-// Parameters:
-// mux - (in) object from which the chunk data is to be fetched
-// fourcc - (in) a character array containing the fourcc of the chunk;
-// e.g., "ICCP", "XMP ", "EXIF" etc.
-// chunk_data - (out) returned chunk data
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
-// or if fourcc corresponds to an image chunk.
-// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxGetChunk(
- const WebPMux* mux, const char fourcc[4], WebPData* chunk_data);
-
-// Deletes the chunk with the given 'fourcc' from the mux object.
-// Parameters:
-// mux - (in/out) object from which the chunk is to be deleted
-// fourcc - (in) a character array containing the fourcc of the chunk;
-// e.g., "ICCP", "XMP ", "EXIF" etc.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL
-// or if fourcc corresponds to an image chunk.
-// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxDeleteChunk(
- WebPMux* mux, const char fourcc[4]);
-
-//------------------------------------------------------------------------------
-// Images.
-
-// Encapsulates data about a single frame.
-struct WebPMuxFrameInfo {
- WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream
- // or a single-image WebP file.
- int x_offset; // x-offset of the frame.
- int y_offset; // y-offset of the frame.
- int duration; // duration of the frame (in milliseconds).
-
- WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF
- // or WEBP_CHUNK_IMAGE
- WebPMuxAnimDispose dispose_method; // Disposal method for the frame.
- WebPMuxAnimBlend blend_method; // Blend operation for the frame.
- uint32_t pad[1]; // padding for later use
-};
-
-// Sets the (non-animated) image in the mux object.
-// Note: Any existing images (including frames) will be removed.
-// Parameters:
-// mux - (in/out) object in which the image is to be set
-// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
-// WebP file (non-animated)
-// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxSetImage(
- WebPMux* mux, const WebPData* bitstream, int copy_data);
-
-// Adds a frame at the end of the mux object.
-// Notes: (1) frame.id should be WEBP_CHUNK_ANMF
-// (2) For setting a non-animated image, use WebPMuxSetImage() instead.
-// (3) Type of frame being pushed must be same as the frames in mux.
-// (4) As WebP only supports even offsets, any odd offset will be snapped
-// to an even location using: offset &= ~1
-// Parameters:
-// mux - (in/out) object to which the frame is to be added
-// frame - (in) frame data.
-// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL
-// or if content of 'frame' is invalid.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxPushFrame(
- WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data);
-
-// Gets the nth frame from the mux object.
-// The content of 'frame->bitstream' is allocated using WebPMalloc(), and NOT
-// owned by the 'mux' object. It MUST be deallocated by the caller by calling
-// WebPDataClear().
-// nth=0 has a special meaning - last position.
-// Parameters:
-// mux - (in) object from which the info is to be fetched
-// nth - (in) index of the frame in the mux object
-// frame - (out) data of the returned frame
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL.
-// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object.
-// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxGetFrame(
- const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame);
-
-// Deletes a frame from the mux object.
-// nth=0 has a special meaning - last position.
-// Parameters:
-// mux - (in/out) object from which a frame is to be deleted
-// nth - (in) The position from which the frame is to be deleted
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL.
-// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
-// before deletion.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
-
-//------------------------------------------------------------------------------
-// Animation.
-
-// Animation parameters.
-struct WebPMuxAnimParams {
- uint32_t bgcolor; // Background color of the canvas stored (in MSB order) as:
- // Bits 00 to 07: Alpha.
- // Bits 08 to 15: Red.
- // Bits 16 to 23: Green.
- // Bits 24 to 31: Blue.
- int loop_count; // Number of times to repeat the animation [0 = infinite].
-};
-
-// Sets the animation parameters in the mux object. Any existing ANIM chunks
-// will be removed.
-// Parameters:
-// mux - (in/out) object in which ANIM chunk is to be set/added
-// params - (in) animation parameters.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxSetAnimationParams(
- WebPMux* mux, const WebPMuxAnimParams* params);
-
-// Gets the animation parameters from the mux object.
-// Parameters:
-// mux - (in) object from which the animation parameters to be fetched
-// params - (out) animation parameters extracted from the ANIM chunk
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
-// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxGetAnimationParams(
- const WebPMux* mux, WebPMuxAnimParams* params);
-
-//------------------------------------------------------------------------------
-// Misc Utilities.
-
-// Sets the canvas size for the mux object. The width and height can be
-// specified explicitly or left as zero (0, 0).
-// * When width and height are specified explicitly, then this frame bound is
-// enforced during subsequent calls to WebPMuxAssemble() and an error is
-// reported if any animated frame does not completely fit within the canvas.
-// * When unspecified (0, 0), the constructed canvas will get the frame bounds
-// from the bounding-box over all frames after calling WebPMuxAssemble().
-// Parameters:
-// mux - (in) object to which the canvas size is to be set
-// width - (in) canvas width
-// height - (in) canvas height
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or
-// width or height are invalid or out of bounds
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
- int width, int height);
-
-// Gets the canvas size from the mux object.
-// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
-// That is, the mux object hasn't been modified since the last call to
-// WebPMuxAssemble() or WebPMuxCreate().
-// Parameters:
-// mux - (in) object from which the canvas size is to be fetched
-// width - (out) canvas width
-// height - (out) canvas height
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL.
-// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux,
- int* width, int* height);
-
-// Gets the feature flags from the mux object.
-// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
-// That is, the mux object hasn't been modified since the last call to
-// WebPMuxAssemble() or WebPMuxCreate().
-// Parameters:
-// mux - (in) object from which the features are to be fetched
-// flags - (out) the flags specifying which features are present in the
-// mux object. This will be an OR of various flag values.
-// Enum 'WebPFeatureFlags' can be used to test individual flag values.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
-// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxGetFeatures(const WebPMux* mux,
- uint32_t* flags);
-
-// Gets number of chunks with the given 'id' in the mux object.
-// Parameters:
-// mux - (in) object from which the info is to be fetched
-// id - (in) chunk id specifying the type of chunk
-// num_elements - (out) number of chunks with the given chunk id
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
- WebPChunkId id, int* num_elements);
-
-// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'.
-// This function also validates the mux object.
-// Note: The content of 'assembled_data' will be ignored and overwritten.
-// Also, the content of 'assembled_data' is allocated using WebPMalloc(), and
-// NOT owned by the 'mux' object. It MUST be deallocated by the caller by
-// calling WebPDataClear(). It's always safe to call WebPDataClear() upon
-// return, even in case of error.
-// Parameters:
-// mux - (in/out) object whose chunks are to be assembled
-// assembled_data - (out) assembled WebP data
-// Returns:
-// WEBP_MUX_BAD_DATA - if mux object is invalid.
-// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN WebPMuxError WebPMuxAssemble(WebPMux* mux,
- WebPData* assembled_data);
-
-//------------------------------------------------------------------------------
-// WebPAnimEncoder API
-//
-// This API allows encoding (possibly) animated WebP images.
-//
-// Code Example:
-/*
- WebPAnimEncoderOptions enc_options;
- WebPAnimEncoderOptionsInit(&enc_options);
- // Tune 'enc_options' as needed.
- WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
- while(<there are more frames>) {
- WebPConfig config;
- WebPConfigInit(&config);
- // Tune 'config' as needed.
- WebPAnimEncoderAdd(enc, frame, timestamp_ms, &config);
- }
- WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
- WebPAnimEncoderAssemble(enc, webp_data);
- WebPAnimEncoderDelete(enc);
- // Write the 'webp_data' to a file, or re-mux it further.
-*/
-
-typedef struct WebPAnimEncoder WebPAnimEncoder; // Main opaque object.
-
-// Forward declarations. Defined in encode.h.
-struct WebPPicture;
-struct WebPConfig;
-
-// Global options.
-struct WebPAnimEncoderOptions {
- WebPMuxAnimParams anim_params; // Animation parameters.
- int minimize_size; // If true, minimize the output size (slow). Implicitly
- // disables key-frame insertion.
- int kmin;
- int kmax; // Minimum and maximum distance between consecutive key
- // frames in the output. The library may insert some key
- // frames as needed to satisfy this criteria.
- // Note that these conditions should hold: kmax > kmin
- // and kmin >= kmax / 2 + 1. Also, if kmax <= 0, then
- // key-frame insertion is disabled; and if kmax == 1,
- // then all frames will be key-frames (kmin value does
- // not matter for these special cases).
- int allow_mixed; // If true, use mixed compression mode; may choose
- // either lossy and lossless for each frame.
- int verbose; // If true, print info and warning messages to stderr.
-
- uint32_t padding[4]; // Padding for later use.
-};
-
-// Internal, version-checked, entry point.
-WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
- WebPAnimEncoderOptions*, int);
-
-// Should always be called, to initialize a fresh WebPAnimEncoderOptions
-// structure before modification. Returns false in case of version mismatch.
-// WebPAnimEncoderOptionsInit() must have succeeded before using the
-// 'enc_options' object.
-static WEBP_INLINE int WebPAnimEncoderOptionsInit(
- WebPAnimEncoderOptions* enc_options) {
- return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION);
-}
-
-// Internal, version-checked, entry point.
-WEBP_EXTERN WebPAnimEncoder* WebPAnimEncoderNewInternal(
- int, int, const WebPAnimEncoderOptions*, int);
-
-// Creates and initializes a WebPAnimEncoder object.
-// Parameters:
-// width/height - (in) canvas width and height of the animation.
-// enc_options - (in) encoding options; can be passed NULL to pick
-// reasonable defaults.
-// Returns:
-// A pointer to the newly created WebPAnimEncoder object.
-// Or NULL in case of memory error.
-static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
- int width, int height, const WebPAnimEncoderOptions* enc_options) {
- return WebPAnimEncoderNewInternal(width, height, enc_options,
- WEBP_MUX_ABI_VERSION);
-}
-
-// Optimize the given frame for WebP, encode it and add it to the
-// WebPAnimEncoder object.
-// The last call to 'WebPAnimEncoderAdd' should be with frame = NULL, which
-// indicates that no more frames are to be added. This call is also used to
-// determine the duration of the last frame.
-// Parameters:
-// enc - (in/out) object to which the frame is to be added.
-// frame - (in/out) frame data in ARGB or YUV(A) format. If it is in YUV(A)
-// format, it will be converted to ARGB, which incurs a small loss.
-// timestamp_ms - (in) timestamp of this frame in milliseconds.
-// Duration of a frame would be calculated as
-// "timestamp of next frame - timestamp of this frame".
-// Hence, timestamps should be in non-decreasing order.
-// config - (in) encoding options; can be passed NULL to pick
-// reasonable defaults.
-// Returns:
-// On error, returns false and frame->error_code is set appropriately.
-// Otherwise, returns true.
-WEBP_EXTERN int WebPAnimEncoderAdd(
- WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
- const struct WebPConfig* config);
-
-// Assemble all frames added so far into a WebP bitstream.
-// This call should be preceded by a call to 'WebPAnimEncoderAdd' with
-// frame = NULL; if not, the duration of the last frame will be internally
-// estimated.
-// Parameters:
-// enc - (in/out) object from which the frames are to be assembled.
-// webp_data - (out) generated WebP bitstream.
-// Returns:
-// True on success.
-WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
- WebPData* webp_data);
-
-// Get error string corresponding to the most recent call using 'enc'. The
-// returned string is owned by 'enc' and is valid only until the next call to
-// WebPAnimEncoderAdd() or WebPAnimEncoderAssemble() or WebPAnimEncoderDelete().
-// Parameters:
-// enc - (in/out) object from which the error string is to be fetched.
-// Returns:
-// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
-// to 'enc' had an error, or an empty string if the last call was a success.
-WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
-
-// Deletes the WebPAnimEncoder object.
-// Parameters:
-// enc - (in/out) object to be deleted
-WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_MUX_H_
diff --git a/include/webp/mux_types.h b/include/webp/mux_types.h
deleted file mode 100644
index 2fe8195..0000000
--- a/include/webp/mux_types.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Data-types common to the mux and demux libraries.
-//
-// Author: Urvang (urvang@google.com)
-
-#ifndef WEBP_WEBP_MUX_TYPES_H_
-#define WEBP_WEBP_MUX_TYPES_H_
-
-#include <string.h> // memset()
-#include "./types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Note: forward declaring enumerations is not allowed in (strict) C and C++,
-// the types are left here for reference.
-// typedef enum WebPFeatureFlags WebPFeatureFlags;
-// typedef enum WebPMuxAnimDispose WebPMuxAnimDispose;
-// typedef enum WebPMuxAnimBlend WebPMuxAnimBlend;
-typedef struct WebPData WebPData;
-
-// VP8X Feature Flags.
-typedef enum WebPFeatureFlags {
- ANIMATION_FLAG = 0x00000002,
- XMP_FLAG = 0x00000004,
- EXIF_FLAG = 0x00000008,
- ALPHA_FLAG = 0x00000010,
- ICCP_FLAG = 0x00000020,
-
- ALL_VALID_FLAGS = 0x0000003e
-} WebPFeatureFlags;
-
-// Dispose method (animation only). Indicates how the area used by the current
-// frame is to be treated before rendering the next frame on the canvas.
-typedef enum WebPMuxAnimDispose {
- WEBP_MUX_DISPOSE_NONE, // Do not dispose.
- WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color.
-} WebPMuxAnimDispose;
-
-// Blend operation (animation only). Indicates how transparent pixels of the
-// current frame are blended with those of the previous canvas.
-typedef enum WebPMuxAnimBlend {
- WEBP_MUX_BLEND, // Blend.
- WEBP_MUX_NO_BLEND // Do not blend.
-} WebPMuxAnimBlend;
-
-// Data type used to describe 'raw' data, e.g., chunk data
-// (ICC profile, metadata) and WebP compressed image data.
-// 'bytes' memory must be allocated using WebPMalloc() and such.
-struct WebPData {
- const uint8_t* bytes;
- size_t size;
-};
-
-// Initializes the contents of the 'webp_data' object with default values.
-static WEBP_INLINE void WebPDataInit(WebPData* webp_data) {
- if (webp_data != NULL) {
- memset(webp_data, 0, sizeof(*webp_data));
- }
-}
-
-// Clears the contents of the 'webp_data' object by calling WebPFree().
-// Does not deallocate the object itself.
-static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
- if (webp_data != NULL) {
- WebPFree((void*)webp_data->bytes);
- WebPDataInit(webp_data);
- }
-}
-
-// Allocates necessary storage for 'dst' and copies the contents of 'src'.
-// Returns true on success.
-static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
- if (src == NULL || dst == NULL) return 0;
- WebPDataInit(dst);
- if (src->bytes != NULL && src->size != 0) {
- dst->bytes = (uint8_t*)WebPMalloc(src->size);
- if (dst->bytes == NULL) return 0;
- memcpy((void*)dst->bytes, src->bytes, src->size);
- dst->size = src->size;
- }
- return 1;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_MUX_TYPES_H_
diff --git a/include/webp/types.h b/include/webp/types.h
deleted file mode 100644
index 47f7f2b..0000000
--- a/include/webp/types.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Common types + memory wrappers
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_WEBP_TYPES_H_
-#define WEBP_WEBP_TYPES_H_
-
-#include <stddef.h> // for size_t
-
-#ifndef _MSC_VER
-#include <inttypes.h>
-#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
- (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
-#define WEBP_INLINE inline
-#else
-#define WEBP_INLINE
-#endif
-#else
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long int uint64_t;
-typedef long long int int64_t;
-#define WEBP_INLINE __forceinline
-#endif /* _MSC_VER */
-
-#ifndef WEBP_EXTERN
-// This explicitly marks library functions and allows for changing the
-// signature for e.g., Windows DLL builds.
-# if defined(__GNUC__) && __GNUC__ >= 4
-# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
-# else
-# define WEBP_EXTERN extern
-# endif /* __GNUC__ >= 4 */
-#endif /* WEBP_EXTERN */
-
-// Macro to check ABI compatibility (same major revision number)
-#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Allocates 'size' bytes of memory. Returns NULL upon error. Memory
-// must be deallocated by calling WebPFree(). This function is made available
-// by the core 'libwebp' library.
-WEBP_EXTERN void* WebPMalloc(size_t size);
-
-// Releases memory returned by the WebPDecode*() functions (from decode.h).
-WEBP_EXTERN void WebPFree(void* ptr);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBP_WEBP_TYPES_H_
diff --git a/infra/common.sh b/infra/common.sh
new file mode 100644
index 0000000..b4892d5
--- /dev/null
+++ b/infra/common.sh
@@ -0,0 +1,106 @@
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+log_err() {
+ echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
+}
+
+#######################################
+# Create build directory. Build directory will be deleted if it exists.
+# Arguments:
+# None.
+# Returns:
+# mkdir result.
+#######################################
+make_build_dir() {
+ if [[ "$#" -ne 1 ]]; then
+ return 1
+ fi
+
+ local build_dir
+ build_dir="$1"
+ rm -rf "${build_dir}"
+ mkdir -p "${build_dir}"
+}
+
+#######################################
+# Cleanup files from the build directory.
+# Globals:
+# LIBWEBP_ROOT repository's root path.
+# Arguments:
+# $1 build directory.
+#######################################
+cleanup() {
+ # $1 is not completely removed to allow for binary artifacts to be
+ # extracted.
+ find "${1:?"Build directory not defined"}" \
+ \( -name "*.[ao]" -o -name "*.l[ao]" \) -exec rm -f {} +
+}
+
+#######################################
+# Setup ccache for toolchain.
+# Globals:
+# PATH
+# Arguments:
+# None.
+#######################################
+setup_ccache() {
+ if [[ -x "$(command -v ccache)" ]]; then
+ export CCACHE_CPP2=yes
+ export PATH="/usr/lib/ccache:${PATH}"
+ fi
+}
+
+#######################################
+# Detects whether test block should be run in the current test shard.
+# Globals:
+# TEST_TOTAL_SHARDS: Valid range: [1, N]. Defaults to 1.
+# TEST_SHARD_INDEX: Valid range: [0, TEST_TOTAL_SHARDS). Defaults to 0.
+# libwebp_test_id: current test number; incremented with each call.
+# Arguments:
+# None
+# Returns:
+# true if the shard is active
+# false if the shard is inactive
+#######################################
+shard_should_run() {
+ TEST_TOTAL_SHARDS=${TEST_TOTAL_SHARDS:=1}
+ TEST_SHARD_INDEX=${TEST_SHARD_INDEX:=0}
+ libwebp_test_id=${libwebp_test_id:=-1}
+ : $((libwebp_test_id += 1))
+
+ if [[ "${TEST_SHARD_INDEX}" -lt 0 ||
+ "${TEST_SHARD_INDEX}" -ge "${TEST_TOTAL_SHARDS}" ]]; then
+ log_err "Invalid TEST_SHARD_INDEX (${TEST_SHARD_INDEX})!" \
+ "Expected [0, ${TEST_TOTAL_SHARDS})."
+ fi
+
+ [[ "$((libwebp_test_id % TEST_TOTAL_SHARDS))" -eq "${TEST_SHARD_INDEX}" ]]
+}
diff --git a/infra/compile.sh b/infra/compile.sh
new file mode 100755
index 0000000..18e9ebe
--- /dev/null
+++ b/infra/compile.sh
@@ -0,0 +1,401 @@
+#!/bin/bash
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -xe
+LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")"
+WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.XXX)"}
+
+# shellcheck source=infra/common.sh
+source "${LIBWEBP_ROOT}/infra/common.sh"
+
+usage() {
+ cat << EOF
+Usage: compile.sh BUILD_TYPE TARGET
+Options:
+BUILD_TYPE supported build type: (shared, static, static-debug)
+TARGET supported target platforms:
+ aarch64-linux-clang
+ aarch64-linux-gnu
+ arm-linux-gnueabi
+ arm-neon-linux-gnueabi
+ cmake
+ cmake-aarch64
+ cmake-arm
+ cmake-clang
+ disable-near-lossless
+ disable-sse4.1
+ disable-stats
+ force-aligned-32
+ force-aligned-64
+ gradle
+ i686-linux-asan
+ i686-linux-clang
+ i686-linux-gnu
+ i686-w64-mingw32
+ mips2el-linux-gnu
+ mips32dspr2el-linux-gnu
+ mips32eb-linux-gnu
+ mips32el-linux-gnu
+ mips32r2el-linux-gnu
+ mips32r5el-linux-gnu
+ mips64r2el-linux-gnu
+ mips64r6el-linux-gnu
+ native
+ reduce-csp
+ reduce-size
+ reduce-size-disable-stats
+ visibility-default-gnu
+ visibility-hidden-clang
+ visibility-hidden-gnu
+ wasm
+ x86_64-linux-clang
+ x86_64-linux-gnu
+ x86_64-linux-msan
+ x86_64-w64-mingw32
+Environment variables:
+WORKSPACE directory where the build is done
+EOF
+}
+
+################################################################################
+echo "Building libwebp in ${WORKSPACE}"
+
+if [[ ! -d "${WORKSPACE}" ]]; then
+ log_err "${WORKSPACE} directory does not exist"
+ exit 1
+fi
+
+BUILD_TYPE=${1:?"Build type not defined.$(
+ echo
+ usage
+)"}
+TARGET=${2:?"Target not defined.$(
+ echo
+ usage
+)"}
+readonly BUILD_DIR="${WORKSPACE}/build-${BUILD_TYPE}"
+
+trap 'cleanup ${BUILD_DIR}' EXIT
+make_build_dir "${BUILD_DIR}"
+
+config_flags=()
+case "${BUILD_TYPE}" in
+ shared*) ;; # Valid BUILD_TYPE but no setup required
+ static*) config_flags+=("--disable-shared") ;;
+ experimental) config_flags+=("--enable-experimental") ;;
+ *)
+ log_err "Invalid BUILD_TYPE"
+ usage
+ exit 1
+ ;;
+esac
+
+if grep -m 1 -q "enable-asserts" "${LIBWEBP_ROOT}/configure.ac"; then
+ config_flags+=("--enable-asserts")
+fi
+
+case "${TARGET}" in
+ aarch64-linux-clang)
+ TARGET="aarch64-linux-gnu"
+ CC="clang"
+ CC="${CC} --target=aarch64-linux-gnu"
+ export CC
+ export CFLAGS="-isystem /usr/aarch64-linux-gnu/include"
+ ;;
+ arm-linux-gnueabi)
+ export CFLAGS="-O3 -march=armv7-a -mfloat-abi=softfp -ftree-vectorize"
+ ;;
+ arm-neon-linux-gnueabi)
+ TARGET="arm-linux-gnueabi"
+ CFLAGS="-O3 -march=armv7-a -mfpu=neon -mfloat-abi=softfp -ftree-vectorize"
+ export CFLAGS
+ ;;
+ mips2el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips2"
+ TARGET="mipsel-linux-gnu"
+ ;;
+ mips32el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips32"
+ TARGET="mipsel-linux-gnu"
+ ;;
+ mips32r2el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips32r2"
+ TARGET="mipsel-linux-gnu"
+ ;;
+ mips32dspr2el-linux-gnu)
+ export CFLAGS="-EL -O2 -mdspr2"
+ TARGET="mipsel-linux-gnu"
+ ;;
+ mips32r5el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips32r5 -mmsa"
+ TARGET="mipsel-linux-gnu"
+ ;;
+ mips32eb-linux-gnu)
+ export CFLAGS="-EB -O2 -mips32"
+ TARGET="mips-linux-gnu"
+ ;;
+ mips64r2el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips64r2 -mabi=64"
+ TARGET="mips64el-linux-gnuabi64"
+ ;;
+ mips64r6el-linux-gnu)
+ export CFLAGS="-EL -O2 -mips64r6 -mabi=64 -mmsa"
+ TARGET="mips-img-linux-gnu"
+ ;;
+ i686-linux-gnu)
+ export CC="gcc -m32"
+ ;;
+ i686-linux-clang)
+ TARGET="i686-linux-gnu"
+ export CC="clang -m32"
+ ;;
+ i686-linux-asan)
+ TARGET="i686-linux-gnu"
+ export CC="clang -m32 -fsanitize=address"
+ ;;
+ i686-linux-msan)
+ TARGET="i686-linux-gnu"
+ export CC="clang -m32 -fsanitize=memory"
+ ;;
+ x86_64-linux-clang)
+ TARGET="x86_64-linux-gnu"
+ export CC=clang
+ ;;
+ x86_64-linux-msan)
+ TARGET="x86_64-linux-gnu"
+ export CC="clang -fsanitize=memory"
+ ;;
+ force-aligned-32)
+ config_flags+=("--enable-aligned")
+ TARGET="i686-linux-gnu"
+ export CC="gcc -m32"
+ ;;
+ force-aligned-64)
+ config_flags+=("--enable-aligned")
+ TARGET="x86_64-linux-gnu"
+ ;;
+ visibility-default-*)
+ export CFLAGS="-O2 -g -fvisibility=default"
+ TARGET="x86_64-linux-gnu"
+ ;;
+ visibility-hidden-*)
+ export CFLAGS="-O2 -g -fvisibility=hidden"
+ if [[ "${TARGET}" = "visibility-hidden-clang" ]]; then
+ export CC=clang
+ fi
+ TARGET="x86_64-linux-gnu"
+ ;;
+ disable-sse4.1)
+ grep "${TARGET}" "${LIBWEBP_ROOT}/configure.ac" || exit 0
+ config_flags+=("--${TARGET}")
+ TARGET="x86_64-linux-gnu"
+ ;;
+ disable-near-lossless)
+ grep "${TARGET}" "${LIBWEBP_ROOT}/configure.ac" || exit 0
+ config_flags+=("--${TARGET}")
+ TARGET="x86_64-linux-gnu"
+ ;;
+ disable-stats)
+ git -C "${LIBWEBP_ROOT}" grep WEBP_DISABLE_STATS || exit 0
+ export CFLAGS="-O2 -g -DWEBP_DISABLE_STATS"
+ TARGET="x86_64-linux-gnu"
+ ;;
+ reduce-size)
+ git -C "${LIBWEBP_ROOT}" grep WEBP_REDUCE_SIZE || exit 0
+ export CFLAGS="-O2 -g -DWEBP_REDUCE_SIZE"
+ TARGET="x86_64-linux-gnu"
+ ;;
+ reduce-size-disable-stats)
+ git -C "${LIBWEBP_ROOT}" grep -e WEBP_DISABLE_STATS -e WEBP_REDUCE_SIZE \
+ || exit 0
+ export CFLAGS="-O2 -g -DWEBP_DISABLE_STATS -DWEBP_REDUCE_SIZE"
+ TARGET="x86_64-linux-gnu"
+ ;;
+ reduce-csp)
+ git -C "${LIBWEBP_ROOT}" grep WEBP_REDUCE_CSP || exit 0
+ export CFLAGS="-O2 -g -DWEBP_REDUCE_CSP"
+ TARGET="x86_64-linux-gnu"
+ ;;
+ x86_64-linux-gnu | *mingw32 | aarch64*) ;; # Default target configuration
+ # non-configure based builds
+ native)
+ setup_ccache
+ # exercise makefile.unix then quit
+ make -C "${LIBWEBP_ROOT}" -f makefile.unix -j all
+ for tgt in extras examples/anim_diff; do
+ grep -q -m 1 "${tgt}" "${LIBWEBP_ROOT}/makefile.unix" \
+ && make -C "${LIBWEBP_ROOT}" -f makefile.unix -j "${tgt}"
+ done
+ [[ -d "${LIBWEBP_ROOT}/tests/fuzzer" ]] \
+ && make -j -C "${LIBWEBP_ROOT}/tests/fuzzer" -f makefile.unix
+ exit 0
+ ;;
+ cmake*)
+ setup_ccache
+ # exercise cmake then quit
+ opts=()
+ case "${TARGET}" in
+ cmake-clang)
+ opts+=("-DCMAKE_C_COMPILER=clang")
+ ;;
+ cmake-arm)
+ opts+=("-DCMAKE_C_COMPILER=arm-linux-gnueabi-gcc")
+ case "${GERRIT_BRANCH:-}" in
+ portable-intrinsics | 0.6.1) exit 0 ;;
+ *) ;; # Skip configuration
+ esac
+ ;;
+ cmake-aarch64)
+ opts+=("-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc")
+ case "${GERRIT_BRANCH:-}" in
+ portable-intrinsics | 0.6.1) exit 0 ;;
+ *) ;; # Skip configuration
+ esac
+ ;;
+ *) ;; # Skip configuration
+ esac
+ case "${BUILD_TYPE}" in
+ static*)
+ opts+=("-DBUILD_SHARED_LIBS=OFF")
+ ;;
+ experimental)
+ opts+=("-DWEBP_EXPERIMENTAL_FEATURES=ON" "-DBUILD_SHARED_LIBS=ON")
+ ;;
+ *)
+ opts+=("-DBUILD_SHARED_LIBS=ON")
+ ;;
+ esac
+ case "${BUILD_TYPE}" in
+ *debug) opts+=("-DCMAKE_BUILD_TYPE=Debug") ;;
+ *) opts+=("-DCMAKE_BUILD_TYPE=RelWithDebInfo") ;;
+ esac
+ cd "${BUILD_DIR}"
+ opts+=("-DWEBP_BUILD_CWEBP=ON" "-DWEBP_BUILD_DWEBP=ON")
+ grep -m 1 -q WEBP_BUILD_GIF2WEBP "${LIBWEBP_ROOT}/CMakeLists.txt" \
+ && opts+=("-DWEBP_BUILD_GIF2WEBP=ON")
+ grep -m 1 -q WEBP_BUILD_IMG2WEBP "${LIBWEBP_ROOT}/CMakeLists.txt" \
+ && opts+=("-DWEBP_BUILD_IMG2WEBP=ON")
+ cmake "${opts[@]}" "${LIBWEBP_ROOT}"
+ make VERBOSE=1 -j
+ case "${BUILD_TYPE}" in
+ static)
+ mkdir -p examples
+ cp [cd]webp examples
+ ;;
+ *) ;; # Skip configuration.
+ esac
+
+ grep "install" "${LIBWEBP_ROOT}/CMakeLists.txt" || exit 0
+
+ make DESTDIR="${BUILD_DIR}/webp-install" install/strip
+ mkdir tmp
+ cd tmp
+ cat > CMakeLists.txt << EOF
+cmake_minimum_required(VERSION 2.8.7)
+
+project(libwebp C)
+
+find_package(WebP)
+if (NOT WebP_FOUND)
+ message(FATAL_ERROR "WebP package not found")
+endif ()
+message("WebP_FOUND: \${WebP_FOUND}")
+message("WebP_INCLUDE_DIRS: \${WebP_INCLUDE_DIRS}")
+message("WebP_LIBRARIES: \${WebP_LIBRARIES}")
+message("WEBP_INCLUDE_DIRS: \${WEBP_INCLUDE_DIRS}")
+message("WEBP_LIBRARIES: \${WEBP_LIBRARIES}")
+EOF
+ cmake . "${opts[@]}" \
+ "-DCMAKE_PREFIX_PATH=${BUILD_DIR}/webp-install/usr/local"
+ exit 0
+ ;;
+ gradle)
+ setup_ccache
+ # exercise gradle then quit
+ [[ -f "${LIBWEBP_ROOT}/gradlew" ]] || exit 0
+
+ cd "${BUILD_DIR}"
+ # TODO -g / --gradle-user-home could be used if there's a race between jobs
+ "${LIBWEBP_ROOT}/gradlew" -p "${LIBWEBP_ROOT}" buildAllExecutables
+ exit 0
+ ;;
+ wasm)
+ grep -m 1 -q WEBP_ENABLE_WASM "${LIBWEBP_ROOT}/CMakeLists.txt" || exit 0
+ opts+=("-DCMAKE_C_COMPILER=clang" "-DWEBP_ENABLE_WASM=ON")
+ opts+=("-DWEBP_BUILD_CWEBP=ON" "-DWEBP_BUILD_DWEBP=ON")
+ case "${BUILD_TYPE}" in
+ *debug) opts+=("-DCMAKE_BUILD_TYPE=Debug") ;;
+ *) opts+=("-DCMAKE_BUILD_TYPE=RelWithDebInfo") ;;
+ esac
+ cd "${BUILD_DIR}"
+ cmake "${opts[@]}" "${LIBWEBP_ROOT}"
+ make VERBOSE=1 -j
+ mkdir examples
+ case "${BUILD_TYPE}" in
+ static)
+ mkdir -p examples
+ cp [cd]webp examples
+ ;;
+ *) ;; # Skip configuration
+ esac
+ exit 0
+ ;;
+ *)
+ log_err "Invalid TARGET"
+ usage
+ exit 1
+ ;;
+esac
+
+case "${TARGET}" in
+ *mingw32) ;; # Skip configuration
+ *)
+ case "${TARGET}-${CC}" in
+ static-debug-gcc* | static-debug-)
+ CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage -O0 -g"
+ CXXFLAGS="${CXXFLAGS} -fprofile-arcs -ftest-coverage -O0 -g"
+ export CFLAGS CXXFLAGS
+ ;;
+ *) ;; # This case should not be reached.
+ esac
+ ;;
+esac
+
+setup_ccache
+
+cd "${LIBWEBP_ROOT}"
+./autogen.sh
+
+cd "${BUILD_DIR}"
+"${LIBWEBP_ROOT}/configure" \
+ --host "${TARGET}" --build "$("${LIBWEBP_ROOT}/config.guess")" \
+ --enable-everything "${config_flags[@]}"
+make -j V=1
diff --git a/infra/compile_android.sh b/infra/compile_android.sh
new file mode 100755
index 0000000..013b97c
--- /dev/null
+++ b/infra/compile_android.sh
@@ -0,0 +1,224 @@
+#!/bin/bash
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -xe
+LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")"
+readonly LIBWEBP_ROOT
+readonly WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.android.XXX)"}
+# shellcheck source=infra/common.sh
+source "${LIBWEBP_ROOT}/infra/common.sh"
+
+usage() {
+ cat << EOF
+Usage: $(basename "$0") BUILD_TYPE APP_ABI
+Options:
+BUILD_TYPE supported build types:
+ static
+ static-debug
+ shared
+ shared-debug
+APP_ABI supported application binary interfaces:
+ armeabi-v7a
+ arm64-v8a
+ x86
+ x86_64
+Environment variables:
+WORKSPACE directory where the build is done.
+ANDROID_NDK_DIR directory where the android ndk tools are.
+EOF
+}
+
+################################################################################
+echo "Building libwebp for Android in ${WORKSPACE}"
+
+if [[ ! -d "${WORKSPACE}" ]]; then
+ log_err "${WORKSPACE} directory does not exist."
+ exit 1
+fi
+
+readonly BUILD_TYPE=${1:?"BUILD_TYPE is not defined.$(
+ echo
+ usage
+)"}
+readonly APP_ABI=${2:?"APP_ABI not defined.$(
+ echo
+ usage
+)"}
+readonly ANDROID_NDK_DIR=${ANDROID_NDK_DIR:?"ANDROID_NDK_DIR is not defined.$(
+ echo
+ usage
+)"}
+readonly BUILD_DIR="${WORKSPACE}/build-${BUILD_TYPE}"
+readonly STANDALONE_ANDROID_DIR="${WORKSPACE}/android"
+
+if [[ ! -x "${ANDROID_NDK_DIR}/ndk-build" ]]; then
+ log_err "unable to find ndk-build in ANDROID_NDK_DIR: ${ANDROID_NDK_DIR}."
+ exit 1
+fi
+
+CFLAGS=
+LDFLAGS=
+opts=()
+case "${BUILD_TYPE}" in
+ *debug)
+ readonly APP_OPTIM="debug"
+ CFLAGS="-O0 -g"
+ opts+=("--enable-asserts")
+ ;;
+ static* | shared*)
+ readonly APP_OPTIM="release"
+ CFLAGS="-O2 -g"
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
+
+case "${BUILD_TYPE}" in
+ shared*) readonly SHARED="1" ;;
+ *)
+ readonly SHARED="0"
+ CFLAGS="${CFLAGS} -fPIE"
+ LDFLAGS="${LDFLAGS} -Wl,-pie"
+ opts+=("--disable-shared")
+ ;;
+esac
+
+# Create a fresh build directory
+make_build_dir "${BUILD_DIR}"
+cd "${BUILD_DIR}"
+ln -s "${LIBWEBP_ROOT}" jni
+
+"${ANDROID_NDK_DIR}/ndk-build" -j2 \
+ APP_ABI="${APP_ABI}" \
+ APP_OPTIM="${APP_OPTIM}" \
+ ENABLE_SHARED="${SHARED}"
+
+cd "${LIBWEBP_ROOT}"
+./autogen.sh
+
+case "${APP_ABI}" in
+ armeabi*) arch="arm" ;;
+ arm64*) arch="arm64" ;;
+ *) arch="${APP_ABI}" ;;
+esac
+# TODO(b/185520507): remove this and use the binaries from
+# toolchains/llvm/prebuilt/ directly.
+rm -rf "${STANDALONE_ANDROID_DIR}"
+"${ANDROID_NDK_DIR}/build/tools/make_standalone_toolchain.py" \
+ --api 24 --arch "${arch}" --stl gnustl --install-dir \
+ "${STANDALONE_ANDROID_DIR}"
+export PATH="${STANDALONE_ANDROID_DIR}/bin:${PATH}"
+
+rm -rf "${BUILD_DIR}"
+make_build_dir "${BUILD_DIR}"
+cd "${BUILD_DIR}"
+
+case "${arch}" in
+ arm)
+ host="arm-linux-androideabi"
+ case "${APP_ABI}" in
+ armeabi) ;;
+ armeabi-v7a)
+ CFLAGS="${CFLAGS} -march=armv7-a -mfpu=neon -mfloat-abi=softfp"
+ ;;
+ *) ;; # No configuration needed
+ esac
+ ;;
+ arm64)
+ host="aarch64-linux-android"
+ ;;
+ x86)
+ host="i686-linux-android"
+ ;;
+ x86_64)
+ host="x86_64-linux-android"
+ ;;
+ *) ;; # Skip configuration
+esac
+
+setup_ccache
+CC="clang"
+
+"${LIBWEBP_ROOT}/configure" --host "${host}" --build \
+ "$("${LIBWEBP_ROOT}/config.guess")" CC="${CC}" CFLAGS="${CFLAGS}" \
+ LDFLAGS="${LDFLAGS}" "${opts[@]}"
+make -j
+
+if [[ "${GERRIT_REFSPEC:-}" = "refs/heads/portable-intrinsics" ]] \
+ || [[ "${GERRIT_BRANCH:-}" = "portable-intrinsics" ]]; then
+ cd "${WORKSPACE}"
+ rm -rf build && mkdir build
+ cd build
+ standalone="${WORKSPACE}/android"
+ cmake ../libwebp \
+ -DWEBP_BUILD_DWEBP=1 \
+ -DCMAKE_C_COMPILER="${standalone}/bin/clang" \
+ -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \
+ -DCMAKE_C_FLAGS=-fPIE \
+ -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DWEBP_ENABLE_WASM=1
+ make -j2
+
+ cd "${WORKSPACE}"
+ make_build_dir "${BUILD_DIR}"
+ cd "${BUILD_DIR}"
+ case "${APP_ABI}" in
+ armeabi-v7a | arm64*)
+ cmake "${LIBWEBP_ROOT}" \
+ -DWEBP_BUILD_DWEBP=1 \
+ -DCMAKE_C_COMPILER="${standalone}/bin/clang" \
+ -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \
+ -DCMAKE_C_FLAGS='-fPIE -DENABLE_NEON_BUILTIN_MULHI_INT16X8' \
+ -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DWEBP_ENABLE_WASM=1
+ make -j2
+ ;;
+ x86*)
+ cmake "${LIBWEBP_ROOT}" \
+ -DWEBP_BUILD_DWEBP=1 \
+ -DCMAKE_C_COMPILER="${standalone}/bin/clang" \
+ -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \
+ -DCMAKE_C_FLAGS='-fPIE -DENABLE_X86_BUILTIN_MULHI_INT16X8' \
+ -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DWEBP_ENABLE_WASM=1
+ make -j2
+ ;;
+ *)
+ log_err "APP_ABI not supported."
+ exit 1
+ ;;
+ esac
+fi
diff --git a/infra/compile_js.sh b/infra/compile_js.sh
new file mode 100755
index 0000000..6a13fe6
--- /dev/null
+++ b/infra/compile_js.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+readonly WORKSPACE="${WORKSPACE:-"$(mktemp -d -t webp.js.XXX)"}"
+readonly BUILD_DIR="${WORKSPACE}/webp_js/"
+readonly LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")"
+
+# shellcheck source=infra/common.sh
+source "${LIBWEBP_ROOT}/infra/common.sh"
+
+usage() {
+ cat << EOF
+Usage: $(basename "$0")
+Environment variables:
+WORKSPACE directory where the build is done
+EMSDK_DIR directory where emsdk is installed
+EOF
+}
+
+[[ -d "${EMSDK_DIR:?Not defined}" ]] \
+ || (log_err "${EMSDK_DIR} is not a valid directory." && exit 1)
+
+# shellcheck source=/opt/emsdk/emsdk_env.sh
+source "${EMSDK_DIR}/emsdk_env.sh"
+
+readonly EMSCRIPTEN=${EMSCRIPTEN:-"${EMSDK}/upstream/emscripten"}
+readonly \
+ EMSCRIPTEN_CMAKE_FILE="${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake"
+make_build_dir "${BUILD_DIR}"
+
+pushd "${BUILD_DIR}"
+opts=("-GUnix Makefiles" "-DWEBP_BUILD_WEBP_JS=ON")
+if [[ -z "$(command -v emcmake)" ]]; then
+ opts+=("-DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_CMAKE_FILE}")
+ cmake \
+ "${opts[@]}" \
+ "${LIBWEBP_ROOT}"
+ make -j
+else
+ emcmake cmake \
+ "${opts[@]}" \
+ "${LIBWEBP_ROOT}"
+ emmake make -j
+fi
+popd
diff --git a/infra/run_static_analysis.sh b/infra/run_static_analysis.sh
new file mode 100755
index 0000000..fa8445c
--- /dev/null
+++ b/infra/run_static_analysis.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+# Copyright (c) 2021, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of Google nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -xe
+
+LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")"
+readonly LIBWEBP_ROOT
+readonly WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.scanbuild.XXX)"}
+
+# shellcheck source=infra/common.sh
+source "${LIBWEBP_ROOT}/infra/common.sh"
+
+usage() {
+ cat << EOF
+Usage: $(basename "$0") MODE
+Options:
+MODE supported scan modes: (shallow|deep)
+Environment variables:
+WORKSPACE directory where the build is done.
+EOF
+}
+
+#######################################
+# Wrap clang-tools scan-build.
+# Globals:
+# OUTPUT_DIR target directory where scan-build report is generated.
+# MODE scan-build mode
+# Arguments:
+# $* scan-build additional args.
+# Returns:
+# scan-build retcode
+#######################################
+scan_build() {
+ scan-build -o "${OUTPUT_DIR}" --use-analyzer="$(command -v clang)" \
+ -analyzer-config mode="${MODE}" "$*"
+}
+
+MODE=${1:?"MODE is not specified.$(
+ echo
+ usage
+)"}
+
+readonly OUTPUT_DIR="${WORKSPACE}/output-${MODE}"
+readonly BUILD_DIR="${WORKSPACE}/build"
+
+make_build_dir "${OUTPUT_DIR}"
+make_build_dir "${BUILD_DIR}"
+
+cd "${LIBWEBP_ROOT}"
+./autogen.sh
+
+cd "${BUILD_DIR}"
+grep -m 1 -q 'enable-asserts' "${LIBWEBP_ROOT}/configure.ac" \
+ && args='--enable-asserts'
+scan_build "${LIBWEBP_ROOT}/configure" --enable-everything "${args}"
+scan_build make -j4
+
+index="$(find "${OUTPUT_DIR}" -name index.html)"
+if [[ -f "${index}" ]]; then
+ mv "$(dirname "${index}")/"* "${OUTPUT_DIR}"
+else
+ # make a empty report to wipe out any old bug reports.
+ cat << EOT > "${OUTPUT_DIR}/index.html"
+<html>
+<body>
+No bugs reported.
+</body>
+</html>
+EOT
+fi
diff --git a/iosbuild.sh b/iosbuild.sh
new file mode 100755
index 0000000..cd3a24c
--- /dev/null
+++ b/iosbuild.sh
@@ -0,0 +1,168 @@
+#!/bin/bash
+#
+# This script generates 'WebP.framework' and 'WebPDecoder.framework',
+# 'WebPDemux.framework' and 'WebPMux.framework'.
+# An iOS app can decode WebP images by including 'WebPDecoder.framework' and
+# both encode and decode WebP images by including 'WebP.framework'.
+#
+# Run ./iosbuild.sh to generate the frameworks under the current directory
+# (the previous build will be erased if it exists).
+#
+# This script is inspired by the build script written by Carson McDonald.
+# (https://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
+
+set -e
+
+# Set this variable based on the desired minimum deployment target.
+readonly IOS_MIN_VERSION=6.0
+
+# Extract the latest SDK version from the final field of the form: iphoneosX.Y
+readonly SDK=$(xcodebuild -showsdks \
+ | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
+)
+# Extract Xcode version.
+readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
+if [[ -z "${XCODE}" ]]; then
+ echo "Xcode not available"
+ exit 1
+fi
+
+readonly OLDPATH=${PATH}
+
+# Add iPhoneOS-V6 to the list of platforms below if you need armv6 support.
+# Note that iPhoneOS-V6 support is not available with the iOS6 SDK.
+PLATFORMS="iPhoneSimulator iPhoneSimulator64"
+PLATFORMS+=" iPhoneOS-V7 iPhoneOS-V7s iPhoneOS-V7-arm64"
+readonly PLATFORMS
+readonly SRCDIR=$(dirname $0)
+readonly TOPDIR=$(pwd)
+readonly BUILDDIR="${TOPDIR}/iosbuild"
+readonly TARGETDIR="${TOPDIR}/WebP.framework"
+readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
+readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
+readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
+readonly DEVELOPER=$(xcode-select --print-path)
+readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
+readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
+LIBLIST=''
+DECLIBLIST=''
+MUXLIBLIST=''
+DEMUXLIBLIST=''
+
+if [[ -z "${SDK}" ]]; then
+ echo "iOS SDK not available"
+ exit 1
+elif [[ ${SDK%%.*} -gt 8 ]]; then
+ EXTRA_CFLAGS="-fembed-bitcode"
+elif [[ ${SDK%%.*} -le 6 ]]; then
+ echo "You need iOS SDK version 6.0 or above"
+ exit 1
+fi
+
+echo "Xcode Version: ${XCODE}"
+echo "iOS SDK Version: ${SDK}"
+
+if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
+ || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then
+ cat << EOF
+WARNING: The following directories will be deleted:
+WARNING: ${BUILDDIR}
+WARNING: ${TARGETDIR}
+WARNING: ${DECTARGETDIR}
+WARNING: ${MUXTARGETDIR}
+WARNING: ${DEMUXTARGETDIR}
+WARNING: The build will continue in 5 seconds...
+EOF
+ sleep 5
+fi
+rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
+ ${MUXTARGETDIR} ${DEMUXTARGETDIR}
+mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \
+ ${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/
+
+if [[ ! -e ${SRCDIR}/configure ]]; then
+ if ! (cd ${SRCDIR} && sh autogen.sh); then
+ cat << EOF
+Error creating configure script!
+This script requires the autoconf/automake and libtool to build. MacPorts can
+be used to obtain these:
+https://www.macports.org/install.php
+EOF
+ exit 1
+ fi
+fi
+
+for PLATFORM in ${PLATFORMS}; do
+ ARCH2=""
+ if [[ "${PLATFORM}" == "iPhoneOS-V7-arm64" ]]; then
+ PLATFORM="iPhoneOS"
+ ARCH="aarch64"
+ ARCH2="arm64"
+ elif [[ "${PLATFORM}" == "iPhoneOS-V7s" ]]; then
+ PLATFORM="iPhoneOS"
+ ARCH="armv7s"
+ elif [[ "${PLATFORM}" == "iPhoneOS-V7" ]]; then
+ PLATFORM="iPhoneOS"
+ ARCH="armv7"
+ elif [[ "${PLATFORM}" == "iPhoneOS-V6" ]]; then
+ PLATFORM="iPhoneOS"
+ ARCH="armv6"
+ elif [[ "${PLATFORM}" == "iPhoneSimulator64" ]]; then
+ PLATFORM="iPhoneSimulator"
+ ARCH="x86_64"
+ else
+ ARCH="i386"
+ fi
+
+ ROOTDIR="${BUILDDIR}/${PLATFORM}-${SDK}-${ARCH}"
+ mkdir -p "${ROOTDIR}"
+
+ DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
+ SDKROOT="${PLATFORMSROOT}/"
+ SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
+ CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
+ CFLAGS+=" -miphoneos-version-min=${IOS_MIN_VERSION} ${EXTRA_CFLAGS}"
+
+ set -x
+ export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
+ ${SRCDIR}/configure --host=${ARCH}-apple-darwin --prefix=${ROOTDIR} \
+ --build=$(${SRCDIR}/config.guess) \
+ --disable-shared --enable-static \
+ --enable-libwebpdecoder --enable-swap-16bit-csp \
+ --enable-libwebpmux \
+ CFLAGS="${CFLAGS}"
+ set +x
+
+ # Build only the libraries, skip the examples.
+ make V=0 -C sharpyuv
+ make V=0 -C src install
+
+ LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
+ DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
+ MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
+ DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
+
+ make clean
+
+ export PATH=${OLDPATH}
+done
+
+echo "LIBLIST = ${LIBLIST}"
+cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/
+${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
+
+echo "DECLIBLIST = ${DECLIBLIST}"
+cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/
+${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder
+
+echo "MUXLIBLIST = ${MUXLIBLIST}"
+cp -a ${SRCDIR}/src/webp/{types,mux,mux_types}.h \
+ ${MUXTARGETDIR}/Headers/
+${LIPO} -create ${MUXLIBLIST} -output ${MUXTARGETDIR}/WebPMux
+
+echo "DEMUXLIBLIST = ${DEMUXLIBLIST}"
+cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
+ ${DEMUXTARGETDIR}/Headers/
+${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux
+
+echo "SUCCESS"
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..64d9bbc
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,2 @@
+/libtool.m4
+/lt*.m4
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644
index 0000000..d383ad5
--- /dev/null
+++ b/m4/ax_pthread.m4
@@ -0,0 +1,332 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+# This macro figures out how to build C programs using POSIX threads. It
+# sets the PTHREAD_LIBS output variable to the threads library and linker
+# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+# flags that are needed. (The user can also force certain compiler
+# flags/libs to be tested by setting these environment variables.)
+#
+# Also sets PTHREAD_CC to any special C compiler that is needed for
+# multi-threaded programs (defaults to the value of CC otherwise). (This
+# is necessary on AIX to use the special cc_r compiler alias.)
+#
+# NOTE: You are assumed to not only compile your program with these flags,
+# but also link it with them as well. e.g. you should link with
+# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+# If you are only building threads programs, you may wish to use these
+# variables in your default LIBS, CFLAGS, and CC:
+#
+# LIBS="$PTHREAD_LIBS $LIBS"
+# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+# CC="$PTHREAD_CC"
+#
+# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+# PTHREAD_CFLAGS.
+#
+# ACTION-IF-FOUND is a list of shell commands to run if a threads library
+# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+# is not found. If ACTION-IF-FOUND is not specified, the default action
+# will define HAVE_PTHREAD.
+#
+# Please let the authors know if this macro fails on any platform, or if
+# you have any other suggestions or comments. This macro was based on work
+# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+# Alejandro Forero Cuervo to the autoconf macro repository. We are also
+# grateful for the helpful feedback of numerous users.
+#
+# Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 21
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+ AC_MSG_RESULT([$ax_pthread_ok])
+ if test x"$ax_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+ solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+ ;;
+
+ darwin*)
+ ax_pthread_flags="-pthread $ax_pthread_flags"
+ ;;
+esac
+
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+ [AC_MSG_RESULT([yes])],
+ [ax_pthread_extra_flags=
+ AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+ if test x"$ax_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+ static void routine(void *a) { a = 0; }
+ static void *start_routine(void *a) { return a; }],
+ [pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */])],
+ [ax_pthread_ok=yes],
+ [])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT([$ax_pthread_ok])
+ if test "x$ax_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+ [int attr = $attr; return attr /* ; */])],
+ [attr_name=$attr; break],
+ [])
+ done
+ AC_MSG_RESULT([$attr_name])
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case ${host_os} in
+ aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+ osf* | hpux*) flag="-D_REENTRANT";;
+ solaris*)
+ if test "$GCC" = "yes"; then
+ flag="-D_REENTRANT"
+ else
+ # TODO: What about Clang on Solaris?
+ flag="-mt -D_REENTRANT"
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$flag])
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+ [ax_cv_PTHREAD_PRIO_INHERIT], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+ [[int i = PTHREAD_PRIO_INHERIT;]])],
+ [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+ [ax_cv_PTHREAD_PRIO_INHERIT=no])
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != xyes; then
+ case $host_os in
+ aix*)
+ AS_CASE(["x/$CC"],
+ [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+ [#handle absolute path differently from PATH based program lookup
+ AS_CASE(["x$CC"],
+ [x/*],
+ [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+ [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+ ;;
+ esac
+ fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+ :
+else
+ ax_pthread_ok=no
+ $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff --git a/makefile.unix b/makefile.unix
new file mode 100644
index 0000000..8348d10
--- /dev/null
+++ b/makefile.unix
@@ -0,0 +1,536 @@
+# This makefile is a simpler alternative to the autoconf-based build
+# system, for simple local building of the libraries and tools.
+# It will not install the libraries system-wide, but just create the 'cwebp'
+# and 'dwebp' tools in the examples/ directory, along with the static
+# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
+# 'src/demux/libwebpdemux.a', 'extras/libwebpextras.a' and
+# 'sharpyuv/libsharpyuv.a'.
+#
+# To build the library and examples, use:
+# make -f makefile.unix
+# from this top directory.
+
+#### Customizable part ####
+
+# These flags assume you have libpng, libjpeg, libtiff and libgif installed. If
+# not, either follow the install instructions below or just comment out the next
+# four lines.
+EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG -DWEBP_HAVE_TIFF
+DWEBP_LIBS= -lpng -lz
+CWEBP_LIBS= $(DWEBP_LIBS) -ljpeg -ltiff
+GIF_LIBS = -lgif
+
+ifeq ($(strip $(shell uname)), Darwin)
+ # Work around a problem linking tables marked as common symbols,
+ # cf., src/enc/yuv.[hc]
+ # Failure observed with: gcc 4.2.1 and 4.0.1.
+ EXTRA_FLAGS += -fno-common
+ EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H
+ EXTRA_FLAGS += -Wno-deprecated-declarations
+ EXTRA_FLAGS += -I/opt/local/include
+ EXTRA_LIBS += -L/opt/local/lib
+ GL_LIBS = -framework GLUT -framework OpenGL
+else
+ EXTRA_FLAGS += -I/usr/local/include
+ EXTRA_LIBS += -L/usr/local/lib
+ GL_LIBS = -lglut -lGL
+endif
+
+# SDL flags: use sdl-config if it exists
+SDL_CONFIG = $(shell sdl-config --version 2> /dev/null)
+ifneq ($(SDL_CONFIG),)
+ SDL_LIBS = $(shell sdl-config --libs)
+ SDL_FLAGS = $(shell sdl-config --cflags)
+else
+ # use best-guess
+ SDL_LIBS = -lSDL
+ SDL_FLAGS =
+endif
+
+# To install libraries on Mac OS X:
+# 1. Install MacPorts (https://www.macports.org/install.php)
+# 2. Run "sudo port install jpeg"
+# 3. Run "sudo port install libpng"
+# 4. Run "sudo port install tiff"
+# 5. Run "sudo port install giflib"
+
+# To install libraries on Linux:
+# 1. Run "sudo apt-get install libjpeg62-dev"
+# 2. Run "sudo apt-get install libpng12-dev"
+# 3. Run "sudo apt-get install libtiff4-dev"
+# 4. Run "sudo apt-get install libgif-dev"
+
+# Uncomment for build for 32bit platform
+# Alternatively, you can just use the command
+# 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect.
+# EXTRA_FLAGS += -m32
+
+# Extra flags to enable byte swap for 16 bit colorspaces.
+# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP=1
+
+# Extra flags to enable multi-threading
+EXTRA_FLAGS += -DWEBP_USE_THREAD
+EXTRA_LIBS += -lpthread
+
+# Control symbol visibility. Comment out if your compiler doesn't support it.
+EXTRA_FLAGS += -fvisibility=hidden
+
+# Extra flags to emulate C89 strictness with the full ANSI
+EXTRA_FLAGS += -Wextra -Wold-style-definition
+EXTRA_FLAGS += -Wmissing-prototypes
+EXTRA_FLAGS += -Wmissing-declarations
+EXTRA_FLAGS += -Wdeclaration-after-statement
+EXTRA_FLAGS += -Wshadow
+EXTRA_FLAGS += -Wformat-security -Wformat-nonliteral
+# EXTRA_FLAGS += -Wvla
+
+# SSE4.1-specific flags:
+ifeq ($(HAVE_SSE41), 1)
+EXTRA_FLAGS += -DWEBP_HAVE_SSE41
+src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1
+endif
+
+# NEON-specific flags:
+# EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8
+# -> seems to make the overall lib slower: -fno-split-wide-types
+
+# MIPS (MSA) 32-bit build specific flags for mips32r5 (p5600):
+# EXTRA_FLAGS += -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64
+# EXTRA_FLAGS += -msched-weight -mload-store-pairs
+
+# MIPS (MSA) 64-bit build specific flags for mips64r6 (i6400):
+# EXTRA_FLAGS += -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64
+# EXTRA_FLAGS += -msched-weight -mload-store-pairs
+
+#### Nothing should normally be changed below this line ####
+
+AR = ar
+ARFLAGS = r
+CPPFLAGS = -I. -Isrc/ -Wall
+ifeq ($(DEBUG), 1)
+ CFLAGS = -g
+else
+ CFLAGS = -O3 -DNDEBUG
+endif
+CFLAGS += $(EXTRA_FLAGS)
+CC = gcc
+INSTALL = install
+GROFF = /usr/bin/groff
+COL = /usr/bin/col
+LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
+
+ifdef BITTRACE
+CFLAGS += -DBITTRACE=$(BITTRACE)
+endif
+
+ANIM_UTIL_OBJS = \
+ examples/anim_util.o \
+
+SHARPYUV_OBJS = \
+ sharpyuv/sharpyuv.o \
+ sharpyuv/sharpyuv_cpu.o \
+ sharpyuv/sharpyuv_csp.o \
+ sharpyuv/sharpyuv_dsp.o \
+ sharpyuv/sharpyuv_gamma.o \
+ sharpyuv/sharpyuv_neon.o \
+ sharpyuv/sharpyuv_sse2.o \
+
+DEC_OBJS = \
+ src/dec/alpha_dec.o \
+ src/dec/buffer_dec.o \
+ src/dec/frame_dec.o \
+ src/dec/idec_dec.o \
+ src/dec/io_dec.o \
+ src/dec/quant_dec.o \
+ src/dec/tree_dec.o \
+ src/dec/vp8_dec.o \
+ src/dec/vp8l_dec.o \
+ src/dec/webp_dec.o \
+
+DEMUX_OBJS = \
+ src/demux/anim_decode.o \
+ src/demux/demux.o \
+
+DSP_DEC_OBJS = \
+ src/dsp/alpha_processing.o \
+ src/dsp/alpha_processing_mips_dsp_r2.o \
+ src/dsp/alpha_processing_neon.o \
+ src/dsp/alpha_processing_sse2.o \
+ src/dsp/alpha_processing_sse41.o \
+ src/dsp/cpu.o \
+ src/dsp/dec.o \
+ src/dsp/dec_clip_tables.o \
+ src/dsp/dec_mips32.o \
+ src/dsp/dec_mips_dsp_r2.o \
+ src/dsp/dec_msa.o \
+ src/dsp/dec_neon.o \
+ src/dsp/dec_sse2.o \
+ src/dsp/dec_sse41.o \
+ src/dsp/filters.o \
+ src/dsp/filters_mips_dsp_r2.o \
+ src/dsp/filters_msa.o \
+ src/dsp/filters_neon.o \
+ src/dsp/filters_sse2.o \
+ src/dsp/lossless.o \
+ src/dsp/lossless_mips_dsp_r2.o \
+ src/dsp/lossless_msa.o \
+ src/dsp/lossless_neon.o \
+ src/dsp/lossless_sse2.o \
+ src/dsp/lossless_sse41.o \
+ src/dsp/rescaler.o \
+ src/dsp/rescaler_mips32.o \
+ src/dsp/rescaler_mips_dsp_r2.o \
+ src/dsp/rescaler_msa.o \
+ src/dsp/rescaler_neon.o \
+ src/dsp/rescaler_sse2.o \
+ src/dsp/upsampling.o \
+ src/dsp/upsampling_mips_dsp_r2.o \
+ src/dsp/upsampling_msa.o \
+ src/dsp/upsampling_neon.o \
+ src/dsp/upsampling_sse2.o \
+ src/dsp/upsampling_sse41.o \
+ src/dsp/yuv.o \
+ src/dsp/yuv_mips32.o \
+ src/dsp/yuv_mips_dsp_r2.o \
+ src/dsp/yuv_neon.o \
+ src/dsp/yuv_sse2.o \
+ src/dsp/yuv_sse41.o \
+
+DSP_ENC_OBJS = \
+ src/dsp/cost.o \
+ src/dsp/cost_mips32.o \
+ src/dsp/cost_mips_dsp_r2.o \
+ src/dsp/cost_neon.o \
+ src/dsp/cost_sse2.o \
+ src/dsp/enc.o \
+ src/dsp/enc_mips32.o \
+ src/dsp/enc_mips_dsp_r2.o \
+ src/dsp/enc_msa.o \
+ src/dsp/enc_neon.o \
+ src/dsp/enc_sse2.o \
+ src/dsp/enc_sse41.o \
+ src/dsp/lossless_enc.o \
+ src/dsp/lossless_enc_mips32.o \
+ src/dsp/lossless_enc_mips_dsp_r2.o \
+ src/dsp/lossless_enc_msa.o \
+ src/dsp/lossless_enc_neon.o \
+ src/dsp/lossless_enc_sse2.o \
+ src/dsp/lossless_enc_sse41.o \
+ src/dsp/ssim.o \
+ src/dsp/ssim_sse2.o \
+
+ENC_OBJS = \
+ src/enc/alpha_enc.o \
+ src/enc/analysis_enc.o \
+ src/enc/backward_references_cost_enc.o \
+ src/enc/backward_references_enc.o \
+ src/enc/config_enc.o \
+ src/enc/cost_enc.o \
+ src/enc/filter_enc.o \
+ src/enc/frame_enc.o \
+ src/enc/histogram_enc.o \
+ src/enc/iterator_enc.o \
+ src/enc/near_lossless_enc.o \
+ src/enc/picture_enc.o \
+ src/enc/picture_csp_enc.o \
+ src/enc/picture_psnr_enc.o \
+ src/enc/picture_rescale_enc.o \
+ src/enc/picture_tools_enc.o \
+ src/enc/predictor_enc.o \
+ src/enc/quant_enc.o \
+ src/enc/syntax_enc.o \
+ src/enc/token_enc.o \
+ src/enc/tree_enc.o \
+ src/enc/vp8l_enc.o \
+ src/enc/webp_enc.o \
+
+EX_FORMAT_DEC_OBJS = \
+ imageio/image_dec.o \
+ imageio/jpegdec.o \
+ imageio/metadata.o \
+ imageio/pngdec.o \
+ imageio/pnmdec.o \
+ imageio/tiffdec.o \
+ imageio/webpdec.o \
+
+EX_FORMAT_ENC_OBJS = \
+ imageio/image_enc.o \
+
+EX_UTIL_OBJS = \
+ examples/example_util.o \
+
+GIFDEC_OBJS = \
+ examples/gifdec.o \
+
+IMAGE_UTIL_OBJS = \
+ imageio/imageio_util.o \
+
+MUX_OBJS = \
+ src/mux/anim_encode.o \
+ src/mux/muxedit.o \
+ src/mux/muxinternal.o \
+ src/mux/muxread.o \
+
+UTILS_DEC_OBJS = \
+ src/utils/bit_reader_utils.o \
+ src/utils/color_cache_utils.o \
+ src/utils/filters_utils.o \
+ src/utils/huffman_utils.o \
+ src/utils/quant_levels_dec_utils.o \
+ src/utils/random_utils.o \
+ src/utils/rescaler_utils.o \
+ src/utils/thread_utils.o \
+ src/utils/utils.o \
+
+UTILS_ENC_OBJS = \
+ src/utils/bit_writer_utils.o \
+ src/utils/huffman_encode_utils.o \
+ src/utils/quant_levels_utils.o \
+
+EXTRA_OBJS = \
+ extras/extras.o \
+ extras/quality_estimate.o \
+
+LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
+LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
+ $(DSP_ENC_OBJS) $(UTILS_ENC_OBJS)
+LIBWEBPMUX_OBJS = $(MUX_OBJS)
+LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
+LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
+LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
+
+HDRS_INSTALLED = \
+ src/webp/decode.h \
+ src/webp/demux.h \
+ src/webp/encode.h \
+ src/webp/mux.h \
+ src/webp/mux_types.h \
+ src/webp/types.h \
+
+SHARPYUV_HDRS_INSTALLED = \
+ sharpyuv/sharpyuv.h \
+ sharpyuv/sharpyuv_cpu.h \
+ sharpyuv/sharpyuv_csp.h \
+
+HDRS = \
+ src/dec/alphai_dec.h \
+ src/dec/common_dec.h \
+ src/dec/vp8_dec.h \
+ src/dec/vp8i_dec.h \
+ src/dec/vp8li_dec.h \
+ src/dec/webpi_dec.h \
+ src/dsp/common_sse2.h \
+ src/dsp/cpu.h \
+ src/dsp/dsp.h \
+ src/dsp/lossless.h \
+ src/dsp/lossless_common.h \
+ src/dsp/mips_macro.h \
+ src/dsp/msa_macro.h \
+ src/dsp/neon.h \
+ src/dsp/yuv.h \
+ src/enc/backward_references_enc.h \
+ src/enc/cost_enc.h \
+ src/enc/histogram_enc.h \
+ src/enc/vp8i_enc.h \
+ src/enc/vp8li_enc.h \
+ src/mux/animi.h \
+ src/mux/muxi.h \
+ src/utils/bit_reader_utils.h \
+ src/utils/bit_reader_inl_utils.h \
+ src/utils/bit_writer_utils.h \
+ src/utils/color_cache_utils.h \
+ src/utils/endian_inl_utils.h \
+ src/utils/filters_utils.h \
+ src/utils/huffman_utils.h \
+ src/utils/huffman_encode_utils.h \
+ src/utils/quant_levels_utils.h \
+ src/utils/quant_levels_dec_utils.h \
+ src/utils/random_utils.h \
+ src/utils/rescaler_utils.h \
+ src/utils/thread_utils.h \
+ src/utils/utils.h \
+ src/webp/format_constants.h \
+ $(HDRS_INSTALLED) \
+ $(SHARPYUV_HDRS_INSTALLED) \
+
+OUT_LIBS = examples/libexample_util.a
+OUT_LIBS += imageio/libimageio_util.a
+OUT_LIBS += imageio/libimagedec.a
+OUT_LIBS += imageio/libimageenc.a
+OUT_LIBS += src/libwebpdecoder.a
+OUT_LIBS += src/libwebp.a
+OUT_LIBS += sharpyuv/libsharpyuv.a
+EXTRA_LIB = extras/libwebpextras.a
+OUT_EXAMPLES = examples/cwebp examples/dwebp
+EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
+ examples/anim_diff examples/anim_dump \
+ examples/img2webp examples/webpinfo
+OTHER_EXAMPLES = extras/get_disto extras/webp_quality extras/vwebp_sdl
+
+OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
+ifeq ($(MAKECMDGOALS),clean)
+ OUTPUT += $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES)
+ OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB)
+ OUTPUT += examples/libgifdec.a examples/libanim_util.a
+endif
+
+ex: $(OUT_EXAMPLES)
+all: ex $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES)
+extras: $(EXTRA_LIB)
+
+$(EX_FORMAT_DEC_OBJS): %.o: %.h
+
+# special dependencies:
+# tree_dec.c/vp8_dec.c/bit_reader_utils.c <->
+# bit_reader_inl_utils.h, endian_inl_utils.h
+# bit_writer_utils.c <-> endian_inl_utils.h
+src/dec/tree_dec.o: src/utils/bit_reader_inl_utils.h
+src/dec/tree_dec.o: src/utils/endian_inl_utils.h
+src/dec/vp8_dec.o: src/utils/bit_reader_inl_utils.h src/utils/endian_inl_utils.h
+src/utils/bit_reader_utils.o: src/utils/bit_reader_inl_utils.h
+src/utils/bit_reader_utils.o: src/utils/endian_inl_utils.h
+src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h
+
+%.o: %.c $(HDRS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+examples/libanim_util.a: $(ANIM_UTIL_OBJS)
+examples/libexample_util.a: $(EX_UTIL_OBJS)
+examples/libgifdec.a: $(GIFDEC_OBJS)
+extras/libwebpextras.a: $(LIBWEBPEXTRA_OBJS)
+imageio/libimagedec.a: $(EX_FORMAT_DEC_OBJS)
+imageio/libimageenc.a: $(EX_FORMAT_ENC_OBJS)
+imageio/libimageio_util.a: $(IMAGE_UTIL_OBJS)
+src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
+src/libwebp.a: $(LIBWEBP_OBJS)
+src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
+src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
+sharpyuv/libsharpyuv.a: $(LIBSHARPYUV_OBJS)
+
+%.a:
+ $(AR) $(ARFLAGS) $@ $^
+
+examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
+examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
+examples/cwebp: examples/cwebp.o
+examples/dwebp: examples/dwebp.o
+examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
+examples/vwebp: examples/vwebp.o
+examples/webpmux: examples/webpmux.o
+examples/img2webp: examples/img2webp.o
+examples/webpinfo: examples/webpinfo.o
+
+examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
+examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
+examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
+examples/anim_diff: sharpyuv/libsharpyuv.a
+examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS)
+examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
+examples/anim_dump: examples/libanim_util.a examples/libgifdec.a
+examples/anim_dump: src/demux/libwebpdemux.a
+examples/anim_dump: examples/libexample_util.a
+examples/anim_dump: imageio/libimageio_util.a
+examples/anim_dump: imageio/libimageenc.a
+examples/anim_dump: src/libwebp.a
+examples/anim_dump: sharpyuv/libsharpyuv.a
+examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
+examples/cwebp: examples/libexample_util.a
+examples/cwebp: imageio/libimagedec.a
+examples/cwebp: src/demux/libwebpdemux.a
+examples/cwebp: imageio/libimageio_util.a
+examples/cwebp: src/libwebp.a
+examples/cwebp: sharpyuv/libsharpyuv.a
+examples/cwebp: override EXTRA_LIBS += $(CWEBP_LIBS)
+examples/dwebp: examples/libexample_util.a
+examples/dwebp: imageio/libimagedec.a
+examples/dwebp: src/demux/libwebpdemux.a
+examples/dwebp: imageio/libimageenc.a
+examples/dwebp: imageio/libimageio_util.a
+examples/dwebp: src/libwebp.a
+examples/dwebp: sharpyuv/libsharpyuv.a
+examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS)
+examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
+examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
+examples/gif2webp: sharpyuv/libsharpyuv.a
+examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS)
+examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
+examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
+examples/vwebp: imageio/libimageio_util.a src/libwebp.a
+examples/vwebp: sharpyuv/libsharpyuv.a
+examples/vwebp: override EXTRA_LIBS += $(GL_LIBS)
+examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
+examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a
+examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
+examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
+examples/img2webp: imageio/libimagedec.a
+examples/img2webp: src/demux/libwebpdemux.a
+examples/img2webp: src/mux/libwebpmux.a
+examples/img2webp: src/libwebp.a
+examples/img2webp: sharpyuv/libsharpyuv.a
+examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS)
+examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
+examples/webpinfo: src/libwebpdecoder.a
+
+extras/get_disto: extras/get_disto.o
+extras/get_disto: imageio/libimagedec.a
+extras/get_disto: src/demux/libwebpdemux.a
+extras/get_disto: imageio/libimageio_util.a
+extras/get_disto: src/libwebp.a
+extras/get_disto: sharpyuv/libsharpyuv.a
+extras/get_disto: override EXTRA_LIBS += $(CWEBP_LIBS)
+
+extras/webp_quality: extras/webp_quality.o
+extras/webp_quality: imageio/libimageio_util.a
+extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
+extras/webp_quality: sharpyuv/libsharpyuv.a
+
+extras/vwebp_sdl: extras/vwebp_sdl.o
+extras/vwebp_sdl: extras/webp_to_sdl.o
+extras/vwebp_sdl: imageio/libimageio_util.a
+extras/vwebp_sdl: src/libwebp.a
+extras/vwebp_sdl: sharpyuv/libsharpyuv.a
+extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS)
+extras/vwebp_sdl: override EXTRA_LIBS += $(SDL_LIBS)
+
+$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+dist: DESTDIR := dist
+dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
+dist: all
+ $(INSTALL) -m755 -d $(DESTDIR)/include/webp \
+ $(DESTDIR)/include/webp/sharpyuv \
+ $(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
+ $(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin
+ $(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
+ $(INSTALL) -m644 $(SHARPYUV_HDRS_INSTALLED) $(DESTDIR)/include/webp/sharpyuv
+ $(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
+ $(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
+ $(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
+ $(INSTALL) -m644 sharpyuv/libsharpyuv.a $(DESTDIR)/lib
+ umask 022; \
+ for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \
+ man/img2webp.1 man/webpinfo.1; do \
+ basenam=$$(basename $$m .1); \
+ $(GROFF) -t -e -man -T ascii $$m \
+ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
+ $(GROFF) -t -e -man -T html $$m \
+ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \
+ done
+
+clean:
+ $(RM) $(OUTPUT) *~ \
+ examples/*.o examples/*~ \
+ extras/*.o extras/*~ \
+ imageio/*.o imageio/*~ \
+ sharpyuv/*.o sharpyuv/*~ \
+ src/dec/*.o src/dec/*~ \
+ src/demux/*.o src/demux/*~ \
+ src/dsp/*.o src/dsp/*~ \
+ src/enc/*.o src/enc/*~ \
+ src/mux/*.o src/mux/*~ \
+ src/utils/*.o src/utils/*~ \
+ src/webp/*~ man/*~ doc/*~ swig/*~ \
+
+.PHONY: all clean dist ex
+.SUFFIXES:
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..57e2483
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,17 @@
+man_MANS = cwebp.1 dwebp.1
+if BUILD_MUX
+ man_MANS += webpmux.1
+endif
+if BUILD_GIF2WEBP
+ man_MANS += gif2webp.1
+endif
+if BUILD_IMG2WEBP
+ man_MANS += img2webp.1
+endif
+if BUILD_VWEBP
+ man_MANS += vwebp.1
+endif
+if BUILD_WEBPINFO
+ man_MANS += webpinfo.1
+endif
+EXTRA_DIST = $(man_MANS)
diff --git a/man/cwebp.1 b/man/cwebp.1
new file mode 100644
index 0000000..28de4c9
--- /dev/null
+++ b/man/cwebp.1
@@ -0,0 +1,328 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH CWEBP 1 "March 17, 2022"
+.SH NAME
+cwebp \- compress an image file to a WebP file
+.SH SYNOPSIS
+.B cwebp
+.RI [ options ] " input_file \-o output_file.webp
+.br
+.SH DESCRIPTION
+This manual page documents the
+.B cwebp
+command.
+.PP
+\fBcwebp\fP compresses an image using the WebP format.
+Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples.
+Note: Animated PNG and WebP files are not supported.
+.SH OPTIONS
+The basic options are:
+.TP
+.BI \-o " string
+Specify the name of the output WebP file. If omitted, \fBcwebp\fP will
+perform compression but only report statistics.
+Using "\-" as output name will direct output to 'stdout'.
+.TP
+.BI \-\- " string
+Explicitly specify the input file. This option is useful if the input
+file starts with a '\-' for instance. This option must appear \fBlast\fP.
+Any other options afterward will be ignored.
+.TP
+.B \-h, \-help
+A short usage summary.
+.TP
+.B \-H, \-longhelp
+A summary of all the possible options.
+.TP
+.B \-version
+Print the version number (as major.minor.revision) and exit.
+.TP
+.B \-lossless
+Encode the image without any loss. For images with fully transparent area,
+the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the
+\-exact option is used.
+.TP
+.BI \-near_lossless " int
+Specify the level of near\-lossless image preprocessing. This option adjusts
+pixel values to help compressibility, but has minimal impact on the visual
+quality. It triggers lossless compression mode automatically. The range is 0
+(maximum preprocessing) to 100 (no preprocessing, the default). The typical
+value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
+better results.
+.TP
+.BI \-q " float
+Specify the compression factor for RGB channels between 0 and 100. The default
+is 75.
+.br
+In case of lossy compression (default), a small factor produces a smaller file
+with lower quality. Best quality is achieved by using a value of 100.
+.br
+In case of lossless compression (specified by the \fB\-lossless\fP option), a
+small factor enables faster compression speed, but produces a larger file.
+Maximum compression is achieved by using a value of 100.
+.TP
+.BI \-z " int
+Switch on \fBlossless\fP compression mode with the specified level between 0
+and 9, with level 0 being the fastest, 9 being the slowest. Fast mode
+produces larger file size than slower ones. A good default is \fB\-z 6\fP.
+This option is actually a shortcut for some predefined settings for quality
+and method. If options \fB\-q\fP or \fB\-m\fP are subsequently used, they will
+invalidate the effect of this option.
+.TP
+.BI \-alpha_q " int
+Specify the compression factor for alpha compression between 0 and 100.
+Lossless compression of alpha is achieved using a value of 100, while the lower
+values result in a lossy compression. The default is 100.
+.TP
+.BI \-preset " string
+Specify a set of pre\-defined parameters to suit a particular type of
+source material. Possible values are: \fBdefault\fP, \fBphoto\fP,
+\fBpicture\fP, \fBdrawing\fP, \fBicon\fP, \fBtext\fP. Since
+\fB\-preset\fP overwrites the other parameters' values (except the
+\fB\-q\fP one), this option should preferably appear first in the
+order of the arguments.
+.TP
+.BI \-m " int
+Specify the compression method to use. This parameter controls the
+trade off between encoding speed and the compressed file size and quality.
+Possible values range from 0 to 6. Default value is 4.
+When higher values are used, the encoder will spend more time inspecting
+additional encoding possibilities and decide on the quality gain.
+Lower value can result in faster processing time at the expense of
+larger file size and lower compression quality.
+.TP
+.BI \-crop " x_position y_position width height
+Crop the source to a rectangle with top\-left corner at coordinates
+(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
+This cropping area must be fully contained within the source rectangle.
+Note: the cropping is applied \fIbefore\fP any scaling.
+.TP
+.BI \-resize " width height
+Resize the source to a rectangle with size \fBwidth\fP x \fBheight\fP.
+If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
+the value will be calculated preserving the aspect\-ratio. Note: scaling
+is applied \fIafter\fP cropping.
+.TP
+.B \-mt
+Use multi\-threading for encoding, if possible.
+.TP
+.B \-low_memory
+Reduce memory usage of lossy encoding by saving four times the compressed
+size (typically). This will make the encoding slower and the output slightly
+different in size and distortion. This flag is only effective for methods
+3 and up, and is off by default. Note that leaving this flag off will have
+some side effects on the bitstream: it forces certain bitstream features
+like number of partitions (forced to 1). Note that a more detailed report
+of bitstream size is printed by \fBcwebp\fP when using this option.
+
+.SS LOSSY OPTIONS
+These options are only effective when doing lossy encoding (the default, with
+or without alpha).
+
+.TP
+.BI \-size " int
+Specify a target size (in bytes) to try and reach for the compressed output.
+The compressor will make several passes of partial encoding in order to get as
+close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
+are used, \fB\-size\fP value will prevail.
+.TP
+.BI \-psnr " float
+Specify a target PSNR (in dB) to try and reach for the compressed output.
+The compressor will make several passes of partial encoding in order to get as
+close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
+are used, \fB\-size\fP value will prevail.
+.TP
+.BI \-pass " int
+Set a maximum number of passes to use during the dichotomy used by
+options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
+If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
+specified, a default value of '6' passes will be used.
+.TP
+.BI \-qrange " int int
+Specifies the permissible interval for the quality factor. This is particularly
+useful when using multi-pass (\fB\-size\fP or \fB\-psnr\fP options).
+Default is 0 100.
+If the quality factor is outside this range, it will be clamped.
+If the minimum value must be less or equal to the maximum one.
+.TP
+.B \-af
+Turns auto\-filter on. This algorithm will spend additional time optimizing
+the filtering strength to reach a well\-balanced quality.
+.TP
+.B \-jpeg_like
+Change the internal parameter mapping to better match the expected size
+of JPEG compression. This flag will generally produce an output file of
+similar size to its JPEG equivalent (for the same \fB\-q\fP setting), but
+with less visual distortion.
+
+.TP
+Advanced options:
+
+.TP
+.BI \-f " int
+Specify the strength of the deblocking filter, between 0 (no filtering)
+and 100 (maximum filtering). A value of 0 will turn off any filtering.
+Higher value will increase the strength of the filtering process applied
+after decoding the picture. The higher the value the smoother the picture will
+appear. Typical values are usually in the range of 20 to 50.
+.TP
+.BI \-sharpness " int
+Specify the sharpness of the filtering (if used).
+Range is 0 (sharpest) to 7 (least sharp). Default is 0.
+.TP
+.B \-strong
+Use strong filtering (if filtering is being used thanks to the
+\fB\-f\fP option). Strong filtering is on by default.
+.TP
+.B \-nostrong
+Disable strong filtering (if filtering is being used thanks to the
+\fB\-f\fP option) and use simple filtering instead.
+.TP
+.B \-sharp_yuv
+Use more accurate and sharper RGB->YUV conversion if needed. Note that this
+process is slower than the default 'fast' RGB->YUV conversion.
+.TP
+.BI \-sns " int
+Specify the amplitude of the spatial noise shaping. Spatial noise shaping
+(or \fBsns\fP for short) refers to a general collection of built\-in algorithms
+used to decide which area of the picture should use relatively less bits,
+and where else to better transfer these bits. The possible range goes from
+0 (algorithm is off) to 100 (the maximal effect). The default value is 50.
+.TP
+.BI \-segments " int
+Change the number of partitions to use during the segmentation of the
+sns algorithm. Segments should be in range 1 to 4. Default value is 4.
+This option has no effect for methods 3 and up, unless \fB\-low_memory\fP
+is used.
+.TP
+.BI \-partition_limit " int
+Degrade quality by limiting the number of bits used by some macroblocks.
+Range is 0 (no degradation, the default) to 100 (full degradation).
+Useful values are usually around 30\-70 for moderately large images.
+In the VP8 format, the so\-called control partition has a limit of 512k and
+is used to store the following information: whether the macroblock is skipped,
+which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
+mode, and finally the prediction modes to use for each of the sub\-blocks.
+For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
+The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
+information can use up almost all these 4 bits (although the case is unlikely),
+which is problematic for very large images. The partition_limit factor controls
+how frequently the most bit\-costly mode (intra 4x4) will be used. This is
+useful in case the 512k limit is reached and the following message is displayed:
+\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
+If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one
+should use less segments in order to save more header bits per macroblock.
+See the \fB\-segments\fP option.
+
+.SS LOGGING OPTIONS
+These options control the level of output:
+.TP
+.B \-v
+Print extra information (encoding time in particular).
+.TP
+.B \-print_psnr
+Compute and report average PSNR (Peak\-Signal\-To\-Noise ratio).
+.TP
+.B \-print_ssim
+Compute and report average SSIM (structural similarity
+metric, see https://en.wikipedia.org/wiki/SSIM for additional details).
+.TP
+.B \-print_lsim
+Compute and report local similarity metric (sum of lowest error amongst the
+collocated pixel neighbors).
+.TP
+.B \-progress
+Report encoding progress in percent.
+.TP
+.B \-quiet
+Do not print anything.
+.TP
+.B \-short
+Only print brief information (output file size and PSNR) for testing purposes.
+.TP
+.BI \-map " int
+Output additional ASCII\-map of encoding information. Possible map values
+range from 1 to 6. This is only meant to help debugging.
+
+.SS ADDITIONAL OPTIONS
+More advanced options are:
+.TP
+.BI \-s " width height
+Specify that the input file actually consists of raw Y'CbCr samples following
+the ITU\-R BT.601 recommendation, in 4:2:0 linear format.
+The luma plane has size \fBwidth\fP x \fBheight\fP.
+.TP
+.BI \-pre " int
+Specify some preprocessing steps. Using a value of '2' will trigger
+quality\-dependent pseudo\-random dithering during RGBA\->YUVA conversion
+(lossy compression only).
+.TP
+.BI \-alpha_filter " string
+Specify the predictive filtering method for the alpha plane. One of 'none',
+\&'fast' or 'best', in increasing complexity and slowness order. Default is
+\&'fast'. Internally, alpha filtering is performed using four possible
+predictions (none, horizontal, vertical, gradient). The 'best' mode will try
+each mode in turn and pick the one which gives the smaller size. The 'fast'
+mode will just try to form an a priori guess without testing all modes.
+.TP
+.BI \-alpha_method " int
+Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes
+no compression, 1 uses WebP lossless format for compression. The default is 1.
+.TP
+.B \-exact
+Preserve RGB values in transparent area. The default is off, to help
+compressibility.
+.TP
+.BI \-blend_alpha " int
+This option blends the alpha channel (if present) with the source using the
+background color specified in hexadecimal as 0xrrggbb. The alpha channel is
+afterward reset to the opaque value 255.
+.TP
+.B \-noalpha
+Using this option will discard the alpha channel.
+.TP
+.BI \-hint " string
+Specify the hint about input image type. Possible values are:
+\fBphoto\fP, \fBpicture\fP or \fBgraph\fP.
+.TP
+.BI \-metadata " string
+A comma separated list of metadata to copy from the input to the output if
+present.
+Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP.
+The default is \fBnone\fP.
+
+Note: each input format may not support all combinations.
+.TP
+.B \-noasm
+Disable all assembly optimizations.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
+.br
+cwebp \-q 70 picture_with_alpha.png \-o picture_with_alpha.webp
+.br
+cwebp \-sns 70 \-f 50 \-size 60000 picture.png \-o picture.webp
+.br
+cwebp \-o picture.webp \-\- \-\-\-picture.png
+
+.SH AUTHORS
+\fBcwebp\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
+for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR dwebp (1),
+.BR gif2webp (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/man/dwebp.1 b/man/dwebp.1
new file mode 100644
index 0000000..e718aba
--- /dev/null
+++ b/man/dwebp.1
@@ -0,0 +1,150 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH DWEBP 1 "November 17, 2021"
+.SH NAME
+dwebp \- decompress a WebP file to an image file
+.SH SYNOPSIS
+.B dwebp
+.RI [ options ] " input_file.webp
+.br
+.SH DESCRIPTION
+This manual page documents the
+.B dwebp
+command.
+.PP
+\fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images.
+Note: Animated WebP files are not supported.
+.SH OPTIONS
+The basic options are:
+.TP
+.B \-h
+Print usage summary.
+.TP
+.B \-version
+Print the version number (as major.minor.revision) and exit.
+.TP
+.BI \-o " string
+Specify the name of the output file (as PNG format by default).
+Using "-" as output name will direct output to 'stdout'.
+.TP
+.BI \-\- " string
+Explicitly specify the input file. This option is useful if the input
+file starts with an '\-' for instance. This option must appear \fBlast\fP.
+Any other options afterward will be ignored. If the input file is "\-",
+the data will be read from \fIstdin\fP instead of a file.
+.TP
+.B \-bmp
+Change the output format to uncompressed BMP.
+.TP
+.B \-tiff
+Change the output format to uncompressed TIFF.
+.TP
+.B \-pam
+Change the output format to PAM (retains alpha).
+.TP
+.B \-ppm
+Change the output format to PPM (discards alpha).
+.TP
+.B \-pgm
+Change the output format to PGM. The output consists of luma/chroma
+samples instead of RGB, using the IMC4 layout. This option is mainly
+for verification and debugging purposes.
+.TP
+.B \-yuv
+Change the output format to raw YUV. The output consists of
+luma/chroma-U/chroma-V samples instead of RGB, saved sequentially as
+individual planes. This option is mainly for verification and debugging
+purposes.
+.TP
+.B \-nofancy
+Don't use the fancy upscaler for YUV420. This may lead to jaggy
+edges (especially the red ones), but should be faster.
+.TP
+.B \-nofilter
+Don't use the in-loop filtering process even if it is required by
+the bitstream. This may produce visible blocks on the non-compliant output,
+but it will make the decoding faster.
+.TP
+.BI \-dither " strength
+Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a
+post-processing effect applied to chroma components in lossy compression.
+It helps by smoothing gradients and avoiding banding artifacts.
+.TP
+.BI \-alpha_dither
+If the compressed file contains a transparency plane that was quantized
+during compression, this flag will allow dithering the reconstructed plane
+in order to generate smoother transparency gradients.
+.TP
+.B \-nodither
+Disable all dithering (default).
+.TP
+.B \-mt
+Use multi-threading for decoding, if possible.
+.TP
+.BI \-crop " x_position y_position width height
+Crop the decoded picture to a rectangle with top-left corner at coordinates
+(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
+This cropping area must be fully contained within the source rectangle.
+The top-left corner will be snapped to even coordinates if needed.
+This option is meant to reduce the memory needed for cropping large images.
+Note: the cropping is applied \fIbefore\fP any scaling.
+.TP
+.B \-flip
+Flip decoded image vertically (can be useful for OpenGL textures for instance).
+.TP
+\fB\-resize\fR, \fB\-scale\fI width height\fR
+Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This
+option is mostly intended to reducing the memory needed to decode large images,
+when only a small version is needed (thumbnail, preview, etc.). Note: scaling
+is applied \fIafter\fP cropping.
+If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
+the value will be calculated preserving the aspect-ratio.
+.TP
+.B \-quiet
+Do not print anything.
+.TP
+.B \-v
+Print extra information (decoding time in particular).
+.TP
+.B \-noasm
+Disable all assembly optimizations.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+dwebp picture.webp \-o output.png
+.br
+dwebp picture.webp \-ppm \-o output.ppm
+.br
+dwebp \-o output.ppm \-\- \-\-\-picture.webp
+.br
+cat picture.webp | dwebp \-o \- \-\- \- > output.ppm
+
+.SH AUTHORS
+\fBdwebp\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
+for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR cwebp (1),
+.BR gif2webp (1),
+.BR webpmux (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
+.SS Output file format details
+PAM: http://netpbm.sourceforge.net/doc/pam.html
+.br
+PGM: http://netpbm.sourceforge.net/doc/pgm.html
+.br
+PPM: http://netpbm.sourceforge.net/doc/ppm.html
+.br
+PNG: http://www.libpng.org/pub/png/png-sitemap.html#info
diff --git a/man/gif2webp.1 b/man/gif2webp.1
new file mode 100644
index 0000000..3bf43bc
--- /dev/null
+++ b/man/gif2webp.1
@@ -0,0 +1,164 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH GIF2WEBP 1 "November 17, 2021"
+.SH NAME
+gif2webp \- Convert a GIF image to WebP
+.SH SYNOPSIS
+.B gif2webp
+.RI [ options ] " input_file.gif \-o output_file.webp
+.br
+.SH DESCRIPTION
+This manual page documents the
+.B gif2webp
+command.
+.PP
+\fBgif2webp\fP converts a GIF image to a WebP image.
+.SH OPTIONS
+The basic options are:
+.TP
+.BI \-o " string
+Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will
+perform conversion but only report statistics.
+Using "\-" as output name will direct output to 'stdout'.
+.TP
+.BI \-\- " string
+Explicitly specify the input file. This option is useful if the input
+file starts with an '\-' for instance. This option must appear \fBlast\fP.
+Any other options afterward will be ignored. If the input file is "\-",
+the data will be read from \fIstdin\fP instead of a file.
+.TP
+.B \-h, \-help
+Usage information.
+.TP
+.B \-version
+Print the version number (as major.minor.revision) and exit.
+.TP
+.B \-lossy
+Encode the image using lossy compression.
+.TP
+.B \-mixed
+Mixed compression mode: optimize compression of the image by picking either
+lossy or lossless compression for each frame heuristically.
+.TP
+.BI \-q " float
+Specify the compression factor for RGB channels between 0 and 100. The default
+is 75.
+.br
+In case of lossless compression (default), a small factor enables faster
+compression speed, but produces a larger file. Maximum compression is achieved
+by using a value of 100.
+.br
+In case of lossy compression (specified by the \-lossy option), a small factor
+produces a smaller file with lower quality. Best quality is achieved by using a
+value of 100.
+.TP
+.BI \-m " int
+Specify the compression method to use. This parameter controls the
+trade off between encoding speed and the compressed file size and quality.
+Possible values range from 0 to 6. Default value is 4.
+When higher values are used, the encoder will spend more time inspecting
+additional encoding possibilities and decide on the quality gain.
+Lower value can result is faster processing time at the expense of
+larger file size and lower compression quality.
+.TP
+.BI \-min_size
+Encode image to achieve smallest size. This disables key frame insertion and
+picks the dispose method resulting in the smallest output for each frame. It
+uses lossless compression by default, but can be combined with \-q, \-m,
+\-lossy or \-mixed options.
+.TP
+.BI \-kmin " int
+.TP
+.BI \-kmax " int
+Specify the minimum and maximum distance between consecutive key frames
+(independently decodable frames) in the output animation. The tool will insert
+some key frames into the output animation as needed so that this criteria is
+satisfied.
+.br
+A 'kmax' value of 0 will turn off insertion of key frames. A 'kmax' value of 1
+will result in all frames being key frames. 'kmin' value is not taken into
+account in both these special cases.
+Typical values are in the range 3 to 30. Default values are kmin = 9,
+kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression.
+.br
+These two options are relevant only for animated images with large number of
+frames (>50).
+.br
+When lower values are used, more frames will be converted to key frames. This
+may lead to smaller number of frames required to decode a frame on average,
+thereby improving the decoding performance. But this may lead to slightly bigger
+file sizes.
+Higher values may lead to worse decoding performance, but smaller file sizes.
+.br
+Some restrictions:
+.br
+(i) kmin < kmax,
+.br
+(ii) kmin >= kmax / 2 + 1 and
+.br
+(iii) kmax - kmin <= 30.
+.br
+If any of these restrictions are not met, they will be enforced automatically.
+.TP
+.BI \-metadata " string
+A comma separated list of metadata to copy from the input to the output if
+present.
+Valid values: \fBall\fP, \fBnone\fP, \fBicc\fP, \fBxmp\fP.
+The default is \fBxmp\fP.
+.TP
+.BI \-f " int
+For lossy encoding only (specified by the \-lossy option). Specify the strength
+of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).
+A value of 0 will turn off any filtering. Higher value will increase the
+strength of the filtering process applied after decoding the picture. The higher
+the value the smoother the picture will appear. Typical values are usually in
+the range of 20 to 50.
+.TP
+.B \-mt
+Use multi-threading for encoding, if possible.
+.TP
+.B \-loop_compatibility
+If enabled, handle the loop information in a compatible fashion for Chrome
+version prior to M62 (inclusive) and Firefox.
+.TP
+.B \-v
+Print extra information.
+.TP
+.B \-quiet
+Do not print anything.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+gif2webp picture.gif \-o picture.webp
+.br
+gif2webp \-q 70 picture.gif \-o picture.webp
+.br
+gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp
+.br
+gif2webp \-lossy \-f 50 picture.gif \-o picture.webp
+.br
+gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif
+.br
+cat picture.gif | gif2webp \-o \- \-\- \- > output.webp
+
+.SH AUTHORS
+\fBgif2webp\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Urvang Joshi <urvang@google.com>, for the
+Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR cwebp (1),
+.BR dwebp (1),
+.BR webpmux (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/man/img2webp.1 b/man/img2webp.1
new file mode 100644
index 0000000..5b28ced
--- /dev/null
+++ b/man/img2webp.1
@@ -0,0 +1,105 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH IMG2WEBP 1 "January 5, 2022"
+.SH NAME
+img2webp \- create animated WebP file from a sequence of input images.
+.SH SYNOPSIS
+.B img2webp
+[file_options] [[frame_options] frame_file]...
+.br
+.B img2webp argument_file_name
+.br
+.SH DESCRIPTION
+This manual page documents the
+.B img2webp
+command.
+.PP
+\fBimg2webp\fP compresses a sequence of images using the animated WebP format.
+Input images can either be PNG, JPEG, TIFF or WebP.
+If a single file name (not starting with the character '\-') is supplied as
+the argument, the command line arguments are actually tokenized from this file.
+This allows for easy scripting or using a large number of arguments.
+.SH FILE-LEVEL OPTIONS
+The file-level options are applied at the beginning of the compression process,
+before the input frames are read.
+.TP
+.BI \-o " string
+Specify the name of the output WebP file.
+.TP
+.BI \-min_size
+Encode images to achieve smallest size. This disables key frame insertion and
+picks the parameters resulting in the smallest output for each frame. It uses
+lossless compression by default, but can be combined with \-q, \-m, \-lossy or
+\-mixed options.
+.TP
+.BI \-kmin " int
+.TP
+.BI \-kmax " int
+Specify the minimum and maximum distance between consecutive key frames
+(independently decodable frames) in the output animation. The tool will insert
+some key frames into the output animation as needed so that this criteria is
+satisfied.
+.br
+.B \-mixed
+Mixed compression mode: optimize compression of the image by picking either
+lossy or lossless compression for each frame heuristically. This global
+option disables the local option \fB-lossy\fP and \fB-lossless\fP .
+.TP
+.BI \-loop " int
+Specifies the number of times the animation should loop. Using '0'
+means 'loop indefinitely'.
+.TP
+.BI \-v
+Be more verbose.
+.TP
+.B \-h, \-help
+A short usage summary.
+.TP
+.B \-version
+Print the version numbers of the relevant libraries used.
+
+.SH PER-FRAME OPTIONS
+The per-frame options are applied for the images following as arguments in the
+command line. They can be modified any number of times preceding each particular
+input image.
+.TP
+.BI \-d " int
+Specify the image duration in milliseconds.
+.TP
+.B \-lossless, \-lossy
+Compress the next image(s) using lossless or lossy compression mode. The
+default mode is lossless.
+.TP
+.BI \-q " float
+Specify the compression factor between 0 and 100. The default is 75.
+.TP
+.BI \-m " int
+Specify the compression method to use. This parameter controls the
+trade off between encoding speed and the compressed file size and quality.
+Possible values range from 0 to 6. Default value is 4.
+
+.SH EXAMPLE
+img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp
+.br
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH AUTHORS
+\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
+for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR webpmux (1),
+.BR gif2webp (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/man/vwebp.1 b/man/vwebp.1
new file mode 100644
index 0000000..fa48db6
--- /dev/null
+++ b/man/vwebp.1
@@ -0,0 +1,101 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH VWEBP 1 "November 17, 2021"
+.SH NAME
+vwebp \- decompress a WebP file and display it in a window
+.SH SYNOPSIS
+.B vwebp
+.RI [ options ] " input_file.webp
+.br
+.SH DESCRIPTION
+This manual page documents the
+.B vwebp
+command.
+.PP
+\fBvwebp\fP decompresses a WebP file and displays it in a window using OpenGL.
+.SH OPTIONS
+.TP
+.B \-h
+Print usage summary.
+.TP
+.B \-version
+Print version number and exit.
+.TP
+.B \-noicc
+Don't use the ICC profile if present.
+.TP
+.B \-nofancy
+Don't use the fancy YUV420 upscaler.
+.TP
+.B \-nofilter
+Disable in-loop filtering.
+.TP
+.BI \-dither " strength
+Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a
+post-processing effect applied to chroma components in lossy compression.
+It helps by smoothing gradients and avoiding banding artifacts. Default: 50.
+.TP
+.BI \-noalphadither
+By default, quantized transparency planes are dithered during decompression,
+to smooth the gradients. This flag will prevent this dithering.
+.TP
+.B \-usebgcolor
+Fill transparent areas with the bitstream's own background color instead of
+checkerboard only. Default is white for non-animated images.
+.TP
+.B \-mt
+Use multi-threading for decoding, if possible.
+.TP
+.B \-info
+Display image information on top of the decoded image.
+.TP
+.BI \-\- " string
+Explicitly specify the input file. This option is useful if the input
+file starts with an '\-' for instance. This option must appear \fBlast\fP.
+Any other options afterward will be ignored. If the input file is "\-",
+the data will be read from \fIstdin\fP instead of a file.
+.TP
+
+.SH KEYBOARD SHORTCUTS
+.TP
+.B 'c'
+Toggle use of color profile.
+.TP
+.B 'b'
+Toggle display of background color.
+.TP
+.B 'i'
+Overlay file information.
+.TP
+.B 'd'
+Disable blending and disposal process, for debugging purposes.
+.TP
+.B 'q' / 'Q' / ESC
+Quit.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+vwebp picture.webp
+.br
+vwebp picture.webp -mt -dither 0
+.br
+vwebp \-\- \-\-\-picture.webp
+
+.SH AUTHORS
+\fBvwebp\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR dwebp (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/man/webpinfo.1 b/man/webpinfo.1
new file mode 100644
index 0000000..35d6d92
--- /dev/null
+++ b/man/webpinfo.1
@@ -0,0 +1,80 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH WEBPINFO 1 "November 17, 2021"
+.SH NAME
+webpinfo \- print out the chunk level structure of WebP files
+along with basic integrity checks.
+.SH SYNOPSIS
+.B webpinfo
+.I OPTIONS
+.I INPUT
+.br
+.B webpinfo [\-h|\-help|\-H|\-longhelp]
+.br
+
+.SH DESCRIPTION
+This manual page documents the
+.B webpinfo
+command.
+.PP
+\fBwebpinfo\fP can be used to print out the chunk level structure and bitstream
+header information of WebP files. It can also check if the files are of valid
+WebP format.
+
+.SH OPTIONS
+.TP
+.B \-version
+Print the version number (as major.minor.revision) and exit.
+.TP
+.B \-quiet
+Do not show chunk parsing information.
+.TP
+.B \-diag
+Show parsing error diagnosis.
+.TP
+.B \-summary
+Show chunk stats summary.
+.TP
+.BI \-bitstream_info
+Parse bitstream header.
+.TP
+.B \-h, \-help
+A short usage summary.
+.TP
+.B \-H, \-longhelp
+Detailed usage instructions.
+
+.SH INPUT
+Input files in WebP format. Input files must come last, following
+options (if any). There can be multiple input files.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+.br
+webpinfo \-h
+.br
+webpinfo \-diag \-summary input_file.webp
+.br
+webpinfo \-bitstream_info input_file_1.webp input_file_2.webp
+.br
+webpinfo *.webp
+
+.SH AUTHORS
+\fBwebpinfo\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Hui Su <huisu@google.com>,
+for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR webpmux (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/man/webpmux.1 b/man/webpmux.1
new file mode 100644
index 0000000..07e8738
--- /dev/null
+++ b/man/webpmux.1
@@ -0,0 +1,271 @@
+.\" Hey, EMACS: -*- nroff -*-
+.TH WEBPMUX 1 "November 17, 2021"
+.SH NAME
+webpmux \- create animated WebP files from non\-animated WebP images, extract
+frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
+.SH SYNOPSIS
+.B webpmux \-get
+.I GET_OPTIONS
+.I INPUT
+.B \-o
+.I OUTPUT
+.br
+.B webpmux \-set
+.I SET_OPTIONS
+.I INPUT
+.B \-o
+.I OUTPUT
+.br
+.B webpmux \-strip
+.I STRIP_OPTIONS
+.I INPUT
+.B \-o
+.I OUTPUT
+.br
+.B webpmux \-frame
+.I FRAME_OPTIONS
+.B [ \-frame ... ] [ \-loop
+.I LOOP_COUNT
+.B ]
+.br
+.RS 8
+.B [ \-bgcolor
+.I BACKGROUND_COLOR
+.B ] \-o
+.I OUTPUT
+.RE
+.br
+.B webpmux \-duration
+.I DURATION OPTIONS
+.B [ \-duration ... ]
+.I INPUT
+.B \-o
+.I OUTPUT
+.br
+.B webpmux \-info
+.I INPUT
+.br
+.B webpmux [\-h|\-help]
+.br
+.B webpmux \-version
+.br
+.B webpmux argument_file_name
+.SH DESCRIPTION
+This manual page documents the
+.B webpmux
+command.
+.PP
+\fBwebpmux\fP can be used to create/extract from animated WebP files, as well as
+to add/extract/strip XMP/EXIF metadata and ICC profile.
+If a single file name (not starting with the character '\-') is supplied as
+the argument, the command line arguments are actually tokenized from this file.
+This allows for easy scripting or using a large number of arguments.
+.SH OPTIONS
+.SS GET_OPTIONS (\-get):
+.TP
+.B icc
+Get ICC profile.
+.TP
+.B exif
+Get EXIF metadata.
+.TP
+.B xmp
+Get XMP metadata.
+.TP
+.BI frame " n
+Get nth frame from an animated image. (n = 0 has a special meaning: last frame).
+
+.SS SET_OPTIONS (\-set)
+.TP
+.BI loop " loop_count
+Set loop count on an animated file.
+.P
+Where: 'loop_count' must be in range [0, 65535].
+.TP
+.BI bgcolor " A,R,G,B
+Set the background color of the canvas on an animated file.
+.P
+where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the
+Alpha, Red, Green and Blue component values respectively.
+.TP
+.BI icc " file.icc
+Set ICC profile.
+.P
+Where: 'file.icc' contains the ICC profile to be set.
+.TP
+.BI exif " file.exif
+Set EXIF metadata.
+.P
+Where: 'file.exif' contains the EXIF metadata to be set.
+.TP
+.BI xmp " file.xmp
+Set XMP metadata.
+.P
+Where: 'file.xmp' contains the XMP metadata to be set.
+
+.SS STRIP_OPTIONS (\-strip)
+.TP
+.B icc
+Strip ICC profile.
+.TP
+.B exif
+Strip EXIF metadata.
+.TP
+.B xmp
+Strip XMP metadata.
+
+.SS DURATION_OPTIONS (\-duration)
+Amend the duration of a specific interval of frames. This option is only
+effective on animated WebP and has no effect on a single-frame file.
+.TP
+.I duration[,start[,end]]
+Where:
+.br
+.B duration
+is the duration for the interval in milliseconds (mandatory).
+Must be non-negative.
+.br
+.B start
+is the starting frame index of the interval (optional).
+.br
+.B end
+is the ending frame index (inclusive) of the interval (optional).
+.TP
+The three typical usages of this option are:
+.br
+.B -duration d
+ set the duration to 'd' for the whole animation.
+.br
+.B -duration d,f
+ set the duration of frame 'f' to 'd'.
+.br
+.B -duration d,start,end
+ set the duration to 'd' for the whole [start,end] interval.
+.TP
+.P
+Note that the frames outside of the [start, end] interval will remain untouched.
+The 'end' value '0' has the special meaning 'last frame of the animation'.
+.TP
+.I Reminder:
+frame indexing starts at '1'.
+.br
+
+.SS FRAME_OPTIONS (\-frame)
+Create an animated WebP file from multiple (non\-animated) WebP images.
+.TP
+.I file_i +di[+xi+yi[+mi[bi]]]
+Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image
+offset for this frame, 'di' is the pause duration before next frame, 'mi' is
+the dispose method for this frame (0 for NONE or 1 for BACKGROUND) and 'bi' is
+the blending method for this frame (+b for BLEND or \-b for NO_BLEND).
+Argument 'bi' can be omitted and will default to +b (BLEND).
+Also, 'mi' can be omitted if 'bi' is omitted and will default to 0 (NONE).
+Finally, if 'mi' and 'bi' are omitted then 'xi' and 'yi' can be omitted and will
+default to +0+0.
+.TP
+.BI \-loop " n
+Loop the frames n number of times. 0 indicates the frames should loop forever.
+Valid range is 0 to 65535 [Default: 0 (infinite)].
+.TP
+.BI \-bgcolor " A,R,G,B
+Background color of the canvas.
+.br
+where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the
+Alpha, Red, Green and Blue component values respectively
+[Default: 255,255,255,255].
+
+.SS INPUT
+.TP
+Input file in WebP format.
+
+.SS OUTPUT (\-o)
+.TP
+Output file in WebP format.
+
+.SS Note:
+.TP
+The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid.
+
+.SH BUGS
+Please report all bugs to the issue tracker:
+https://bugs.chromium.org/p/webp
+.br
+Patches welcome! See this page to get started:
+https://www.webmproject.org/code/contribute/submitting\-patches/
+
+.SH EXAMPLES
+.P
+Add ICC profile:
+.br
+webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp
+.P
+Extract ICC profile:
+.br
+webpmux \-get icc icc_container.webp \-o image_profile.icc
+.P
+Strip ICC profile:
+.br
+webpmux \-strip icc icc_container.webp \-o without_icc.webp
+.P
+Add XMP metadata:
+.br
+webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp
+.P
+Extract XMP metadata:
+.br
+webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp
+.P
+Strip XMP metadata:
+.br
+webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp
+.P
+Add EXIF metadata:
+.br
+webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp
+.P
+Extract EXIF metadata:
+.br
+webpmux \-get exif exif_container.webp \-o image_metadata.exif
+.P
+Strip EXIF metadata:
+.br
+webpmux \-strip exif exif_container.webp \-o without_exif.webp
+.P
+Create an animated WebP file from 3 (non\-animated) WebP images:
+.br
+webpmux \-frame 1.webp +100 \-frame 2.webp +100+50+50
+.br
+.RS 8
+\-frame 3.webp +100+50+50+1+b \-loop 10 \-bgcolor 255,255,255,255
+.br
+\-o anim_container.webp
+.RE
+.P
+Get the 2nd frame from an animated WebP file:
+.br
+webpmux \-get frame 2 anim_container.webp \-o frame_2.webp
+.P
+Using \-get/\-set/\-strip with input file name starting with '\-':
+.br
+webpmux \-set icc image_profile.icc \-o icc_container.webp \-\- \-\-\-in.webp
+.br
+webpmux \-get icc \-o image_profile.icc \-\- \-\-\-icc_container.webp
+.br
+webpmux \-strip icc \-o without_icc.webp \-\- \-\-\-icc_container.webp
+
+.SH AUTHORS
+\fBwebpmux\fP is a part of libwebp and was written by the WebP team.
+.br
+The latest source tree is available at
+https://chromium.googlesource.com/webm/libwebp
+.PP
+This manual page was written by Vikas Arora <vikaas.arora@gmail.com>,
+for the Debian project (and may be used by others).
+
+.SH SEE ALSO
+.BR cwebp (1),
+.BR dwebp (1),
+.BR gif2webp (1)
+.br
+Please refer to https://developers.google.com/speed/webp/ for additional
+information.
diff --git a/sharpyuv/Makefile.am b/sharpyuv/Makefile.am
new file mode 100644
index 0000000..b6b4675
--- /dev/null
+++ b/sharpyuv/Makefile.am
@@ -0,0 +1,41 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
+
+lib_LTLIBRARIES = libsharpyuv.la
+
+noinst_LTLIBRARIES =
+noinst_LTLIBRARIES += libsharpyuv_sse2.la
+noinst_LTLIBRARIES += libsharpyuv_neon.la
+
+libsharpyuvinclude_HEADERS =
+libsharpyuvinclude_HEADERS += sharpyuv.h
+libsharpyuvinclude_HEADERS += sharpyuv_csp.h
+noinst_HEADERS =
+noinst_HEADERS += ../src/dsp/cpu.c
+noinst_HEADERS += ../src/dsp/cpu.h
+noinst_HEADERS += ../src/webp/types.h
+
+libsharpyuv_sse2_la_SOURCES =
+libsharpyuv_sse2_la_SOURCES += sharpyuv_sse2.c
+libsharpyuv_sse2_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS)
+libsharpyuv_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS)
+
+libsharpyuv_neon_la_SOURCES =
+libsharpyuv_neon_la_SOURCES += sharpyuv_neon.c
+libsharpyuv_neon_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS)
+libsharpyuv_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
+
+libsharpyuv_la_SOURCES =
+libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h
+libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
+libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
+libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
+libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
+
+libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
+libsharpyuv_la_LDFLAGS = -no-undefined -version-info 0:0:0 -lm
+libsharpyuv_la_LIBADD =
+libsharpyuv_la_LIBADD += libsharpyuv_sse2.la
+libsharpyuv_la_LIBADD += libsharpyuv_neon.la
+libsharpyuvincludedir = $(includedir)/webp/sharpyuv
+pkgconfig_DATA = libsharpyuv.pc
diff --git a/sharpyuv/libsharpyuv.pc.in b/sharpyuv/libsharpyuv.pc.in
new file mode 100644
index 0000000..0fb565a
--- /dev/null
+++ b/sharpyuv/libsharpyuv.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/webp
+
+Name: libsharpyuv
+Description: Library for sharp RGB to YUV conversion
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -l@webp_libname_prefix@sharpyuv
+Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
diff --git a/sharpyuv/libsharpyuv.rc b/sharpyuv/libsharpyuv.rc
new file mode 100644
index 0000000..7f1df72
--- /dev/null
+++ b/sharpyuv/libsharpyuv.rc
@@ -0,0 +1,41 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,2,0
+ PRODUCTVERSION 0,0,2,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google, Inc."
+ VALUE "FileDescription", "libsharpyuv DLL"
+ VALUE "FileVersion", "0.2.0"
+ VALUE "InternalName", "libsharpyuv.dll"
+ VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "OriginalFilename", "libsharpyuv.dll"
+ VALUE "ProductName", "SharpYuv Library"
+ VALUE "ProductVersion", "0.2.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
diff --git a/sharpyuv/sharpyuv.c b/sharpyuv/sharpyuv.c
new file mode 100644
index 0000000..7de34fb
--- /dev/null
+++ b/sharpyuv/sharpyuv.c
@@ -0,0 +1,526 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Sharp RGB to YUV conversion.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/webp/types.h"
+#include "sharpyuv/sharpyuv_cpu.h"
+#include "sharpyuv/sharpyuv_dsp.h"
+#include "sharpyuv/sharpyuv_gamma.h"
+
+//------------------------------------------------------------------------------
+
+int SharpYuvGetVersion(void) {
+ return SHARPYUV_VERSION;
+}
+
+//------------------------------------------------------------------------------
+// Sharp RGB->YUV conversion
+
+static const int kNumIterations = 4;
+
+#define YUV_FIX 16 // fixed-point precision for RGB->YUV
+static const int kYuvHalf = 1 << (YUV_FIX - 1);
+
+// Max bit depth so that intermediate calculations fit in 16 bits.
+static const int kMaxBitDepth = 14;
+
+// Returns the precision shift to use based on the input rgb_bit_depth.
+static int GetPrecisionShift(int rgb_bit_depth) {
+ // Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove
+ // bits if needed.
+ return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2
+ : (kMaxBitDepth - rgb_bit_depth);
+}
+
+typedef int16_t fixed_t; // signed type with extra precision for UV
+typedef uint16_t fixed_y_t; // unsigned type with extra precision for W
+
+//------------------------------------------------------------------------------
+
+static uint8_t clip_8b(fixed_t v) {
+ return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
+}
+
+static uint16_t clip(fixed_t v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static fixed_y_t clip_bit_depth(int y, int bit_depth) {
+ const int max = (1 << bit_depth) - 1;
+ return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max;
+}
+
+//------------------------------------------------------------------------------
+
+static int RGBToGray(int64_t r, int64_t g, int64_t b) {
+ const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf;
+ return (int)(luma >> YUV_FIX);
+}
+
+static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
+ int rgb_bit_depth) {
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
+ const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
+ const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
+ const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
+ return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
+}
+
+static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
+ int rgb_bit_depth) {
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
+ const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
+ const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
+ const uint32_t Y = RGBToGray(R, G, B);
+ dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
+ }
+}
+
+static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
+ fixed_t* dst, int uv_w, int rgb_bit_depth) {
+ int i;
+ for (i = 0; i < uv_w; ++i) {
+ const int r =
+ ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
+ src2[0 * uv_w + 1], rgb_bit_depth);
+ const int g =
+ ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
+ src2[2 * uv_w + 1], rgb_bit_depth);
+ const int b =
+ ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
+ src2[4 * uv_w + 1], rgb_bit_depth);
+ const int W = RGBToGray(r, g, b);
+ dst[0 * uv_w] = (fixed_t)(r - W);
+ dst[1 * uv_w] = (fixed_t)(g - W);
+ dst[2 * uv_w] = (fixed_t)(b - W);
+ dst += 1;
+ src1 += 2;
+ src2 += 2;
+ }
+}
+
+static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
+ int i;
+ assert(w > 0);
+ for (i = 0; i < w; ++i) {
+ y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) {
+ const int v0 = (A * 3 + B + 2) >> 2;
+ return clip_bit_depth(v0 + W0, bit_depth);
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int Shift(int v, int shift) {
+ return (shift >= 0) ? (v << shift) : (v >> -shift);
+}
+
+static void ImportOneRow(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int rgb_step,
+ int rgb_bit_depth,
+ int pic_width,
+ fixed_y_t* const dst) {
+ // Convert the rgb_step from a number of bytes to a number of uint8_t or
+ // uint16_t values depending the bit depth.
+ const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
+ int i;
+ const int w = (pic_width + 1) & ~1;
+ for (i = 0; i < pic_width; ++i) {
+ const int off = i * step;
+ const int shift = GetPrecisionShift(rgb_bit_depth);
+ if (rgb_bit_depth == 8) {
+ dst[i + 0 * w] = Shift(r_ptr[off], shift);
+ dst[i + 1 * w] = Shift(g_ptr[off], shift);
+ dst[i + 2 * w] = Shift(b_ptr[off], shift);
+ } else {
+ dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift);
+ dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
+ dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
+ }
+ }
+ if (pic_width & 1) { // replicate rightmost pixel
+ dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
+ dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
+ dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
+ }
+}
+
+static void InterpolateTwoRows(const fixed_y_t* const best_y,
+ const fixed_t* prev_uv,
+ const fixed_t* cur_uv,
+ const fixed_t* next_uv,
+ int w,
+ fixed_y_t* out1,
+ fixed_y_t* out2,
+ int rgb_bit_depth) {
+ const int uv_w = w >> 1;
+ const int len = (w - 1) >> 1; // length to filter
+ int k = 3;
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ while (k-- > 0) { // process each R/G/B segments in turn
+ // special boundary case for i==0
+ out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth);
+ out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth);
+
+ SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1,
+ bit_depth);
+ SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1,
+ bit_depth);
+
+ // special boundary case for i == w - 1 when w is even
+ if (!(w & 1)) {
+ out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
+ best_y[w - 1 + 0], bit_depth);
+ out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
+ best_y[w - 1 + w], bit_depth);
+ }
+ out1 += w;
+ out2 += w;
+ prev_uv += uv_w;
+ cur_uv += uv_w;
+ next_uv += uv_w;
+ }
+}
+
+static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b,
+ const int coeffs[4], int sfix) {
+ const int srounder = 1 << (YUV_FIX + sfix - 1);
+ const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b +
+ coeffs[3] + srounder;
+ return (luma >> (YUV_FIX + sfix));
+}
+
+static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
+ uint8_t* y_ptr, int y_stride, uint8_t* u_ptr,
+ int u_stride, uint8_t* v_ptr, int v_stride,
+ int rgb_bit_depth,
+ int yuv_bit_depth, int width, int height,
+ const SharpYuvConversionMatrix* yuv_matrix) {
+ int i, j;
+ const fixed_t* const best_uv_base = best_uv;
+ const int w = (width + 1) & ~1;
+ const int h = (height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ const int sfix = GetPrecisionShift(rgb_bit_depth);
+ const int yuv_max = (1 << yuv_bit_depth) - 1;
+
+ for (best_uv = best_uv_base, j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ const int off = (i >> 1);
+ const int W = best_y[i];
+ const int r = best_uv[off + 0 * uv_w] + W;
+ const int g = best_uv[off + 1 * uv_w] + W;
+ const int b = best_uv[off + 2 * uv_w] + W;
+ const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix);
+ if (yuv_bit_depth <= 8) {
+ y_ptr[i] = clip_8b(y);
+ } else {
+ ((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
+ }
+ }
+ best_y += w;
+ best_uv += (j & 1) * 3 * uv_w;
+ y_ptr += y_stride;
+ }
+ for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
+ for (i = 0; i < uv_w; ++i) {
+ const int off = i;
+ // Note r, g and b values here are off by W, but a constant offset on all
+ // 3 components doesn't change the value of u and v with a YCbCr matrix.
+ const int r = best_uv[off + 0 * uv_w];
+ const int g = best_uv[off + 1 * uv_w];
+ const int b = best_uv[off + 2 * uv_w];
+ const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
+ const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
+ if (yuv_bit_depth <= 8) {
+ u_ptr[i] = clip_8b(u);
+ v_ptr[i] = clip_8b(v);
+ } else {
+ ((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
+ ((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
+ }
+ }
+ best_uv += 3 * uv_w;
+ u_ptr += u_stride;
+ v_ptr += v_stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Main function
+
+static void* SafeMalloc(uint64_t nmemb, size_t size) {
+ const uint64_t total_size = nmemb * (uint64_t)size;
+ if (total_size != (size_t)total_size) return NULL;
+ return malloc((size_t)total_size);
+}
+
+#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
+
+static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
+ const uint8_t* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, uint8_t* y_ptr, int y_stride,
+ uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height,
+ const SharpYuvConversionMatrix* yuv_matrix) {
+ // we expand the right/bottom border if needed
+ const int w = (width + 1) & ~1;
+ const int h = (height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ uint64_t prev_diff_y_sum = ~0;
+ int j, iter;
+
+ // TODO(skal): allocate one big memory chunk. But for now, it's easier
+ // for valgrind debugging to have several chunks.
+ fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
+ fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
+ fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
+ fixed_y_t* best_y = best_y_base;
+ fixed_y_t* target_y = target_y_base;
+ fixed_t* best_uv = best_uv_base;
+ fixed_t* target_uv = target_uv_base;
+ const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
+ int ok;
+ assert(w > 0);
+ assert(h > 0);
+
+ if (best_y_base == NULL || best_uv_base == NULL ||
+ target_y_base == NULL || target_uv_base == NULL ||
+ best_rgb_y == NULL || best_rgb_uv == NULL ||
+ tmp_buffer == NULL) {
+ ok = 0;
+ goto End;
+ }
+
+ // Import RGB samples to W/RGB representation.
+ for (j = 0; j < height; j += 2) {
+ const int is_last_row = (j == height - 1);
+ fixed_y_t* const src1 = tmp_buffer + 0 * w;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+
+ // prepare two rows of input
+ ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width,
+ src1);
+ if (!is_last_row) {
+ ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
+ rgb_step, rgb_bit_depth, width, src2);
+ } else {
+ memcpy(src2, src1, 3 * w * sizeof(*src2));
+ }
+ StoreGray(src1, best_y + 0, w);
+ StoreGray(src2, best_y + w, w);
+
+ UpdateW(src1, target_y, w, rgb_bit_depth);
+ UpdateW(src2, target_y + w, w, rgb_bit_depth);
+ UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
+ memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
+ best_y += 2 * w;
+ best_uv += 3 * uv_w;
+ target_y += 2 * w;
+ target_uv += 3 * uv_w;
+ r_ptr += 2 * rgb_stride;
+ g_ptr += 2 * rgb_stride;
+ b_ptr += 2 * rgb_stride;
+ }
+
+ // Iterate and resolve clipping conflicts.
+ for (iter = 0; iter < kNumIterations; ++iter) {
+ const fixed_t* cur_uv = best_uv_base;
+ const fixed_t* prev_uv = best_uv_base;
+ uint64_t diff_y_sum = 0;
+
+ best_y = best_y_base;
+ best_uv = best_uv_base;
+ target_y = target_y_base;
+ target_uv = target_uv_base;
+ for (j = 0; j < h; j += 2) {
+ fixed_y_t* const src1 = tmp_buffer + 0 * w;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+ {
+ const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
+ InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w,
+ src1, src2, rgb_bit_depth);
+ prev_uv = cur_uv;
+ cur_uv = next_uv;
+ }
+
+ UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
+ UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
+ UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
+
+ // update two rows of Y and one row of RGB
+ diff_y_sum +=
+ SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
+ rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
+ SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
+
+ best_y += 2 * w;
+ best_uv += 3 * uv_w;
+ target_y += 2 * w;
+ target_uv += 3 * uv_w;
+ }
+ // test exit condition
+ if (iter > 0) {
+ if (diff_y_sum < diff_y_threshold) break;
+ if (diff_y_sum > prev_diff_y_sum) break;
+ }
+ prev_diff_y_sum = diff_y_sum;
+ }
+
+ // final reconstruction
+ ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr,
+ u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth,
+ width, height, yuv_matrix);
+
+ End:
+ free(best_y_base);
+ free(best_uv_base);
+ free(target_y_base);
+ free(target_uv_base);
+ free(best_rgb_y);
+ free(best_rgb_uv);
+ free(tmp_buffer);
+ return ok;
+}
+#undef SAFE_ALLOC
+
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h> // NOLINT
+
+#define LOCK_ACCESS \
+ static pthread_mutex_t sharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; \
+ if (pthread_mutex_lock(&sharpyuv_lock)) return
+#define UNLOCK_ACCESS_AND_RETURN \
+ do { \
+ (void)pthread_mutex_unlock(&sharpyuv_lock); \
+ return; \
+ } while (0)
+#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
+#define LOCK_ACCESS do {} while (0)
+#define UNLOCK_ACCESS_AND_RETURN return
+#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
+
+// Hidden exported init function.
+// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed,
+// users can declare it as extern and call it with an alternate VP8CPUInfo
+// function.
+SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func);
+void SharpYuvInit(VP8CPUInfo cpu_info_func) {
+ static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
+ (VP8CPUInfo)&sharpyuv_last_cpuinfo_used;
+ LOCK_ACCESS;
+ // Only update SharpYuvGetCPUInfo when called from external code to avoid a
+ // race on reading the value in SharpYuvConvert().
+ if (cpu_info_func != (VP8CPUInfo)&SharpYuvGetCPUInfo) {
+ SharpYuvGetCPUInfo = cpu_info_func;
+ }
+ if (sharpyuv_last_cpuinfo_used == SharpYuvGetCPUInfo) {
+ UNLOCK_ACCESS_AND_RETURN;
+ }
+
+ SharpYuvInitDsp();
+ SharpYuvInitGammaTables();
+
+ sharpyuv_last_cpuinfo_used = SharpYuvGetCPUInfo;
+ UNLOCK_ACCESS_AND_RETURN;
+}
+
+int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, void* y_ptr, int y_stride,
+ void* u_ptr, int u_stride, void* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvConversionMatrix* yuv_matrix) {
+ SharpYuvConversionMatrix scaled_matrix;
+ const int rgb_max = (1 << rgb_bit_depth) - 1;
+ const int rgb_round = 1 << (rgb_bit_depth - 1);
+ const int yuv_max = (1 << yuv_bit_depth) - 1;
+ const int sfix = GetPrecisionShift(rgb_bit_depth);
+
+ if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
+ r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL ||
+ u_ptr == NULL || v_ptr == NULL) {
+ return 0;
+ }
+ if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 &&
+ rgb_bit_depth != 16) {
+ return 0;
+ }
+ if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
+ return 0;
+ }
+ if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
+ // Step/stride should be even for uint16_t buffers.
+ return 0;
+ }
+ if (yuv_bit_depth > 8 &&
+ (y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) {
+ // Stride should be even for uint16_t buffers.
+ return 0;
+ }
+ // The address of the function pointer is used to avoid a read race.
+ SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo);
+
+ // Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the
+ // rgb->yuv conversion matrix.
+ if (rgb_bit_depth == yuv_bit_depth) {
+ memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix));
+ } else {
+ int i;
+ for (i = 0; i < 3; ++i) {
+ scaled_matrix.rgb_to_y[i] =
+ (yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max;
+ scaled_matrix.rgb_to_u[i] =
+ (yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max;
+ scaled_matrix.rgb_to_v[i] =
+ (yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max;
+ }
+ }
+ // Also incorporate precision change scaling.
+ scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix);
+ scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix);
+ scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix);
+
+ return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
+ rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
+ v_ptr, v_stride, yuv_bit_depth, width, height,
+ &scaled_matrix);
+}
+
+//------------------------------------------------------------------------------
diff --git a/sharpyuv/sharpyuv.h b/sharpyuv/sharpyuv.h
new file mode 100644
index 0000000..181b20a
--- /dev/null
+++ b/sharpyuv/sharpyuv.h
@@ -0,0 +1,103 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Sharp RGB to YUV conversion.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_H_
+#define WEBP_SHARPYUV_SHARPYUV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SHARPYUV_EXTERN
+#ifdef WEBP_EXTERN
+#define SHARPYUV_EXTERN WEBP_EXTERN
+#else
+// This explicitly marks library functions and allows for changing the
+// signature for e.g., Windows DLL builds.
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
+#else
+#if defined(_MSC_VER) && defined(WEBP_DLL)
+#define SHARPYUV_EXTERN __declspec(dllexport)
+#else
+#define SHARPYUV_EXTERN extern
+#endif /* _MSC_VER && WEBP_DLL */
+#endif /* __GNUC__ >= 4 */
+#endif /* WEBP_EXTERN */
+#endif /* SHARPYUV_EXTERN */
+
+// SharpYUV API version following the convention from semver.org
+#define SHARPYUV_VERSION_MAJOR 0
+#define SHARPYUV_VERSION_MINOR 2
+#define SHARPYUV_VERSION_PATCH 0
+// Version as a uint32_t. The major number is the high 8 bits.
+// The minor number is the middle 8 bits. The patch number is the low 16 bits.
+#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
+ (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH))
+#define SHARPYUV_VERSION \
+ SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \
+ SHARPYUV_VERSION_PATCH)
+
+// Returns the library's version number, packed in hexadecimal. See
+// SHARPYUV_VERSION.
+SHARPYUV_EXTERN int SharpYuvGetVersion(void);
+
+// RGB to YUV conversion matrix, in 16 bit fixed point.
+// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3]
+// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3]
+// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3]
+// Then y, u and v values are divided by 1<<16 and rounded.
+typedef struct {
+ int rgb_to_y[4];
+ int rgb_to_u[4];
+ int rgb_to_v[4];
+} SharpYuvConversionMatrix;
+
+// Converts RGB to YUV420 using a downsampling algorithm that minimizes
+// artefacts caused by chroma subsampling.
+// This is slower than standard downsampling (averaging of 4 UV values).
+// Assumes that the image will be upsampled using a bilinear filter. If nearest
+// neighbor is used instead, the upsampled image might look worse than with
+// standard downsampling.
+// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
+// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
+// rgb_step: distance in bytes between two horizontally adjacent pixels on the
+// r, g and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_stride: distance in bytes between two vertically adjacent pixels on the
+// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16.
+// Note: 16 bit input is truncated to 14 bits before conversion to yuv.
+// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12.
+// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should
+// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers
+// otherwise.
+// y_stride, u_stride, v_stride: distance in bytes between two vertically
+// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
+// should be multiples of 2.
+// width, height: width and height of the image in pixels
+SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step,
+ int rgb_stride, int rgb_bit_depth,
+ void* y_ptr, int y_stride, void* u_ptr,
+ int u_stride, void* v_ptr, int v_stride,
+ int yuv_bit_depth, int width, int height,
+ const SharpYuvConversionMatrix* yuv_matrix);
+
+// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
+// support (it's rarely used in practice, especially for images).
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_H_
diff --git a/sharpyuv/sharpyuv_cpu.c b/sharpyuv/sharpyuv_cpu.c
new file mode 100644
index 0000000..29425a0
--- /dev/null
+++ b/sharpyuv/sharpyuv_cpu.c
@@ -0,0 +1,14 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+#include "sharpyuv/sharpyuv_cpu.h"
+
+// Include src/dsp/cpu.c to create SharpYuvGetCPUInfo from VP8GetCPUInfo. The
+// function pointer is renamed in sharpyuv_cpu.h.
+#include "src/dsp/cpu.c"
diff --git a/sharpyuv/sharpyuv_cpu.h b/sharpyuv/sharpyuv_cpu.h
new file mode 100644
index 0000000..176ca3e
--- /dev/null
+++ b/sharpyuv/sharpyuv_cpu.h
@@ -0,0 +1,22 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+#ifndef WEBP_SHARPYUV_SHARPYUV_CPU_H_
+#define WEBP_SHARPYUV_SHARPYUV_CPU_H_
+
+#include "sharpyuv/sharpyuv.h"
+
+// Avoid exporting SharpYuvGetCPUInfo in shared object / DLL builds.
+// SharpYuvInit() replaces the use of the function pointer.
+#undef WEBP_EXTERN
+#define WEBP_EXTERN extern
+#define VP8GetCPUInfo SharpYuvGetCPUInfo
+#include "src/dsp/cpu.h"
+
+#endif // WEBP_SHARPYUV_SHARPYUV_CPU_H_
diff --git a/sharpyuv/sharpyuv_csp.c b/sharpyuv/sharpyuv_csp.c
new file mode 100644
index 0000000..0ad22be
--- /dev/null
+++ b/sharpyuv/sharpyuv_csp.c
@@ -0,0 +1,110 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Colorspace utilities.
+
+#include "sharpyuv/sharpyuv_csp.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stddef.h>
+
+static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); }
+
+void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
+ SharpYuvConversionMatrix* matrix) {
+ const float kr = yuv_color_space->kr;
+ const float kb = yuv_color_space->kb;
+ const float kg = 1.0f - kr - kb;
+ const float cr = 0.5f / (1.0f - kb);
+ const float cb = 0.5f / (1.0f - kr);
+
+ const int shift = yuv_color_space->bit_depth - 8;
+
+ const float denom = (float)((1 << yuv_color_space->bit_depth) - 1);
+ float scale_y = 1.0f;
+ float add_y = 0.0f;
+ float scale_u = cr;
+ float scale_v = cb;
+ float add_uv = (float)(128 << shift);
+ assert(yuv_color_space->bit_depth >= 8);
+
+ if (yuv_color_space->range == kSharpYuvRangeLimited) {
+ scale_y *= (219 << shift) / denom;
+ scale_u *= (224 << shift) / denom;
+ scale_v *= (224 << shift) / denom;
+ add_y = (float)(16 << shift);
+ }
+
+ matrix->rgb_to_y[0] = ToFixed16(kr * scale_y);
+ matrix->rgb_to_y[1] = ToFixed16(kg * scale_y);
+ matrix->rgb_to_y[2] = ToFixed16(kb * scale_y);
+ matrix->rgb_to_y[3] = ToFixed16(add_y);
+
+ matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u);
+ matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u);
+ matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u);
+ matrix->rgb_to_u[3] = ToFixed16(add_uv);
+
+ matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v);
+ matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v);
+ matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v);
+ matrix->rgb_to_v[3] = ToFixed16(add_uv);
+}
+
+// Matrices are in YUV_FIX fixed point precision.
+// WebP's matrix, similar but not identical to kRec601LimitedMatrix.
+static const SharpYuvConversionMatrix kWebpMatrix = {
+ {16839, 33059, 6420, 16 << 16},
+ {-9719, -19081, 28800, 128 << 16},
+ {28800, -24116, -4684, 128 << 16},
+};
+// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited
+static const SharpYuvConversionMatrix kRec601LimitedMatrix = {
+ {16829, 33039, 6416, 16 << 16},
+ {-9714, -19071, 28784, 128 << 16},
+ {28784, -24103, -4681, 128 << 16},
+};
+// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull
+static const SharpYuvConversionMatrix kRec601FullMatrix = {
+ {19595, 38470, 7471, 0},
+ {-11058, -21710, 32768, 128 << 16},
+ {32768, -27439, -5329, 128 << 16},
+};
+// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited
+static const SharpYuvConversionMatrix kRec709LimitedMatrix = {
+ {11966, 40254, 4064, 16 << 16},
+ {-6596, -22189, 28784, 128 << 16},
+ {28784, -26145, -2639, 128 << 16},
+};
+// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull
+static const SharpYuvConversionMatrix kRec709FullMatrix = {
+ {13933, 46871, 4732, 0},
+ {-7509, -25259, 32768, 128 << 16},
+ {32768, -29763, -3005, 128 << 16},
+};
+
+const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
+ SharpYuvMatrixType matrix_type) {
+ switch (matrix_type) {
+ case kSharpYuvMatrixWebp:
+ return &kWebpMatrix;
+ case kSharpYuvMatrixRec601Limited:
+ return &kRec601LimitedMatrix;
+ case kSharpYuvMatrixRec601Full:
+ return &kRec601FullMatrix;
+ case kSharpYuvMatrixRec709Limited:
+ return &kRec709LimitedMatrix;
+ case kSharpYuvMatrixRec709Full:
+ return &kRec709FullMatrix;
+ case kSharpYuvMatrixNum:
+ return NULL;
+ }
+ return NULL;
+}
diff --git a/sharpyuv/sharpyuv_csp.h b/sharpyuv/sharpyuv_csp.h
new file mode 100644
index 0000000..3214e3a
--- /dev/null
+++ b/sharpyuv/sharpyuv_csp.h
@@ -0,0 +1,60 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Colorspace utilities.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_
+#define WEBP_SHARPYUV_SHARPYUV_CSP_H_
+
+#include "sharpyuv/sharpyuv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Range of YUV values.
+typedef enum {
+ kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit)
+ kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit)
+} SharpYuvRange;
+
+// Constants that define a YUV color space.
+typedef struct {
+ // Kr and Kb are defined such that:
+ // Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb.
+ float kr;
+ float kb;
+ int bit_depth; // 8, 10 or 12
+ SharpYuvRange range;
+} SharpYuvColorSpace;
+
+// Fills in 'matrix' for the given YUVColorSpace.
+SHARPYUV_EXTERN void SharpYuvComputeConversionMatrix(
+ const SharpYuvColorSpace* yuv_color_space,
+ SharpYuvConversionMatrix* matrix);
+
+// Enums for precomputed conversion matrices.
+typedef enum {
+ kSharpYuvMatrixWebp = 0,
+ kSharpYuvMatrixRec601Limited,
+ kSharpYuvMatrixRec601Full,
+ kSharpYuvMatrixRec709Limited,
+ kSharpYuvMatrixRec709Full,
+ kSharpYuvMatrixNum
+} SharpYuvMatrixType;
+
+// Returns a pointer to a matrix for one of the predefined colorspaces.
+SHARPYUV_EXTERN const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
+ SharpYuvMatrixType matrix_type);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_
diff --git a/sharpyuv/sharpyuv_dsp.c b/sharpyuv/sharpyuv_dsp.c
new file mode 100644
index 0000000..31c272c
--- /dev/null
+++ b/sharpyuv/sharpyuv_dsp.c
@@ -0,0 +1,103 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "sharpyuv/sharpyuv_cpu.h"
+
+//-----------------------------------------------------------------------------
+
+#if !WEBP_NEON_OMIT_C_CODE
+static uint16_t clip(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ uint64_t diff = 0;
+ int i;
+ const int max_y = (1 << bit_depth) - 1;
+ for (i = 0; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)dst[i] + diff_y;
+ dst[i] = clip(new_y, max_y);
+ diff += (uint64_t)abs(diff_y);
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i;
+ for (i = 0; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ int i;
+ const int max_y = (1 << bit_depth) - 1;
+ for (i = 0; i < len; ++i, ++A, ++B) {
+ const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
+ const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
+ out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+#endif // !WEBP_NEON_OMIT_C_CODE
+
+//-----------------------------------------------------------------------------
+
+uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
+ uint16_t* dst, int len, int bit_depth);
+void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
+ int len);
+void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth);
+
+extern void InitSharpYuvSSE2(void);
+extern void InitSharpYuvNEON(void);
+
+void SharpYuvInitDsp(void) {
+#if !WEBP_NEON_OMIT_C_CODE
+ SharpYuvUpdateY = SharpYuvUpdateY_C;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
+ SharpYuvFilterRow = SharpYuvFilterRow_C;
+#endif
+
+ if (SharpYuvGetCPUInfo != NULL) {
+#if defined(WEBP_HAVE_SSE2)
+ if (SharpYuvGetCPUInfo(kSSE2)) {
+ InitSharpYuvSSE2();
+ }
+#endif // WEBP_HAVE_SSE2
+ }
+
+#if defined(WEBP_HAVE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) {
+ InitSharpYuvNEON();
+ }
+#endif // WEBP_HAVE_NEON
+
+ assert(SharpYuvUpdateY != NULL);
+ assert(SharpYuvUpdateRGB != NULL);
+ assert(SharpYuvFilterRow != NULL);
+}
diff --git a/sharpyuv/sharpyuv_dsp.h b/sharpyuv/sharpyuv_dsp.h
new file mode 100644
index 0000000..805fbad
--- /dev/null
+++ b/sharpyuv/sharpyuv_dsp.h
@@ -0,0 +1,28 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
+#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
+
+#include "sharpyuv/sharpyuv_cpu.h"
+#include "src/webp/types.h"
+
+extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
+ uint16_t* dst, int len, int bit_depth);
+extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref,
+ int16_t* dst, int len);
+extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth);
+
+void SharpYuvInitDsp(void);
+
+#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_
diff --git a/sharpyuv/sharpyuv_gamma.c b/sharpyuv/sharpyuv_gamma.c
new file mode 100644
index 0000000..20ab2da
--- /dev/null
+++ b/sharpyuv/sharpyuv_gamma.c
@@ -0,0 +1,113 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Gamma correction utilities.
+
+#include "sharpyuv/sharpyuv_gamma.h"
+
+#include <assert.h>
+#include <math.h>
+
+#include "src/webp/types.h"
+
+// Gamma correction compensates loss of resolution during chroma subsampling.
+// Size of pre-computed table for converting from gamma to linear.
+#define GAMMA_TO_LINEAR_TAB_BITS 10
+#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS)
+static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2];
+#define LINEAR_TO_GAMMA_TAB_BITS 9
+#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS)
+static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2];
+
+static const double kGammaF = 1. / 0.45;
+#define GAMMA_TO_LINEAR_BITS 16
+
+static volatile int kGammaTablesSOk = 0;
+void SharpYuvInitGammaTables(void) {
+ assert(GAMMA_TO_LINEAR_BITS <= 16);
+ if (!kGammaTablesSOk) {
+ int v;
+ const double a = 0.09929682680944;
+ const double thresh = 0.018053968510807;
+ const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
+ // Precompute gamma to linear table.
+ {
+ const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE;
+ const double a_rec = 1. / (1. + a);
+ for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) {
+ const double g = norm * v;
+ double value;
+ if (g <= thresh * 4.5) {
+ value = g / 4.5;
+ } else {
+ value = pow(a_rec * (g + a), kGammaF);
+ }
+ kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
+ }
+ // to prevent small rounding errors to cause read-overflow:
+ kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] =
+ kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE];
+ }
+ // Precompute linear to gamma table.
+ {
+ const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE;
+ for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) {
+ const double g = scale * v;
+ double value;
+ if (g <= thresh) {
+ value = 4.5 * g;
+ } else {
+ value = (1. + a) * pow(g, 1. / kGammaF) - a;
+ }
+ kLinearToGammaTabS[v] =
+ (uint32_t)(final_scale * value + 0.5);
+ }
+ // to prevent small rounding errors to cause read-overflow:
+ kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] =
+ kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE];
+ }
+ kGammaTablesSOk = 1;
+ }
+}
+
+static WEBP_INLINE int Shift(int v, int shift) {
+ return (shift >= 0) ? (v << shift) : (v >> -shift);
+}
+
+static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
+ int tab_pos_shift_right,
+ int tab_value_shift) {
+ const uint32_t tab_pos = Shift(v, -tab_pos_shift_right);
+ // fractional part, in 'tab_pos_shift' fixed-point precision
+ const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part
+ // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1])
+ const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift);
+ const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift);
+ // Final interpolation.
+ const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
+ const int half =
+ (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0;
+ const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right);
+ return result;
+}
+
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
+ const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
+ if (shift > 0) {
+ return kGammaToLinearTabS[v << shift];
+ }
+ return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
+}
+
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
+ return FixedPointInterpolation(
+ value, kLinearToGammaTabS,
+ (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
+ bit_depth - GAMMA_TO_LINEAR_BITS);
+}
diff --git a/sharpyuv/sharpyuv_gamma.h b/sharpyuv/sharpyuv_gamma.h
new file mode 100644
index 0000000..d13aff5
--- /dev/null
+++ b/sharpyuv/sharpyuv_gamma.h
@@ -0,0 +1,35 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Gamma correction utilities.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+
+#include "src/webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initializes precomputed tables. Must be called once before calling
+// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
+void SharpYuvInitGammaTables(void);
+
+// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
+
+// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
diff --git a/sharpyuv/sharpyuv_neon.c b/sharpyuv/sharpyuv_neon.c
new file mode 100644
index 0000000..5840914
--- /dev/null
+++ b/sharpyuv/sharpyuv_neon.c
@@ -0,0 +1,181 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#if defined(WEBP_USE_NEON)
+#include <assert.h>
+#include <stdlib.h>
+#include <arm_neon.h>
+
+static uint16_t clip_NEON(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const int16x8_t zero = vdupq_n_s16(0);
+ const int16x8_t max = vdupq_n_s16(max_y);
+ uint64x2_t sum = vdupq_n_u64(0);
+ uint64_t diff;
+
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
+ const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
+ const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
+ const int16x8_t D = vsubq_s16(A, B); // diff_y
+ const int16x8_t F = vaddq_s16(C, D); // new_y
+ const uint16x8_t H =
+ vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
+ const int16x8_t I = vabsq_s16(D); // abs(diff_y)
+ vst1q_u16(dst + i, H);
+ sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
+ }
+ diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
+ for (; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)(dst[i]) + diff_y;
+ dst[i] = clip_NEON(new_y, max_y);
+ diff += (uint64_t)(abs(diff_y));
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i;
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t A = vld1q_s16(ref + i);
+ const int16x8_t B = vld1q_s16(src + i);
+ const int16x8_t C = vld1q_s16(dst + i);
+ const int16x8_t D = vsubq_s16(A, B); // diff_uv
+ const int16x8_t E = vaddq_s16(C, D); // new_uv
+ vst1q_s16(dst + i, E);
+ }
+ for (; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const int16x8_t max = vdupq_n_s16(max_y);
+ const int16x8_t zero = vdupq_n_s16(0);
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t a0 = vld1q_s16(A + i + 0);
+ const int16x8_t a1 = vld1q_s16(A + i + 1);
+ const int16x8_t b0 = vld1q_s16(B + i + 0);
+ const int16x8_t b1 = vld1q_s16(B + i + 1);
+ const int16x8_t a0b1 = vaddq_s16(a0, b1);
+ const int16x8_t a1b0 = vaddq_s16(a1, b0);
+ const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
+ const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
+ const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
+ const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
+ const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
+ const int16x8_t e0 = vrhaddq_s16(c1, a0);
+ const int16x8_t e1 = vrhaddq_s16(c0, a1);
+ const int16x8x2_t f = vzipq_s16(e0, e1);
+ const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
+ const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
+ const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
+ const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
+ const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
+ const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
+ vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
+ vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
+ }
+ for (; i < len; ++i) {
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const uint16x8_t max = vdupq_n_u16(max_y);
+ for (i = 0; i + 4 <= len; i += 4) {
+ const int16x4_t a0 = vld1_s16(A + i + 0);
+ const int16x4_t a1 = vld1_s16(A + i + 1);
+ const int16x4_t b0 = vld1_s16(B + i + 0);
+ const int16x4_t b1 = vld1_s16(B + i + 1);
+ const int32x4_t a0b1 = vaddl_s16(a0, b1);
+ const int32x4_t a1b0 = vaddl_s16(a1, b0);
+ const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1
+ const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1)
+ const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0)
+ const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3);
+ const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3);
+ const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0));
+ const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1));
+ const int32x4x2_t f = vzipq_s32(e0, e1);
+
+ const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i));
+ const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g));
+ const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g));
+ const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1));
+ const uint16x8_t i_clamped = vminq_u16(i_16, max);
+ vst1q_u16(out + 2 * i + 0, i_clamped);
+ }
+ for (; i < len; ++i) {
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ if (bit_depth <= 10) {
+ SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth);
+ } else {
+ SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void InitSharpYuvNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
+ SharpYuvUpdateY = SharpYuvUpdateY_NEON;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON;
+ SharpYuvFilterRow = SharpYuvFilterRow_NEON;
+}
+
+#else // !WEBP_USE_NEON
+
+extern void InitSharpYuvNEON(void);
+
+void InitSharpYuvNEON(void) {}
+
+#endif // WEBP_USE_NEON
diff --git a/sharpyuv/sharpyuv_sse2.c b/sharpyuv/sharpyuv_sse2.c
new file mode 100644
index 0000000..9744d1b
--- /dev/null
+++ b/sharpyuv/sharpyuv_sse2.c
@@ -0,0 +1,201 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <stdlib.h>
+#include <emmintrin.h>
+
+static uint16_t clip_SSE2(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ uint64_t diff = 0;
+ uint32_t tmp[4];
+ int i;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i one = _mm_set1_epi16(1);
+ __m128i sum = zero;
+
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
+ const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
+ const __m128i D = _mm_sub_epi16(A, B); // diff_y
+ const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
+ const __m128i F = _mm_add_epi16(C, D); // new_y
+ const __m128i G = _mm_or_si128(E, one); // -1 or 1
+ const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
+ const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
+ _mm_storeu_si128((__m128i*)(dst + i), H);
+ sum = _mm_add_epi32(sum, I);
+ }
+ _mm_storeu_si128((__m128i*)tmp, sum);
+ diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
+ for (; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)dst[i] + diff_y;
+ dst[i] = clip_SSE2(new_y, max_y);
+ diff += (uint64_t)abs(diff_y);
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i = 0;
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
+ const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
+ const __m128i D = _mm_sub_epi16(A, B); // diff_uv
+ const __m128i E = _mm_add_epi16(C, D); // new_uv
+ _mm_storeu_si128((__m128i*)(dst + i), E);
+ }
+ for (; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const __m128i kCst8 = _mm_set1_epi16(8);
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i zero = _mm_setzero_si128();
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
+ const __m128i a0b1 = _mm_add_epi16(a0, b1);
+ const __m128i a1b0 = _mm_add_epi16(a1, b0);
+ const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
+ const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
+ const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
+ const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
+ const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
+ const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
+ const __m128i d0 = _mm_add_epi16(c1, a0);
+ const __m128i d1 = _mm_add_epi16(c0, a1);
+ const __m128i e0 = _mm_srai_epi16(d0, 1);
+ const __m128i e1 = _mm_srai_epi16(d1, 1);
+ const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
+ const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
+ const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
+ const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
+ const __m128i h0 = _mm_add_epi16(g0, f0);
+ const __m128i h1 = _mm_add_epi16(g1, f1);
+ const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
+ const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
+ }
+ for (; i < len; ++i) {
+ // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
+ // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
+ // We reuse the common sub-expressions.
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static WEBP_INLINE __m128i s16_to_s32(__m128i in) {
+ return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16);
+}
+
+static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const __m128i kCst8 = _mm_set1_epi32(8);
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i zero = _mm_setzero_si128();
+ for (i = 0; i + 4 <= len; i += 4) {
+ const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0)));
+ const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1)));
+ const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0)));
+ const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1)));
+ const __m128i a0b1 = _mm_add_epi32(a0, b1);
+ const __m128i a1b0 = _mm_add_epi32(a1, b0);
+ const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1
+ const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8);
+ const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1)
+ const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0)
+ const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3);
+ const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3);
+ const __m128i d0 = _mm_add_epi32(c1, a0);
+ const __m128i d1 = _mm_add_epi32(c0, a1);
+ const __m128i e0 = _mm_srai_epi32(d0, 1);
+ const __m128i e1 = _mm_srai_epi32(d1, 1);
+ const __m128i f0 = _mm_unpacklo_epi32(e0, e1);
+ const __m128i f1 = _mm_unpackhi_epi32(e0, e1);
+ const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
+ const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1));
+ const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 0), final);
+ }
+ for (; i < len; ++i) {
+ // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
+ // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
+ // We reuse the common sub-expressions.
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ if (bit_depth <= 10) {
+ SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth);
+ } else {
+ SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void InitSharpYuvSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) {
+ SharpYuvUpdateY = SharpYuvUpdateY_SSE2;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2;
+ SharpYuvFilterRow = SharpYuvFilterRow_SSE2;
+}
+#else // !WEBP_USE_SSE2
+
+extern void InitSharpYuvSSE2(void);
+
+void InitSharpYuvSSE2(void) {}
+
+#endif // WEBP_USE_SSE2
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..b2979fb
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,55 @@
+# The mux and demux libraries depend on libwebp, thus the '.' to force
+# the build order so it's available to them.
+SUBDIRS = dec enc dsp utils .
+if BUILD_MUX
+ SUBDIRS += mux
+endif
+if BUILD_DEMUX
+ SUBDIRS += demux
+endif
+
+lib_LTLIBRARIES = libwebp.la
+
+if BUILD_LIBWEBPDECODER
+ lib_LTLIBRARIES += libwebpdecoder.la
+endif
+
+common_HEADERS =
+common_HEADERS += webp/decode.h
+common_HEADERS += webp/types.h
+commondir = $(includedir)/webp
+
+libwebp_la_SOURCES =
+libwebpinclude_HEADERS =
+libwebpinclude_HEADERS += webp/encode.h
+
+noinst_HEADERS =
+noinst_HEADERS += webp/format_constants.h
+
+libwebp_la_LIBADD =
+libwebp_la_LIBADD += dec/libwebpdecode.la
+libwebp_la_LIBADD += dsp/libwebpdsp.la
+libwebp_la_LIBADD += enc/libwebpencode.la
+libwebp_la_LIBADD += utils/libwebputils.la
+
+# Use '-no-undefined' to declare that libwebp does not depend on any libraries
+# other than the ones listed on the command line, i.e., after linking, it will
+# not have unresolved symbols. Some platforms (Windows among them) require all
+# symbols in shared libraries to be resolved at library creation.
+libwebp_la_LDFLAGS = -no-undefined -version-info 8:6:1
+libwebpincludedir = $(includedir)/webp
+pkgconfig_DATA = libwebp.pc
+
+if BUILD_LIBWEBPDECODER
+ libwebpdecoder_la_SOURCES =
+
+ libwebpdecoder_la_LIBADD =
+ libwebpdecoder_la_LIBADD += dec/libwebpdecode.la
+ libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
+ libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
+
+ libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:6:1
+ pkgconfig_DATA += libwebpdecoder.pc
+endif
+
+${pkgconfig_DATA}: ${top_builddir}/config.status
diff --git a/src/dec/Makefile.am b/src/dec/Makefile.am
new file mode 100644
index 0000000..f8c6398
--- /dev/null
+++ b/src/dec/Makefile.am
@@ -0,0 +1,29 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+noinst_LTLIBRARIES = libwebpdecode.la
+
+libwebpdecode_la_SOURCES =
+libwebpdecode_la_SOURCES += alpha_dec.c
+libwebpdecode_la_SOURCES += alphai_dec.h
+libwebpdecode_la_SOURCES += buffer_dec.c
+libwebpdecode_la_SOURCES += common_dec.h
+libwebpdecode_la_SOURCES += vp8_dec.h
+libwebpdecode_la_SOURCES += frame_dec.c
+libwebpdecode_la_SOURCES += idec_dec.c
+libwebpdecode_la_SOURCES += io_dec.c
+libwebpdecode_la_SOURCES += quant_dec.c
+libwebpdecode_la_SOURCES += tree_dec.c
+libwebpdecode_la_SOURCES += vp8_dec.c
+libwebpdecode_la_SOURCES += vp8i_dec.h
+libwebpdecode_la_SOURCES += vp8l_dec.c
+libwebpdecode_la_SOURCES += vp8li_dec.h
+libwebpdecode_la_SOURCES += webp_dec.c
+libwebpdecode_la_SOURCES += webpi_dec.h
+
+libwebpdecodeinclude_HEADERS =
+libwebpdecodeinclude_HEADERS += ../webp/decode.h
+libwebpdecodeinclude_HEADERS += ../webp/types.h
+noinst_HEADERS =
+noinst_HEADERS += ../webp/format_constants.h
+
+libwebpdecode_la_CPPFLAGS = $(AM_CPPFLAGS)
+libwebpdecodeincludedir = $(includedir)/webp
diff --git a/src/dec/vp8i_dec.h b/src/dec/vp8i_dec.h
index 9af22f8..83791ec 100644
--- a/src/dec/vp8i_dec.h
+++ b/src/dec/vp8i_dec.h
@@ -31,8 +31,8 @@
// version numbers
#define DEC_MAJ_VERSION 1
-#define DEC_MIN_VERSION 2
-#define DEC_REV_VERSION 2
+#define DEC_MIN_VERSION 3
+#define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
index 78db014..c0ea018 100644
--- a/src/dec/vp8l_dec.c
+++ b/src/dec/vp8l_dec.c
@@ -178,7 +178,7 @@
//------------------------------------------------------------------------------
// Decodes the next Huffman code from bit-stream.
-// FillBitWindow(br) needs to be called at minimum every second call
+// VP8LFillBitWindow(br) needs to be called at minimum every second call
// to ReadSymbol, in order to pre-fetch enough bits.
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
VP8LBitReader* const br) {
@@ -321,7 +321,7 @@
// The first code is either 1 bit or 8 bit code.
int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
code_lengths[symbol] = 1;
- // The second code (if present), is always 8 bit long.
+ // The second code (if present), is always 8 bits long.
if (num_symbols == 2) {
symbol = VP8LReadBits(br, 8);
code_lengths[symbol] = 1;
@@ -1281,7 +1281,7 @@
uint8_t* const new_data = (uint8_t*)new_color_map;
new_color_map[0] = transform->data_[0];
for (i = 4; i < 4 * num_colors; ++i) {
- // Equivalent to AddPixelEq(), on a byte-basis.
+ // Equivalent to VP8LAddPixels(), on a byte-basis.
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
}
for (; i < 4 * final_num_colors; ++i) {
@@ -1336,7 +1336,7 @@
ok = ok && ExpandColorMap(num_colors, transform);
break;
}
- case SUBTRACT_GREEN:
+ case SUBTRACT_GREEN_TRANSFORM:
break;
default:
assert(0); // can't happen
diff --git a/src/dec/webp_dec.c b/src/dec/webp_dec.c
index 77a54c5..3f4f7bb 100644
--- a/src/dec/webp_dec.c
+++ b/src/dec/webp_dec.c
@@ -179,7 +179,7 @@
return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
}
// For odd-sized chunk-payload, there's one byte padding at the end.
- disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
+ disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1u;
total_size += disk_chunk_size;
// Check that total bytes skipped so far does not exceed riff_size.
diff --git a/src/demux/Makefile.am b/src/demux/Makefile.am
new file mode 100644
index 0000000..d7392b3
--- /dev/null
+++ b/src/demux/Makefile.am
@@ -0,0 +1,18 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+lib_LTLIBRARIES = libwebpdemux.la
+
+libwebpdemux_la_SOURCES =
+libwebpdemux_la_SOURCES += anim_decode.c demux.c
+
+libwebpdemuxinclude_HEADERS =
+libwebpdemuxinclude_HEADERS += ../webp/decode.h
+libwebpdemuxinclude_HEADERS += ../webp/demux.h
+libwebpdemuxinclude_HEADERS += ../webp/mux_types.h
+libwebpdemuxinclude_HEADERS += ../webp/types.h
+noinst_HEADERS =
+noinst_HEADERS += ../webp/format_constants.h
+
+libwebpdemux_la_LIBADD = ../libwebp.la
+libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:12:0
+libwebpdemuxincludedir = $(includedir)/webp
+pkgconfig_DATA = libwebpdemux.pc
diff --git a/src/demux/demux.c b/src/demux/demux.c
index f04a2b8..324e5eb 100644
--- a/src/demux/demux.c
+++ b/src/demux/demux.c
@@ -24,8 +24,8 @@
#include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1
-#define DMUX_MIN_VERSION 2
-#define DMUX_REV_VERSION 2
+#define DMUX_MIN_VERSION 3
+#define DMUX_REV_VERSION 0
typedef struct {
size_t start_; // start location of the data
@@ -614,7 +614,6 @@
while (f != NULL) {
const int cur_frame_set = f->frame_num_;
- int frame_count = 0;
// Check frame properties.
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
@@ -649,8 +648,6 @@
dmux->canvas_width_, dmux->canvas_height_)) {
return 0;
}
-
- ++frame_count;
}
}
return 1;
diff --git a/src/demux/libwebpdemux.pc.in b/src/demux/libwebpdemux.pc.in
new file mode 100644
index 0000000..4da2e40
--- /dev/null
+++ b/src/demux/libwebpdemux.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libwebpdemux
+Description: Library for parsing the WebP graphics format container
+Version: @PACKAGE_VERSION@
+Requires.private: libwebp >= 0.2.0
+Cflags: -I${includedir}
+Libs: -L${libdir} -l@webp_libname_prefix@webpdemux
diff --git a/src/demux/libwebpdemux.rc b/src/demux/libwebpdemux.rc
new file mode 100644
index 0000000..18353e5
--- /dev/null
+++ b/src/demux/libwebpdemux.rc
@@ -0,0 +1,41 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,3,0
+ PRODUCTVERSION 1,0,3,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google, Inc."
+ VALUE "FileDescription", "libwebpdemux DLL"
+ VALUE "FileVersion", "1.3.0"
+ VALUE "InternalName", "libwebpdemux.dll"
+ VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "OriginalFilename", "libwebpdemux.dll"
+ VALUE "ProductName", "WebP Image Demuxer"
+ VALUE "ProductVersion", "1.3.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
diff --git a/src/dsp/Makefile.am b/src/dsp/Makefile.am
new file mode 100644
index 0000000..7db4ef0
--- /dev/null
+++ b/src/dsp/Makefile.am
@@ -0,0 +1,187 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+noinst_LTLIBRARIES =
+noinst_LTLIBRARIES += libwebpdsp.la
+noinst_LTLIBRARIES += libwebpdsp_sse2.la
+noinst_LTLIBRARIES += libwebpdspdecode_sse2.la
+noinst_LTLIBRARIES += libwebpdsp_sse41.la
+noinst_LTLIBRARIES += libwebpdspdecode_sse41.la
+noinst_LTLIBRARIES += libwebpdsp_neon.la
+noinst_LTLIBRARIES += libwebpdspdecode_neon.la
+noinst_LTLIBRARIES += libwebpdsp_msa.la
+noinst_LTLIBRARIES += libwebpdspdecode_msa.la
+noinst_LTLIBRARIES += libwebpdsp_mips32.la
+noinst_LTLIBRARIES += libwebpdspdecode_mips32.la
+noinst_LTLIBRARIES += libwebpdsp_mips_dsp_r2.la
+noinst_LTLIBRARIES += libwebpdspdecode_mips_dsp_r2.la
+
+if BUILD_LIBWEBPDECODER
+ noinst_LTLIBRARIES += libwebpdspdecode.la
+endif
+
+common_HEADERS = ../webp/types.h
+commondir = $(includedir)/webp
+
+COMMON_SOURCES =
+COMMON_SOURCES += alpha_processing.c
+COMMON_SOURCES += cpu.c
+COMMON_SOURCES += cpu.h
+COMMON_SOURCES += dec.c
+COMMON_SOURCES += dec_clip_tables.c
+COMMON_SOURCES += dsp.h
+COMMON_SOURCES += filters.c
+COMMON_SOURCES += lossless.c
+COMMON_SOURCES += lossless.h
+COMMON_SOURCES += lossless_common.h
+COMMON_SOURCES += rescaler.c
+COMMON_SOURCES += upsampling.c
+COMMON_SOURCES += yuv.c
+COMMON_SOURCES += yuv.h
+
+ENC_SOURCES =
+ENC_SOURCES += cost.c
+ENC_SOURCES += enc.c
+ENC_SOURCES += lossless_enc.c
+ENC_SOURCES += quant.h
+ENC_SOURCES += ssim.c
+
+libwebpdspdecode_sse41_la_SOURCES =
+libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
+libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c
+libwebpdspdecode_sse41_la_SOURCES += lossless_sse41.c
+libwebpdspdecode_sse41_la_SOURCES += upsampling_sse41.c
+libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
+libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdspdecode_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS)
+
+libwebpdspdecode_sse2_la_SOURCES =
+libwebpdspdecode_sse2_la_SOURCES += alpha_processing_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += common_sse2.h
+libwebpdspdecode_sse2_la_SOURCES += dec_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += filters_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += lossless_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += rescaler_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += upsampling_sse2.c
+libwebpdspdecode_sse2_la_SOURCES += yuv_sse2.c
+libwebpdspdecode_sse2_la_CPPFLAGS = $(libwebpdsp_sse2_la_CPPFLAGS)
+libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS)
+
+libwebpdspdecode_neon_la_SOURCES =
+libwebpdspdecode_neon_la_SOURCES += alpha_processing_neon.c
+libwebpdspdecode_neon_la_SOURCES += dec_neon.c
+libwebpdspdecode_neon_la_SOURCES += filters_neon.c
+libwebpdspdecode_neon_la_SOURCES += lossless_neon.c
+libwebpdspdecode_neon_la_SOURCES += neon.h
+libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c
+libwebpdspdecode_neon_la_SOURCES += upsampling_neon.c
+libwebpdspdecode_neon_la_SOURCES += yuv_neon.c
+libwebpdspdecode_neon_la_CPPFLAGS = $(libwebpdsp_neon_la_CPPFLAGS)
+libwebpdspdecode_neon_la_CFLAGS = $(libwebpdsp_neon_la_CFLAGS)
+
+libwebpdspdecode_msa_la_SOURCES =
+libwebpdspdecode_msa_la_SOURCES += dec_msa.c
+libwebpdspdecode_msa_la_SOURCES += filters_msa.c
+libwebpdspdecode_msa_la_SOURCES += lossless_msa.c
+libwebpdspdecode_msa_la_SOURCES += msa_macro.h
+libwebpdspdecode_msa_la_SOURCES += rescaler_msa.c
+libwebpdspdecode_msa_la_SOURCES += upsampling_msa.c
+libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_msa_la_CPPFLAGS)
+libwebpdspdecode_msa_la_CFLAGS = $(libwebpdsp_msa_la_CFLAGS)
+
+libwebpdspdecode_mips32_la_SOURCES =
+libwebpdspdecode_mips32_la_SOURCES += dec_mips32.c
+libwebpdspdecode_mips32_la_SOURCES += mips_macro.h
+libwebpdspdecode_mips32_la_SOURCES += rescaler_mips32.c
+libwebpdspdecode_mips32_la_SOURCES += yuv_mips32.c
+libwebpdspdecode_mips32_la_CPPFLAGS = $(libwebpdsp_mips32_la_CPPFLAGS)
+libwebpdspdecode_mips32_la_CFLAGS = $(libwebpdsp_mips32_la_CFLAGS)
+
+libwebpdspdecode_mips_dsp_r2_la_SOURCES =
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += alpha_processing_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += dec_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += filters_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += lossless_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += mips_macro.h
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += rescaler_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += upsampling_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_SOURCES += yuv_mips_dsp_r2.c
+libwebpdspdecode_mips_dsp_r2_la_CPPFLAGS = $(libwebpdsp_mips_dsp_r2_la_CPPFLAGS)
+libwebpdspdecode_mips_dsp_r2_la_CFLAGS = $(libwebpdsp_mips_dsp_r2_la_CFLAGS)
+
+libwebpdsp_sse2_la_SOURCES =
+libwebpdsp_sse2_la_SOURCES += cost_sse2.c
+libwebpdsp_sse2_la_SOURCES += enc_sse2.c
+libwebpdsp_sse2_la_SOURCES += lossless_enc_sse2.c
+libwebpdsp_sse2_la_SOURCES += ssim_sse2.c
+libwebpdsp_sse2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS)
+libwebpdsp_sse2_la_LIBADD = libwebpdspdecode_sse2.la
+
+libwebpdsp_sse41_la_SOURCES =
+libwebpdsp_sse41_la_SOURCES += enc_sse41.c
+libwebpdsp_sse41_la_SOURCES += lossless_enc_sse41.c
+libwebpdsp_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS)
+libwebpdsp_sse41_la_LIBADD = libwebpdspdecode_sse41.la
+
+libwebpdsp_neon_la_SOURCES =
+libwebpdsp_neon_la_SOURCES += cost_neon.c
+libwebpdsp_neon_la_SOURCES += enc_neon.c
+libwebpdsp_neon_la_SOURCES += lossless_enc_neon.c
+libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
+libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la
+
+libwebpdsp_msa_la_SOURCES =
+libwebpdsp_msa_la_SOURCES += enc_msa.c
+libwebpdsp_msa_la_SOURCES += lossless_enc_msa.c
+libwebpdsp_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_msa_la_CFLAGS = $(AM_CFLAGS)
+libwebpdsp_msa_la_LIBADD = libwebpdspdecode_msa.la
+
+libwebpdsp_mips32_la_SOURCES =
+libwebpdsp_mips32_la_SOURCES += cost_mips32.c
+libwebpdsp_mips32_la_SOURCES += enc_mips32.c
+libwebpdsp_mips32_la_SOURCES += lossless_enc_mips32.c
+libwebpdsp_mips32_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_mips32_la_CFLAGS = $(AM_CFLAGS)
+libwebpdsp_mips32_la_LIBADD = libwebpdspdecode_mips32.la
+
+libwebpdsp_mips_dsp_r2_la_SOURCES =
+libwebpdsp_mips_dsp_r2_la_SOURCES += cost_mips_dsp_r2.c
+libwebpdsp_mips_dsp_r2_la_SOURCES += enc_mips_dsp_r2.c
+libwebpdsp_mips_dsp_r2_la_SOURCES += lossless_enc_mips_dsp_r2.c
+libwebpdsp_mips_dsp_r2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+libwebpdsp_mips_dsp_r2_la_CFLAGS = $(AM_CFLAGS)
+libwebpdsp_mips_dsp_r2_la_LIBADD = libwebpdspdecode_mips_dsp_r2.la
+
+libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
+
+noinst_HEADERS =
+noinst_HEADERS += ../dec/vp8_dec.h
+noinst_HEADERS += ../webp/decode.h
+
+libwebpdsp_la_CPPFLAGS =
+libwebpdsp_la_CPPFLAGS += $(AM_CPPFLAGS)
+libwebpdsp_la_CPPFLAGS += $(USE_SWAP_16BIT_CSP)
+libwebpdsp_la_LDFLAGS = -lm
+libwebpdsp_la_LIBADD =
+libwebpdsp_la_LIBADD += libwebpdsp_sse2.la
+libwebpdsp_la_LIBADD += libwebpdsp_sse41.la
+libwebpdsp_la_LIBADD += libwebpdsp_neon.la
+libwebpdsp_la_LIBADD += libwebpdsp_msa.la
+libwebpdsp_la_LIBADD += libwebpdsp_mips32.la
+libwebpdsp_la_LIBADD += libwebpdsp_mips_dsp_r2.la
+
+if BUILD_LIBWEBPDECODER
+ libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)
+
+ libwebpdspdecode_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
+ libwebpdspdecode_la_LDFLAGS = $(libwebpdsp_la_LDFLAGS)
+ libwebpdspdecode_la_LIBADD =
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_sse2.la
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_sse41.la
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_neon.la
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_msa.la
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_mips32.la
+ libwebpdspdecode_la_LIBADD += libwebpdspdecode_mips_dsp_r2.la
+endif
diff --git a/src/dsp/alpha_processing_sse2.c b/src/dsp/alpha_processing_sse2.c
index a5f8c9f..f0843d0 100644
--- a/src/dsp/alpha_processing_sse2.c
+++ b/src/dsp/alpha_processing_sse2.c
@@ -26,8 +26,8 @@
uint32_t alpha_and = 0xff;
int i, j;
const __m128i zero = _mm_setzero_si128();
- const __m128i rgb_mask = _mm_set1_epi32(0xffffff00u); // to preserve RGB
- const __m128i all_0xff = _mm_set_epi32(0, 0, ~0u, ~0u);
+ const __m128i rgb_mask = _mm_set1_epi32((int)0xffffff00); // to preserve RGB
+ const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0);
__m128i all_alphas = all_0xff;
// We must be able to access 3 extra bytes after the last written byte
@@ -106,8 +106,8 @@
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
int i, j;
- const __m128i a_mask = _mm_set1_epi32(0xffu); // to preserve alpha
- const __m128i all_0xff = _mm_set_epi32(0, 0, ~0u, ~0u);
+ const __m128i a_mask = _mm_set1_epi32(0xff); // to preserve alpha
+ const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0);
__m128i all_alphas = all_0xff;
// We must be able to access 3 extra bytes after the last written byte
@@ -178,7 +178,7 @@
static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
int w, int h, int stride) {
const __m128i zero = _mm_setzero_si128();
- const __m128i kMult = _mm_set1_epi16(0x8081u);
+ const __m128i kMult = _mm_set1_epi16((short)0x8081);
const __m128i kMask = _mm_set_epi16(0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0);
const int kSpan = 4;
while (h-- > 0) {
@@ -267,7 +267,7 @@
}
static void AlphaReplace_SSE2(uint32_t* src, int length, uint32_t color) {
- const __m128i m_color = _mm_set1_epi32(color);
+ const __m128i m_color = _mm_set1_epi32((int)color);
const __m128i zero = _mm_setzero_si128();
int i = 0;
for (; i + 8 <= length; i += 8) {
diff --git a/src/dsp/alpha_processing_sse41.c b/src/dsp/alpha_processing_sse41.c
index cdf877c..1156ac3 100644
--- a/src/dsp/alpha_processing_sse41.c
+++ b/src/dsp/alpha_processing_sse41.c
@@ -26,7 +26,7 @@
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
int i, j;
- const __m128i all_0xff = _mm_set1_epi32(~0u);
+ const __m128i all_0xff = _mm_set1_epi32(~0);
__m128i all_alphas = all_0xff;
// We must be able to access 3 extra bytes after the last written byte
diff --git a/src/dsp/cpu.c b/src/dsp/cpu.c
index 3145e19..62de73f 100644
--- a/src/dsp/cpu.c
+++ b/src/dsp/cpu.c
@@ -11,7 +11,7 @@
//
// Author: Christian Duvivier (cduvivier@google.com)
-#include "src/dsp/dsp.h"
+#include "src/dsp/cpu.h"
#if defined(WEBP_HAVE_NEON_RTCD)
#include <stdio.h>
@@ -212,7 +212,7 @@
#elif defined(WEBP_HAVE_NEON)
// In most cases this function doesn't check for NEON support (it's assumed by
// the configuration), but enables turning off NEON at runtime, for testing
-// purposes, by setting VP8DecGetCPUInfo = NULL.
+// purposes, by setting VP8GetCPUInfo = NULL.
static int armCPUInfo(CPUFeature feature) {
if (feature != kNEON) return 0;
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)
diff --git a/src/dsp/cpu.h b/src/dsp/cpu.h
new file mode 100644
index 0000000..be80727
--- /dev/null
+++ b/src/dsp/cpu.h
@@ -0,0 +1,256 @@
+// Copyright 2022 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.
+// -----------------------------------------------------------------------------
+//
+// CPU detection functions and macros.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DSP_CPU_H_
+#define WEBP_DSP_CPU_H_
+
+#include <stddef.h>
+
+#ifdef HAVE_CONFIG_H
+#include "src/webp/config.h"
+#endif
+
+#include "src/webp/types.h"
+
+#if defined(__GNUC__)
+#define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
+#define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
+#else
+#define LOCAL_GCC_VERSION 0
+#define LOCAL_GCC_PREREQ(maj, min) 0
+#endif
+
+#if defined(__clang__)
+#define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
+#define LOCAL_CLANG_PREREQ(maj, min) \
+ (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
+#else
+#define LOCAL_CLANG_VERSION 0
+#define LOCAL_CLANG_PREREQ(maj, min) 0
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if !defined(HAVE_CONFIG_H)
+#if defined(_MSC_VER) && _MSC_VER > 1310 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
+#endif
+#endif
+
+// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
+// files without intrinsics, allowing the corresponding Init() to be called.
+// Files containing intrinsics will need to be built targeting the instruction
+// set so should succeed on one of the earlier tests.
+#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
+#define WEBP_USE_SSE2
+#endif
+
+#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
+#define WEBP_HAVE_SSE2
+#endif
+
+#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
+#define WEBP_USE_SSE41
+#endif
+
+#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
+#define WEBP_HAVE_SSE41
+#endif
+
+#undef WEBP_MSC_SSE41
+#undef WEBP_MSC_SSE2
+
+// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
+// inline assembly would need to be modified for use with Native Client.
+#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
+ !defined(__native_client__)
+#define WEBP_USE_NEON
+#endif
+
+#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
+ defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
+#define WEBP_ANDROID_NEON // Android targets that may have NEON
+#define WEBP_USE_NEON
+#endif
+
+// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
+// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
+// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with
+// vtbl4_u8(); a fix was made in 16.6.
+#if defined(_MSC_VER) && ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
+ (_MSC_VER >= 1926 && defined(_M_ARM64)))
+#define WEBP_USE_NEON
+#define WEBP_USE_INTRINSICS
+#endif
+
+#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
+#define WEBP_HAVE_NEON
+#endif
+
+#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \
+ (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
+#define WEBP_USE_MIPS32
+#if (__mips_isa_rev >= 2)
+#define WEBP_USE_MIPS32_R2
+#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
+#define WEBP_USE_MIPS_DSP_R2
+#endif
+#endif
+#endif
+
+#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
+#define WEBP_USE_MSA
+#endif
+
+#ifndef WEBP_DSP_OMIT_C_CODE
+#define WEBP_DSP_OMIT_C_CODE 1
+#endif
+
+#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
+#define WEBP_NEON_OMIT_C_CODE 1
+#else
+#define WEBP_NEON_OMIT_C_CODE 0
+#endif
+
+#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || \
+ defined(__aarch64__))
+#define WEBP_NEON_WORK_AROUND_GCC 1
+#else
+#define WEBP_NEON_WORK_AROUND_GCC 0
+#endif
+
+// This macro prevents thread_sanitizer from reporting known concurrent writes.
+#define WEBP_TSAN_IGNORE_FUNCTION
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#undef WEBP_TSAN_IGNORE_FUNCTION
+#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
+#endif
+#endif
+
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define WEBP_MSAN
+#endif
+#endif
+
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h> // NOLINT
+
+#define WEBP_DSP_INIT(func) \
+ do { \
+ static volatile VP8CPUInfo func##_last_cpuinfo_used = \
+ (VP8CPUInfo)&func##_last_cpuinfo_used; \
+ static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \
+ if (pthread_mutex_lock(&func##_lock)) break; \
+ if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \
+ func##_last_cpuinfo_used = VP8GetCPUInfo; \
+ (void)pthread_mutex_unlock(&func##_lock); \
+ } while (0)
+#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
+#define WEBP_DSP_INIT(func) \
+ do { \
+ static volatile VP8CPUInfo func##_last_cpuinfo_used = \
+ (VP8CPUInfo)&func##_last_cpuinfo_used; \
+ if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \
+ func(); \
+ func##_last_cpuinfo_used = VP8GetCPUInfo; \
+ } while (0)
+#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
+
+// Defines an Init + helper function that control multiple initialization of
+// function pointers / tables.
+/* Usage:
+ WEBP_DSP_INIT_FUNC(InitFunc) {
+ ...function body
+ }
+*/
+#define WEBP_DSP_INIT_FUNC(name) \
+ static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \
+ WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \
+ static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void)
+
+#define WEBP_UBSAN_IGNORE_UNDEF
+#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
+#if defined(__clang__) && defined(__has_attribute)
+#if __has_attribute(no_sanitize)
+// This macro prevents the undefined behavior sanitizer from reporting
+// failures. This is only meant to silence unaligned loads on platforms that
+// are known to support them.
+#undef WEBP_UBSAN_IGNORE_UNDEF
+#define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined")))
+
+// This macro prevents the undefined behavior sanitizer from reporting
+// failures related to unsigned integer overflows. This is only meant to
+// silence cases where this well defined behavior is expected.
+#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
+#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
+#endif
+#endif
+
+// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
+// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
+#if !defined(WEBP_OFFSET_PTR)
+#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
+#endif
+
+// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
+#if !defined(WEBP_SWAP_16BIT_CSP)
+#define WEBP_SWAP_16BIT_CSP 0
+#endif
+
+// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
+#if !defined(WORDS_BIGENDIAN) && \
+ (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
+#define WORDS_BIGENDIAN
+#endif
+
+typedef enum {
+ kSSE2,
+ kSSE3,
+ kSlowSSSE3, // special feature for slow SSSE3 architectures
+ kSSE4_1,
+ kAVX,
+ kAVX2,
+ kNEON,
+ kMIPS32,
+ kMIPSdspR2,
+ kMSA
+} CPUFeature;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// returns true if the CPU supports the feature.
+typedef int (*VP8CPUInfo)(CPUFeature feature);
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_DSP_CPU_H_
diff --git a/src/dsp/dec_sse2.c b/src/dsp/dec_sse2.c
index 873aa59..01e6bcb 100644
--- a/src/dsp/dec_sse2.c
+++ b/src/dsp/dec_sse2.c
@@ -158,10 +158,10 @@
dst3 = _mm_loadl_epi64((__m128i*)(dst + 3 * BPS));
} else {
// Load four bytes/pixels per line.
- dst0 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 0 * BPS));
- dst1 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 1 * BPS));
- dst2 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 2 * BPS));
- dst3 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 3 * BPS));
+ dst0 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 0 * BPS));
+ dst1 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 1 * BPS));
+ dst2 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 2 * BPS));
+ dst3 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 3 * BPS));
}
// Convert to 16b.
dst0 = _mm_unpacklo_epi8(dst0, zero);
@@ -187,10 +187,10 @@
_mm_storel_epi64((__m128i*)(dst + 3 * BPS), dst3);
} else {
// Store four bytes/pixels per line.
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
}
}
}
@@ -213,10 +213,10 @@
const __m128i m3 = _mm_subs_epi16(B, d4);
const __m128i zero = _mm_setzero_si128();
// Load the source pixels.
- __m128i dst0 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 0 * BPS));
- __m128i dst1 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 1 * BPS));
- __m128i dst2 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 2 * BPS));
- __m128i dst3 = _mm_cvtsi32_si128(WebPMemToUint32(dst + 3 * BPS));
+ __m128i dst0 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 0 * BPS));
+ __m128i dst1 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 1 * BPS));
+ __m128i dst2 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 2 * BPS));
+ __m128i dst3 = _mm_cvtsi32_si128(WebPMemToInt32(dst + 3 * BPS));
// Convert to 16b.
dst0 = _mm_unpacklo_epi8(dst0, zero);
dst1 = _mm_unpacklo_epi8(dst1, zero);
@@ -233,10 +233,10 @@
dst2 = _mm_packus_epi16(dst2, dst2);
dst3 = _mm_packus_epi16(dst3, dst3);
// Store the results.
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(dst0));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(dst1));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
}
#undef MUL
#endif // USE_TRANSFORM_AC3
@@ -477,11 +477,11 @@
// A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00
// A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10
const __m128i A0 = _mm_set_epi32(
- WebPMemToUint32(&b[6 * stride]), WebPMemToUint32(&b[2 * stride]),
- WebPMemToUint32(&b[4 * stride]), WebPMemToUint32(&b[0 * stride]));
+ WebPMemToInt32(&b[6 * stride]), WebPMemToInt32(&b[2 * stride]),
+ WebPMemToInt32(&b[4 * stride]), WebPMemToInt32(&b[0 * stride]));
const __m128i A1 = _mm_set_epi32(
- WebPMemToUint32(&b[7 * stride]), WebPMemToUint32(&b[3 * stride]),
- WebPMemToUint32(&b[5 * stride]), WebPMemToUint32(&b[1 * stride]));
+ WebPMemToInt32(&b[7 * stride]), WebPMemToInt32(&b[3 * stride]),
+ WebPMemToInt32(&b[5 * stride]), WebPMemToInt32(&b[1 * stride]));
// B0 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00
// B1 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20
@@ -540,7 +540,7 @@
uint8_t* dst, int stride) {
int i;
for (i = 0; i < 4; ++i, dst += stride) {
- WebPUint32ToMem(dst, _mm_cvtsi128_si32(*x));
+ WebPInt32ToMem(dst, _mm_cvtsi128_si32(*x));
*x = _mm_srli_si128(*x, 4);
}
}
@@ -908,10 +908,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one);
const __m128i b = _mm_subs_epu8(a, lsb);
const __m128i avg = _mm_avg_epu8(b, BCDEFGH0);
- const uint32_t vals = _mm_cvtsi128_si32(avg);
+ const int vals = _mm_cvtsi128_si32(avg);
int i;
for (i = 0; i < 4; ++i) {
- WebPUint32ToMem(dst + i * BPS, vals);
+ WebPInt32ToMem(dst + i * BPS, vals);
}
}
@@ -925,10 +925,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0);
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
}
static void VR4_SSE2(uint8_t* dst) { // Vertical-Right
@@ -946,10 +946,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i efgh = _mm_avg_epu8(avg2, XABCD);
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1)));
// these two are hard to implement in SSE2, so we keep the C-version:
DST(0, 2) = AVG3(J, I, X);
@@ -970,11 +970,12 @@
const __m128i abbc = _mm_or_si128(ab, bc);
const __m128i lsb2 = _mm_and_si128(abbc, lsb1);
const __m128i avg4 = _mm_subs_epu8(avg3, lsb2);
- const uint32_t extra_out = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1)));
+ const uint32_t extra_out =
+ (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1)));
// these two are hard to get and irregular
DST(3, 2) = (extra_out >> 0) & 0xff;
@@ -990,7 +991,7 @@
const uint32_t K = dst[-1 + 2 * BPS];
const uint32_t L = dst[-1 + 3 * BPS];
const __m128i LKJI_____ =
- _mm_cvtsi32_si128(L | (K << 8) | (J << 16) | (I << 24));
+ _mm_cvtsi32_si128((int)(L | (K << 8) | (J << 16) | (I << 24)));
const __m128i LKJIXABCD = _mm_or_si128(LKJI_____, ____XABCD);
const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1);
const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2);
@@ -998,10 +999,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_);
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
}
#undef DST
@@ -1015,13 +1016,13 @@
const __m128i zero = _mm_setzero_si128();
int y;
if (size == 4) {
- const __m128i top_values = _mm_cvtsi32_si128(WebPMemToUint32(top));
+ const __m128i top_values = _mm_cvtsi32_si128(WebPMemToInt32(top));
const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
for (y = 0; y < 4; ++y, dst += BPS) {
const int val = dst[-1] - top[-1];
const __m128i base = _mm_set1_epi16(val);
const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
- WebPUint32ToMem(dst, _mm_cvtsi128_si32(out));
+ WebPInt32ToMem(dst, _mm_cvtsi128_si32(out));
}
} else if (size == 8) {
const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
@@ -1062,7 +1063,7 @@
static void HE16_SSE2(uint8_t* dst) { // horizontal
int j;
for (j = 16; j > 0; --j) {
- const __m128i values = _mm_set1_epi8(dst[-1]);
+ const __m128i values = _mm_set1_epi8((char)dst[-1]);
_mm_storeu_si128((__m128i*)dst, values);
dst += BPS;
}
@@ -1070,7 +1071,7 @@
static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) {
int j;
- const __m128i values = _mm_set1_epi8(v);
+ const __m128i values = _mm_set1_epi8((char)v);
for (j = 0; j < 16; ++j) {
_mm_storeu_si128((__m128i*)(dst + j * BPS), values);
}
@@ -1130,7 +1131,7 @@
// helper for chroma-DC predictions
static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) {
int j;
- const __m128i values = _mm_set1_epi8(v);
+ const __m128i values = _mm_set1_epi8((char)v);
for (j = 0; j < 8; ++j) {
_mm_storel_epi64((__m128i*)(dst + j * BPS), values);
}
diff --git a/src/dsp/dec_sse41.c b/src/dsp/dec_sse41.c
index 8f18506..08a3630 100644
--- a/src/dsp/dec_sse41.c
+++ b/src/dsp/dec_sse41.c
@@ -23,7 +23,7 @@
int j;
const __m128i kShuffle3 = _mm_set1_epi8(3);
for (j = 16; j > 0; --j) {
- const __m128i in = _mm_cvtsi32_si128(WebPMemToUint32(dst - 4));
+ const __m128i in = _mm_cvtsi32_si128(WebPMemToInt32(dst - 4));
const __m128i values = _mm_shuffle_epi8(in, kShuffle3);
_mm_storeu_si128((__m128i*)dst, values);
dst += BPS;
diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h
index 73a66be..d2000b8 100644
--- a/src/dsp/dsp.h
+++ b/src/dsp/dsp.h
@@ -18,6 +18,7 @@
#include "src/webp/config.h"
#endif
+#include "src/dsp/cpu.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -43,226 +44,6 @@
#define WEBP_RESTRICT
#endif
-//------------------------------------------------------------------------------
-// CPU detection
-
-#if defined(__GNUC__)
-# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
-# define LOCAL_GCC_PREREQ(maj, min) \
- (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
-#else
-# define LOCAL_GCC_VERSION 0
-# define LOCAL_GCC_PREREQ(maj, min) 0
-#endif
-
-#if defined(__clang__)
-# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
-# define LOCAL_CLANG_PREREQ(maj, min) \
- (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
-#else
-# define LOCAL_CLANG_VERSION 0
-# define LOCAL_CLANG_PREREQ(maj, min) 0
-#endif
-
-#ifndef __has_builtin
-# define __has_builtin(x) 0
-#endif
-
-#if !defined(HAVE_CONFIG_H)
-#if defined(_MSC_VER) && _MSC_VER > 1310 && \
- (defined(_M_X64) || defined(_M_IX86))
-#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
-#endif
-
-#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
- (defined(_M_X64) || defined(_M_IX86))
-#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
-#endif
-#endif
-
-// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
-// files without intrinsics, allowing the corresponding Init() to be called.
-// Files containing intrinsics will need to be built targeting the instruction
-// set so should succeed on one of the earlier tests.
-#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
-#define WEBP_USE_SSE2
-#endif
-
-#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
-#define WEBP_HAVE_SSE2
-#endif
-
-#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
-#define WEBP_USE_SSE41
-#endif
-
-#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
-#define WEBP_HAVE_SSE41
-#endif
-
-#undef WEBP_MSC_SSE41
-#undef WEBP_MSC_SSE2
-
-// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
-// inline assembly would need to be modified for use with Native Client.
-#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
- !defined(__native_client__)
-#define WEBP_USE_NEON
-#endif
-
-#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
- defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
-#define WEBP_ANDROID_NEON // Android targets that may have NEON
-#define WEBP_USE_NEON
-#endif
-
-// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
-// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
-// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with
-// vtbl4_u8(); a fix was made in 16.6.
-#if defined(_MSC_VER) && \
- ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
- (_MSC_VER >= 1926 && defined(_M_ARM64)))
-#define WEBP_USE_NEON
-#define WEBP_USE_INTRINSICS
-#endif
-
-#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
-#define WEBP_HAVE_NEON
-#endif
-
-#if defined(__mips__) && !defined(__mips64) && \
- defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
-#define WEBP_USE_MIPS32
-#if (__mips_isa_rev >= 2)
-#define WEBP_USE_MIPS32_R2
-#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
-#define WEBP_USE_MIPS_DSP_R2
-#endif
-#endif
-#endif
-
-#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
-#define WEBP_USE_MSA
-#endif
-
-#ifndef WEBP_DSP_OMIT_C_CODE
-#define WEBP_DSP_OMIT_C_CODE 1
-#endif
-
-#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
-#define WEBP_NEON_OMIT_C_CODE 1
-#else
-#define WEBP_NEON_OMIT_C_CODE 0
-#endif
-
-#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
-#define WEBP_NEON_WORK_AROUND_GCC 1
-#else
-#define WEBP_NEON_WORK_AROUND_GCC 0
-#endif
-
-// This macro prevents thread_sanitizer from reporting known concurrent writes.
-#define WEBP_TSAN_IGNORE_FUNCTION
-#if defined(__has_feature)
-#if __has_feature(thread_sanitizer)
-#undef WEBP_TSAN_IGNORE_FUNCTION
-#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
-#endif
-#endif
-
-#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
-#include <pthread.h> // NOLINT
-
-#define WEBP_DSP_INIT(func) do { \
- static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
- (VP8CPUInfo)&func ## _last_cpuinfo_used; \
- static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \
- if (pthread_mutex_lock(&func ## _lock)) break; \
- if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \
- func ## _last_cpuinfo_used = VP8GetCPUInfo; \
- (void)pthread_mutex_unlock(&func ## _lock); \
-} while (0)
-#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
-#define WEBP_DSP_INIT(func) do { \
- static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
- (VP8CPUInfo)&func ## _last_cpuinfo_used; \
- if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \
- func(); \
- func ## _last_cpuinfo_used = VP8GetCPUInfo; \
-} while (0)
-#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
-
-// Defines an Init + helper function that control multiple initialization of
-// function pointers / tables.
-/* Usage:
- WEBP_DSP_INIT_FUNC(InitFunc) {
- ...function body
- }
-*/
-#define WEBP_DSP_INIT_FUNC(name) \
- static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \
- WEBP_TSAN_IGNORE_FUNCTION void name(void) { \
- WEBP_DSP_INIT(name ## _body); \
- } \
- static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void)
-
-#define WEBP_UBSAN_IGNORE_UNDEF
-#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
-#if defined(__clang__) && defined(__has_attribute)
-#if __has_attribute(no_sanitize)
-// This macro prevents the undefined behavior sanitizer from reporting
-// failures. This is only meant to silence unaligned loads on platforms that
-// are known to support them.
-#undef WEBP_UBSAN_IGNORE_UNDEF
-#define WEBP_UBSAN_IGNORE_UNDEF \
- __attribute__((no_sanitize("undefined")))
-
-// This macro prevents the undefined behavior sanitizer from reporting
-// failures related to unsigned integer overflows. This is only meant to
-// silence cases where this well defined behavior is expected.
-#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
-#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
- __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
-#endif
-
-// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
-// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
-#if !defined(WEBP_OFFSET_PTR)
-#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
-#endif
-
-// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
-#if !defined(WEBP_SWAP_16BIT_CSP)
-#define WEBP_SWAP_16BIT_CSP 0
-#endif
-
-// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
-#if !defined(WORDS_BIGENDIAN) && \
- (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
- (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
-#define WORDS_BIGENDIAN
-#endif
-
-typedef enum {
- kSSE2,
- kSSE3,
- kSlowSSSE3, // special feature for slow SSSE3 architectures
- kSSE4_1,
- kAVX,
- kAVX2,
- kNEON,
- kMIPS32,
- kMIPSdspR2,
- kMSA
-} CPUFeature;
-// returns true if the CPU supports the feature.
-typedef int (*VP8CPUInfo)(CPUFeature feature);
-WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
//------------------------------------------------------------------------------
// Init stub generator
@@ -551,15 +332,6 @@
extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
uint8_t* u, uint8_t* v, int width);
-// utilities for accurate RGB->YUV conversion
-extern uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* src, const uint16_t* ref,
- uint16_t* dst, int len);
-extern void (*WebPSharpYUVUpdateRGB)(const int16_t* src, const int16_t* ref,
- int16_t* dst, int len);
-extern void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B,
- int len,
- const uint16_t* best_y, uint16_t* out);
-
// Must be called before using the above.
void WebPInitConvertARGBToYUV(void);
diff --git a/src/dsp/enc_neon.c b/src/dsp/enc_neon.c
index 601962b..3a04111 100644
--- a/src/dsp/enc_neon.c
+++ b/src/dsp/enc_neon.c
@@ -764,9 +764,14 @@
// Horizontal sum of all four uint32_t values in 'sum'.
static int SumToInt_NEON(uint32x4_t sum) {
+#if defined(__aarch64__)
+ return (int)vaddvq_u32(sum);
+#else
const uint64x2_t sum2 = vpaddlq_u32(sum);
- const uint64_t sum3 = vgetq_lane_u64(sum2, 0) + vgetq_lane_u64(sum2, 1);
- return (int)sum3;
+ const uint32x2_t sum3 = vadd_u32(vreinterpret_u32_u64(vget_low_u64(sum2)),
+ vreinterpret_u32_u64(vget_high_u64(sum2)));
+ return (int)vget_lane_u32(sum3, 0);
+#endif
}
static int SSE16x16_NEON(const uint8_t* a, const uint8_t* b) {
diff --git a/src/dsp/enc_sse2.c b/src/dsp/enc_sse2.c
index b2e78ed..1d10556 100644
--- a/src/dsp/enc_sse2.c
+++ b/src/dsp/enc_sse2.c
@@ -156,10 +156,10 @@
ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
} else {
// Load four bytes/pixels per line.
- ref0 = _mm_cvtsi32_si128(WebPMemToUint32(&ref[0 * BPS]));
- ref1 = _mm_cvtsi32_si128(WebPMemToUint32(&ref[1 * BPS]));
- ref2 = _mm_cvtsi32_si128(WebPMemToUint32(&ref[2 * BPS]));
- ref3 = _mm_cvtsi32_si128(WebPMemToUint32(&ref[3 * BPS]));
+ ref0 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[0 * BPS]));
+ ref1 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[1 * BPS]));
+ ref2 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[2 * BPS]));
+ ref3 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[3 * BPS]));
}
// Convert to 16b.
ref0 = _mm_unpacklo_epi8(ref0, zero);
@@ -185,10 +185,10 @@
_mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3);
} else {
// Store four bytes/pixels per line.
- WebPUint32ToMem(&dst[0 * BPS], _mm_cvtsi128_si32(ref0));
- WebPUint32ToMem(&dst[1 * BPS], _mm_cvtsi128_si32(ref1));
- WebPUint32ToMem(&dst[2 * BPS], _mm_cvtsi128_si32(ref2));
- WebPUint32ToMem(&dst[3 * BPS], _mm_cvtsi128_si32(ref3));
+ WebPInt32ToMem(&dst[0 * BPS], _mm_cvtsi128_si32(ref0));
+ WebPInt32ToMem(&dst[1 * BPS], _mm_cvtsi128_si32(ref1));
+ WebPInt32ToMem(&dst[2 * BPS], _mm_cvtsi128_si32(ref2));
+ WebPInt32ToMem(&dst[3 * BPS], _mm_cvtsi128_si32(ref3));
}
}
}
@@ -481,7 +481,7 @@
// helper for chroma-DC predictions
static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) {
int j;
- const __m128i values = _mm_set1_epi8(v);
+ const __m128i values = _mm_set1_epi8((char)v);
for (j = 0; j < 8; ++j) {
_mm_storel_epi64((__m128i*)(dst + j * BPS), values);
}
@@ -489,7 +489,7 @@
static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) {
int j;
- const __m128i values = _mm_set1_epi8(v);
+ const __m128i values = _mm_set1_epi8((char)v);
for (j = 0; j < 16; ++j) {
_mm_store_si128((__m128i*)(dst + j * BPS), values);
}
@@ -540,7 +540,7 @@
static WEBP_INLINE void HE8uv_SSE2(uint8_t* dst, const uint8_t* left) {
int j;
for (j = 0; j < 8; ++j) {
- const __m128i values = _mm_set1_epi8(left[j]);
+ const __m128i values = _mm_set1_epi8((char)left[j]);
_mm_storel_epi64((__m128i*)dst, values);
dst += BPS;
}
@@ -549,7 +549,7 @@
static WEBP_INLINE void HE16_SSE2(uint8_t* dst, const uint8_t* left) {
int j;
for (j = 0; j < 16; ++j) {
- const __m128i values = _mm_set1_epi8(left[j]);
+ const __m128i values = _mm_set1_epi8((char)left[j]);
_mm_store_si128((__m128i*)dst, values);
dst += BPS;
}
@@ -722,10 +722,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one);
const __m128i b = _mm_subs_epu8(a, lsb);
const __m128i avg = _mm_avg_epu8(b, BCDEFGH0);
- const uint32_t vals = _mm_cvtsi128_si32(avg);
+ const int vals = _mm_cvtsi128_si32(avg);
int i;
for (i = 0; i < 4; ++i) {
- WebPUint32ToMem(dst + i * BPS, vals);
+ WebPInt32ToMem(dst + i * BPS, vals);
}
}
@@ -760,10 +760,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0);
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
}
static WEBP_INLINE void VR4_SSE2(uint8_t* dst,
@@ -782,10 +782,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i efgh = _mm_avg_epu8(avg2, XABCD);
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1)));
// these two are hard to implement in SSE2, so we keep the C-version:
DST(0, 2) = AVG3(J, I, X);
@@ -807,11 +807,12 @@
const __m128i abbc = _mm_or_si128(ab, bc);
const __m128i lsb2 = _mm_and_si128(abbc, lsb1);
const __m128i avg4 = _mm_subs_epu8(avg3, lsb2);
- const uint32_t extra_out = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 ));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1)));
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1)));
+ const uint32_t extra_out =
+ (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 ));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1)));
// these two are hard to get and irregular
DST(3, 2) = (extra_out >> 0) & 0xff;
@@ -829,10 +830,10 @@
const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one);
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_);
- WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg ));
- WebPUint32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
- WebPUint32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
- WebPUint32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
+ WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg ));
+ WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
+ WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
+ WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
}
static WEBP_INLINE void HU4_SSE2(uint8_t* dst, const uint8_t* top) {
@@ -875,14 +876,14 @@
static WEBP_INLINE void TM4_SSE2(uint8_t* dst, const uint8_t* top) {
const __m128i zero = _mm_setzero_si128();
- const __m128i top_values = _mm_cvtsi32_si128(WebPMemToUint32(top));
+ const __m128i top_values = _mm_cvtsi32_si128(WebPMemToInt32(top));
const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
int y;
for (y = 0; y < 4; ++y, dst += BPS) {
const int val = top[-2 - y] - top[-1];
const __m128i base = _mm_set1_epi16(val);
const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
- WebPUint32ToMem(dst, _mm_cvtsi128_si32(out));
+ WebPInt32ToMem(dst, _mm_cvtsi128_si32(out));
}
}
diff --git a/src/dsp/lossless.c b/src/dsp/lossless.c
index 84a5429..fb86e58 100644
--- a/src/dsp/lossless.c
+++ b/src/dsp/lossless.c
@@ -49,7 +49,7 @@
}
static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) {
- return Clip255(a + b - c);
+ return Clip255((uint32_t)(a + b - c));
}
static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
@@ -66,7 +66,7 @@
}
static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
- return Clip255(a + (a - b) / 2);
+ return Clip255((uint32_t)(a + (a - b) / 2));
}
static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
@@ -293,10 +293,10 @@
const uint32_t red = argb >> 16;
int new_red = red & 0xff;
int new_blue = argb & 0xff;
- new_red += ColorTransformDelta(m->green_to_red_, green);
+ new_red += ColorTransformDelta((int8_t)m->green_to_red_, green);
new_red &= 0xff;
- new_blue += ColorTransformDelta(m->green_to_blue_, green);
- new_blue += ColorTransformDelta(m->red_to_blue_, (int8_t)new_red);
+ new_blue += ColorTransformDelta((int8_t)m->green_to_blue_, green);
+ new_blue += ColorTransformDelta((int8_t)m->red_to_blue_, (int8_t)new_red);
new_blue &= 0xff;
dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
}
@@ -395,7 +395,7 @@
assert(row_start < row_end);
assert(row_end <= transform->ysize_);
switch (transform->type_) {
- case SUBTRACT_GREEN:
+ case SUBTRACT_GREEN_TRANSFORM:
VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);
break;
case PREDICTOR_TRANSFORM:
diff --git a/src/dsp/lossless.h b/src/dsp/lossless.h
index c26c6bc..de60d95 100644
--- a/src/dsp/lossless.h
+++ b/src/dsp/lossless.h
@@ -182,9 +182,9 @@
// -----------------------------------------------------------------------------
// Huffman-cost related functions.
-typedef double (*VP8LCostFunc)(const uint32_t* population, int length);
-typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
- int length);
+typedef float (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
const int Y[256]);
@@ -198,7 +198,7 @@
} VP8LStreaks;
typedef struct { // small struct to hold bit entropy results
- double entropy; // entropy
+ float entropy; // entropy
uint32_t sum; // sum of the population
int nonzeros; // number of non-zero elements in the population
uint32_t max_val; // maximum value in the population
diff --git a/src/dsp/lossless_enc.c b/src/dsp/lossless_enc.c
index 1580631..b1f9f26 100644
--- a/src/dsp/lossless_enc.c
+++ b/src/dsp/lossless_enc.c
@@ -402,7 +402,7 @@
// Compute the combined Shanon's entropy for distribution {X} and {X+Y}
static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) {
int i;
- double retval = 0.;
+ float retval = 0.f;
int sumX = 0, sumXY = 0;
for (i = 0; i < 256; ++i) {
const int x = X[i];
@@ -418,7 +418,7 @@
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
- return (float)retval;
+ return retval;
}
void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) {
@@ -522,11 +522,11 @@
void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
int i;
for (i = 0; i < num_pixels; ++i) {
- const int argb = argb_data[i];
+ const int argb = (int)argb_data[i];
const int green = (argb >> 8) & 0xff;
const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
const uint32_t new_b = (((argb >> 0) & 0xff) - green) & 0xff;
- argb_data[i] = (argb & 0xff00ff00u) | (new_r << 16) | new_b;
+ argb_data[i] = ((uint32_t)argb & 0xff00ff00u) | (new_r << 16) | new_b;
}
}
@@ -547,10 +547,10 @@
const int8_t red = U32ToS8(argb >> 16);
int new_red = red & 0xff;
int new_blue = argb & 0xff;
- new_red -= ColorTransformDelta(m->green_to_red_, green);
+ new_red -= ColorTransformDelta((int8_t)m->green_to_red_, green);
new_red &= 0xff;
- new_blue -= ColorTransformDelta(m->green_to_blue_, green);
- new_blue -= ColorTransformDelta(m->red_to_blue_, red);
+ new_blue -= ColorTransformDelta((int8_t)m->green_to_blue_, green);
+ new_blue -= ColorTransformDelta((int8_t)m->red_to_blue_, red);
new_blue &= 0xff;
data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
}
@@ -560,7 +560,7 @@
uint32_t argb) {
const int8_t green = U32ToS8(argb >> 8);
int new_red = argb >> 16;
- new_red -= ColorTransformDelta(green_to_red, green);
+ new_red -= ColorTransformDelta((int8_t)green_to_red, green);
return (new_red & 0xff);
}
@@ -569,9 +569,9 @@
uint32_t argb) {
const int8_t green = U32ToS8(argb >> 8);
const int8_t red = U32ToS8(argb >> 16);
- uint8_t new_blue = argb & 0xff;
- new_blue -= ColorTransformDelta(green_to_blue, green);
- new_blue -= ColorTransformDelta(red_to_blue, red);
+ int new_blue = argb & 0xff;
+ new_blue -= ColorTransformDelta((int8_t)green_to_blue, green);
+ new_blue -= ColorTransformDelta((int8_t)red_to_blue, red);
return (new_blue & 0xff);
}
@@ -636,17 +636,17 @@
//------------------------------------------------------------------------------
-static double ExtraCost_C(const uint32_t* population, int length) {
+static float ExtraCost_C(const uint32_t* population, int length) {
int i;
- double cost = 0.;
+ float cost = 0.f;
for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
return cost;
}
-static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
+static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
int length) {
int i;
- double cost = 0.;
+ float cost = 0.f;
for (i = 2; i < length - 2; ++i) {
const int xy = X[i + 2] + Y[i + 2];
cost += (i >> 1) * xy;
diff --git a/src/dsp/lossless_enc_mips32.c b/src/dsp/lossless_enc_mips32.c
index 9963051..639f786 100644
--- a/src/dsp/lossless_enc_mips32.c
+++ b/src/dsp/lossless_enc_mips32.c
@@ -103,8 +103,8 @@
// cost += i * *(pop + 1);
// pop += 2;
// }
-// return (double)cost;
-static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
+// return (float)cost;
+static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
int i, temp0, temp1;
const uint32_t* pop = &population[4];
const uint32_t* const LoopEnd = &population[length];
@@ -130,7 +130,7 @@
: "memory", "hi", "lo"
);
- return (double)((int64_t)temp0 << 32 | temp1);
+ return (float)((int64_t)temp0 << 32 | temp1);
}
// C version of this function:
@@ -148,9 +148,9 @@
// pX += 2;
// pY += 2;
// }
-// return (double)cost;
-static double ExtraCostCombined_MIPS32(const uint32_t* const X,
- const uint32_t* const Y, int length) {
+// return (float)cost;
+static float ExtraCostCombined_MIPS32(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
int i, temp0, temp1, temp2, temp3;
const uint32_t* pX = &X[4];
const uint32_t* pY = &Y[4];
@@ -183,7 +183,7 @@
: "memory", "hi", "lo"
);
- return (double)((int64_t)temp0 << 32 | temp1);
+ return (float)((int64_t)temp0 << 32 | temp1);
}
#define HUFFMAN_COST_PASS \
diff --git a/src/dsp/lossless_enc_sse2.c b/src/dsp/lossless_enc_sse2.c
index b2f83b8..66cbaab 100644
--- a/src/dsp/lossless_enc_sse2.c
+++ b/src/dsp/lossless_enc_sse2.c
@@ -54,8 +54,8 @@
const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red_),
CST_5b(m->green_to_blue_));
const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue_), 0);
- const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
- const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks
+ const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks
+ const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks
int i;
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb
@@ -239,7 +239,7 @@
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
int i;
- double retval = 0.;
+ float retval = 0.f;
int sumX = 0, sumXY = 0;
const __m128i zero = _mm_setzero_si128();
@@ -273,7 +273,7 @@
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
- return (float)retval;
+ return retval;
}
#else
@@ -376,7 +376,7 @@
break;
}
case 2: {
- const __m128i mask_or = _mm_set1_epi32(0xff000000);
+ const __m128i mask_or = _mm_set1_epi32((int)0xff000000);
const __m128i mul_cst = _mm_set1_epi16(0x0104);
const __m128i mask_mul = _mm_set1_epi16(0x0f00);
for (x = 0; x + 16 <= width; x += 16, dst += 4) {
@@ -427,7 +427,7 @@
static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
int i;
- const __m128i black = _mm_set1_epi32(ARGB_BLACK);
+ const __m128i black = _mm_set1_epi32((int)ARGB_BLACK);
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
const __m128i res = _mm_sub_epi8(src, black);
diff --git a/src/dsp/lossless_sse2.c b/src/dsp/lossless_sse2.c
index 396cb0b..4b6a532 100644
--- a/src/dsp/lossless_sse2.c
+++ b/src/dsp/lossless_sse2.c
@@ -27,23 +27,22 @@
uint32_t c1,
uint32_t c2) {
const __m128i zero = _mm_setzero_si128();
- const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
- const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
- const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c1), zero);
+ const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c2), zero);
const __m128i V1 = _mm_add_epi16(C0, C1);
const __m128i V2 = _mm_sub_epi16(V1, C2);
const __m128i b = _mm_packus_epi16(V2, V2);
- const uint32_t output = _mm_cvtsi128_si32(b);
- return output;
+ return (uint32_t)_mm_cvtsi128_si32(b);
}
static WEBP_INLINE uint32_t ClampedAddSubtractHalf_SSE2(uint32_t c0,
uint32_t c1,
uint32_t c2) {
const __m128i zero = _mm_setzero_si128();
- const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
- const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
- const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c1), zero);
+ const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)c2), zero);
const __m128i avg = _mm_add_epi16(C1, C0);
const __m128i A0 = _mm_srli_epi16(avg, 1);
const __m128i A1 = _mm_sub_epi16(A0, B0);
@@ -52,16 +51,15 @@
const __m128i A3 = _mm_srai_epi16(A2, 1);
const __m128i A4 = _mm_add_epi16(A0, A3);
const __m128i A5 = _mm_packus_epi16(A4, A4);
- const uint32_t output = _mm_cvtsi128_si32(A5);
- return output;
+ return (uint32_t)_mm_cvtsi128_si32(A5);
}
static WEBP_INLINE uint32_t Select_SSE2(uint32_t a, uint32_t b, uint32_t c) {
int pa_minus_pb;
const __m128i zero = _mm_setzero_si128();
- const __m128i A0 = _mm_cvtsi32_si128(a);
- const __m128i B0 = _mm_cvtsi32_si128(b);
- const __m128i C0 = _mm_cvtsi32_si128(c);
+ const __m128i A0 = _mm_cvtsi32_si128((int)a);
+ const __m128i B0 = _mm_cvtsi32_si128((int)b);
+ const __m128i C0 = _mm_cvtsi32_si128((int)c);
const __m128i AC0 = _mm_subs_epu8(A0, C0);
const __m128i CA0 = _mm_subs_epu8(C0, A0);
const __m128i BC0 = _mm_subs_epu8(B0, C0);
@@ -94,8 +92,8 @@
__m128i* const avg) {
// (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
const __m128i ones = _mm_set1_epi8(1);
- const __m128i A0 = _mm_cvtsi32_si128(a0);
- const __m128i A1 = _mm_cvtsi32_si128(a1);
+ const __m128i A0 = _mm_cvtsi32_si128((int)a0);
+ const __m128i A1 = _mm_cvtsi32_si128((int)a1);
const __m128i avg1 = _mm_avg_epu8(A0, A1);
const __m128i one = _mm_and_si128(_mm_xor_si128(A0, A1), ones);
*avg = _mm_sub_epi8(avg1, one);
@@ -103,8 +101,8 @@
static WEBP_INLINE __m128i Average2_uint32_16_SSE2(uint32_t a0, uint32_t a1) {
const __m128i zero = _mm_setzero_si128();
- const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
- const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a0), zero);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a1), zero);
const __m128i sum = _mm_add_epi16(A1, A0);
return _mm_srli_epi16(sum, 1);
}
@@ -112,19 +110,18 @@
static WEBP_INLINE uint32_t Average2_SSE2(uint32_t a0, uint32_t a1) {
__m128i output;
Average2_uint32_SSE2(a0, a1, &output);
- return _mm_cvtsi128_si32(output);
+ return (uint32_t)_mm_cvtsi128_si32(output);
}
static WEBP_INLINE uint32_t Average3_SSE2(uint32_t a0, uint32_t a1,
uint32_t a2) {
const __m128i zero = _mm_setzero_si128();
const __m128i avg1 = Average2_uint32_16_SSE2(a0, a2);
- const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128((int)a1), zero);
const __m128i sum = _mm_add_epi16(avg1, A1);
const __m128i avg2 = _mm_srli_epi16(sum, 1);
const __m128i A2 = _mm_packus_epi16(avg2, avg2);
- const uint32_t output = _mm_cvtsi128_si32(A2);
- return output;
+ return (uint32_t)_mm_cvtsi128_si32(A2);
}
static WEBP_INLINE uint32_t Average4_SSE2(uint32_t a0, uint32_t a1,
@@ -134,8 +131,7 @@
const __m128i sum = _mm_add_epi16(avg2, avg1);
const __m128i avg3 = _mm_srli_epi16(sum, 1);
const __m128i A0 = _mm_packus_epi16(avg3, avg3);
- const uint32_t output = _mm_cvtsi128_si32(A0);
- return output;
+ return (uint32_t)_mm_cvtsi128_si32(A0);
}
static uint32_t Predictor5_SSE2(const uint32_t* const left,
@@ -192,7 +188,7 @@
static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
int i;
- const __m128i black = _mm_set1_epi32(ARGB_BLACK);
+ const __m128i black = _mm_set1_epi32((int)ARGB_BLACK);
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
const __m128i res = _mm_add_epi8(src, black);
@@ -208,7 +204,7 @@
static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
int i;
- __m128i prev = _mm_set1_epi32(out[-1]);
+ __m128i prev = _mm_set1_epi32((int)out[-1]);
for (i = 0; i + 4 <= num_pixels; i += 4) {
// a | b | c | d
const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
@@ -285,12 +281,12 @@
#undef GENERATE_PREDICTOR_2
// Predictor10: average of (average of (L,TL), average of (T, TR)).
-#define DO_PRED10(OUT) do { \
- __m128i avgLTL, avg; \
- Average2_m128i(&L, &TL, &avgLTL); \
- Average2_m128i(&avgTTR, &avgLTL, &avg); \
- L = _mm_add_epi8(avg, src); \
- out[i + (OUT)] = _mm_cvtsi128_si32(L); \
+#define DO_PRED10(OUT) do { \
+ __m128i avgLTL, avg; \
+ Average2_m128i(&L, &TL, &avgLTL); \
+ Average2_m128i(&avgTTR, &avgLTL, &avg); \
+ L = _mm_add_epi8(avg, src); \
+ out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(L); \
} while (0)
#define DO_PRED10_SHIFT do { \
@@ -303,7 +299,7 @@
static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
int i;
- __m128i L = _mm_cvtsi32_si128(out[-1]);
+ __m128i L = _mm_cvtsi32_si128((int)out[-1]);
for (i = 0; i + 4 <= num_pixels; i += 4) {
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
__m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
@@ -336,7 +332,7 @@
const __m128i B = _mm_andnot_si128(mask, T); \
const __m128i pred = _mm_or_si128(A, B); /* pred = (pa > b)? L : T*/ \
L = _mm_add_epi8(src, pred); \
- out[i + (OUT)] = _mm_cvtsi128_si32(L); \
+ out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(L); \
} while (0)
#define DO_PRED11_SHIFT do { \
@@ -351,7 +347,7 @@
int num_pixels, uint32_t* out) {
int i;
__m128i pa;
- __m128i L = _mm_cvtsi32_si128(out[-1]);
+ __m128i L = _mm_cvtsi32_si128((int)out[-1]);
for (i = 0; i + 4 <= num_pixels; i += 4) {
__m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
__m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
@@ -384,12 +380,12 @@
#undef DO_PRED11_SHIFT
// Predictor12: ClampedAddSubtractFull.
-#define DO_PRED12(DIFF, LANE, OUT) do { \
- const __m128i all = _mm_add_epi16(L, (DIFF)); \
- const __m128i alls = _mm_packus_epi16(all, all); \
- const __m128i res = _mm_add_epi8(src, alls); \
- out[i + (OUT)] = _mm_cvtsi128_si32(res); \
- L = _mm_unpacklo_epi8(res, zero); \
+#define DO_PRED12(DIFF, LANE, OUT) do { \
+ const __m128i all = _mm_add_epi16(L, (DIFF)); \
+ const __m128i alls = _mm_packus_epi16(all, all); \
+ const __m128i res = _mm_add_epi8(src, alls); \
+ out[i + (OUT)] = (uint32_t)_mm_cvtsi128_si32(res); \
+ L = _mm_unpacklo_epi8(res, zero); \
} while (0)
#define DO_PRED12_SHIFT(DIFF, LANE) do { \
@@ -402,7 +398,7 @@
int num_pixels, uint32_t* out) {
int i;
const __m128i zero = _mm_setzero_si128();
- const __m128i L8 = _mm_cvtsi32_si128(out[-1]);
+ const __m128i L8 = _mm_cvtsi32_si128((int)out[-1]);
__m128i L = _mm_unpacklo_epi8(L8, zero);
for (i = 0; i + 4 <= num_pixels; i += 4) {
// Load 4 pixels at a time.
@@ -468,7 +464,7 @@
const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0);
#undef MK_CST_16
#undef CST
- const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
+ const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks
int i;
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
@@ -532,7 +528,7 @@
static void ConvertBGRAToRGBA_SSE2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
- const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ffu);
+ const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ff);
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
while (num_pixels >= 8) {
@@ -561,7 +557,7 @@
static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
- const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
+ const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0);
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
while (num_pixels >= 8) {
@@ -596,8 +592,8 @@
static void ConvertBGRAToRGB565_SSE2(const uint32_t* src,
int num_pixels, uint8_t* dst) {
- const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
- const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
+ const __m128i mask_0xe0 = _mm_set1_epi8((char)0xe0);
+ const __m128i mask_0xf8 = _mm_set1_epi8((char)0xf8);
const __m128i mask_0x07 = _mm_set1_epi8(0x07);
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
diff --git a/src/dsp/lossless_sse41.c b/src/dsp/lossless_sse41.c
index b0d6daa..bb7ce76 100644
--- a/src/dsp/lossless_sse41.c
+++ b/src/dsp/lossless_sse41.c
@@ -25,11 +25,12 @@
int num_pixels, uint32_t* dst) {
// sign-extended multiplying constants, pre-shifted by 5.
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
- const __m128i mults_rb = _mm_set1_epi32((uint32_t)CST(green_to_red_) << 16 |
- (CST(green_to_blue_) & 0xffff));
+ const __m128i mults_rb =
+ _mm_set1_epi32((int)((uint32_t)CST(green_to_red_) << 16 |
+ (CST(green_to_blue_) & 0xffff)));
const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_));
#undef CST
- const __m128i mask_ag = _mm_set1_epi32(0xff00ff00);
+ const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00);
const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5,
-1, 9, -1, 9, -1, 13, -1, 13);
const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1,
diff --git a/src/dsp/quant.h b/src/dsp/quant.h
index 5e8dba8..fc099bf 100644
--- a/src/dsp/quant.h
+++ b/src/dsp/quant.h
@@ -21,10 +21,15 @@
#define IsFlat IsFlat_NEON
-static uint32x2_t horizontal_add_uint32x4(const uint32x4_t a) {
+static uint32_t horizontal_add_uint32x4(const uint32x4_t a) {
+#if defined(__aarch64__)
+ return vaddvq_u32(a);
+#else
const uint64x2_t b = vpaddlq_u32(a);
- return vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
- vreinterpret_u32_u64(vget_high_u64(b)));
+ const uint32x2_t c = vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
+ vreinterpret_u32_u64(vget_high_u64(b)));
+ return vget_lane_u32(c, 0);
+#endif
}
static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
@@ -45,7 +50,7 @@
levels += 16;
}
- return thresh >= (int32_t)vget_lane_u32(horizontal_add_uint32x4(sum), 0);
+ return thresh >= (int)horizontal_add_uint32x4(sum);
}
#else
diff --git a/src/dsp/rescaler_sse2.c b/src/dsp/rescaler_sse2.c
index d7effea..3f18e94 100644
--- a/src/dsp/rescaler_sse2.c
+++ b/src/dsp/rescaler_sse2.c
@@ -85,7 +85,7 @@
const __m128i mult = _mm_cvtsi32_si128(((x_add - accum) << 16) | accum);
const __m128i out = _mm_madd_epi16(cur_pixels, mult);
assert(sizeof(*frow) == sizeof(uint32_t));
- WebPUint32ToMem((uint8_t*)frow, _mm_cvtsi128_si32(out));
+ WebPInt32ToMem((uint8_t*)frow, _mm_cvtsi128_si32(out));
frow += 1;
if (frow >= frow_end) break;
accum -= wrk->x_sub;
@@ -132,7 +132,7 @@
__m128i base = zero;
accum += wrk->x_add;
while (accum > 0) {
- const __m128i A = _mm_cvtsi32_si128(WebPMemToUint32(src));
+ const __m128i A = _mm_cvtsi32_si128(WebPMemToInt32(src));
src += 4;
base = _mm_unpacklo_epi8(A, zero);
// To avoid overflow, we need: base * x_add / x_sub < 32768
@@ -198,7 +198,7 @@
const __m128i* const mult,
uint8_t* const dst) {
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
- const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
+ const __m128i mask = _mm_set_epi32(~0, 0, ~0, 0);
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
const __m128i B1 = _mm_mul_epu32(*A1, *mult);
const __m128i B2 = _mm_mul_epu32(*A2, *mult);
diff --git a/src/dsp/upsampling_sse2.c b/src/dsp/upsampling_sse2.c
index 340f1e2..08b6d0b 100644
--- a/src/dsp/upsampling_sse2.c
+++ b/src/dsp/upsampling_sse2.c
@@ -121,7 +121,7 @@
int uv_pos, pos; \
/* 16byte-aligned array to cache reconstructed u and v */ \
uint8_t uv_buf[14 * 32 + 15] = { 0 }; \
- uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
+ uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~(uintptr_t)15); \
uint8_t* const r_v = r_u + 32; \
\
assert(top_y != NULL); \
diff --git a/src/dsp/yuv.c b/src/dsp/yuv.c
index 48466f8..d16c13d 100644
--- a/src/dsp/yuv.c
+++ b/src/dsp/yuv.c
@@ -194,50 +194,6 @@
//-----------------------------------------------------------------------------
-#if !WEBP_NEON_OMIT_C_CODE
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_C(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- uint64_t diff = 0;
- int i;
- for (i = 0; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)dst[i] + diff_y;
- dst[i] = clip_y(new_y);
- diff += (uint64_t)abs(diff_y);
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_C(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i;
- for (i = 0; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- for (i = 0; i < len; ++i, ++A, ++B) {
- const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
- const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
- out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
- }
-}
-#endif // !WEBP_NEON_OMIT_C_CODE
-
-#undef MAX_Y
-
-//-----------------------------------------------------------------------------
-
void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width);
void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width);
void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb,
@@ -247,18 +203,9 @@
void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v,
int src_width, int do_store);
-uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len);
-void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len);
-void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out);
-
extern void WebPInitConvertARGBToYUVSSE2(void);
extern void WebPInitConvertARGBToYUVSSE41(void);
extern void WebPInitConvertARGBToYUVNEON(void);
-extern void WebPInitSharpYUVSSE2(void);
-extern void WebPInitSharpYUVNEON(void);
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
WebPConvertARGBToY = ConvertARGBToY_C;
@@ -269,17 +216,10 @@
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
-#if !WEBP_NEON_OMIT_C_CODE
- WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
-#endif
-
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitConvertARGBToYUVSSE2();
- WebPInitSharpYUVSSE2();
}
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_SSE41)
@@ -293,7 +233,6 @@
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitConvertARGBToYUVNEON();
- WebPInitSharpYUVNEON();
}
#endif // WEBP_HAVE_NEON
@@ -302,7 +241,4 @@
assert(WebPConvertRGB24ToY != NULL);
assert(WebPConvertBGR24ToY != NULL);
assert(WebPConvertRGBA32ToUV != NULL);
- assert(WebPSharpYUVUpdateY != NULL);
- assert(WebPSharpYUVUpdateRGB != NULL);
- assert(WebPSharpYUVFilterRow != NULL);
}
diff --git a/src/dsp/yuv_neon.c b/src/dsp/yuv_neon.c
index a34d602..ff77b00 100644
--- a/src/dsp/yuv_neon.c
+++ b/src/dsp/yuv_neon.c
@@ -173,116 +173,8 @@
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_NEON;
}
-//------------------------------------------------------------------------------
-
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y_NEON(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- int i;
- const int16x8_t zero = vdupq_n_s16(0);
- const int16x8_t max = vdupq_n_s16(MAX_Y);
- uint64x2_t sum = vdupq_n_u64(0);
- uint64_t diff;
-
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
- const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
- const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
- const int16x8_t D = vsubq_s16(A, B); // diff_y
- const int16x8_t F = vaddq_s16(C, D); // new_y
- const uint16x8_t H =
- vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
- const int16x8_t I = vabsq_s16(D); // abs(diff_y)
- vst1q_u16(dst + i, H);
- sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
- }
- diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
- for (; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)(dst[i]) + diff_y;
- dst[i] = clip_y_NEON(new_y);
- diff += (uint64_t)(abs(diff_y));
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i;
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t A = vld1q_s16(ref + i);
- const int16x8_t B = vld1q_s16(src + i);
- const int16x8_t C = vld1q_s16(dst + i);
- const int16x8_t D = vsubq_s16(A, B); // diff_uv
- const int16x8_t E = vaddq_s16(C, D); // new_uv
- vst1q_s16(dst + i, E);
- }
- for (; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- const int16x8_t max = vdupq_n_s16(MAX_Y);
- const int16x8_t zero = vdupq_n_s16(0);
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t a0 = vld1q_s16(A + i + 0);
- const int16x8_t a1 = vld1q_s16(A + i + 1);
- const int16x8_t b0 = vld1q_s16(B + i + 0);
- const int16x8_t b1 = vld1q_s16(B + i + 1);
- const int16x8_t a0b1 = vaddq_s16(a0, b1);
- const int16x8_t a1b0 = vaddq_s16(a1, b0);
- const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
- const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
- const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
- const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
- const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
- const int16x8_t d0 = vaddq_s16(c1, a0);
- const int16x8_t d1 = vaddq_s16(c0, a1);
- const int16x8_t e0 = vrshrq_n_s16(d0, 1);
- const int16x8_t e1 = vrshrq_n_s16(d1, 1);
- const int16x8x2_t f = vzipq_s16(e0, e1);
- const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
- const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
- const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
- const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
- const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
- const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
- vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
- vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
- }
- for (; i < len; ++i) {
- const int a0b1 = A[i + 0] + B[i + 1];
- const int a1b0 = A[i + 1] + B[i + 0];
- const int a0a1b0b1 = a0b1 + a1b0 + 8;
- const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
- const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
- out[2 * i + 0] = clip_y_NEON(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y_NEON(best_y[2 * i + 1] + v1);
- }
-}
-#undef MAX_Y
-
-//------------------------------------------------------------------------------
-
-extern void WebPInitSharpYUVNEON(void);
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVNEON(void) {
- WebPSharpYUVUpdateY = SharpYUVUpdateY_NEON;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_NEON;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_NEON;
-}
-
#else // !WEBP_USE_NEON
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVNEON)
-WEBP_DSP_INIT_STUB(WebPInitSharpYUVNEON)
#endif // WEBP_USE_NEON
diff --git a/src/dsp/yuv_sse2.c b/src/dsp/yuv_sse2.c
index baa48d5..01a48f9 100644
--- a/src/dsp/yuv_sse2.c
+++ b/src/dsp/yuv_sse2.c
@@ -15,10 +15,12 @@
#if defined(WEBP_USE_SSE2)
-#include "src/dsp/common_sse2.h"
#include <stdlib.h>
#include <emmintrin.h>
+#include "src/dsp/common_sse2.h"
+#include "src/utils/utils.h"
+
//-----------------------------------------------------------------------------
// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
@@ -74,7 +76,7 @@
// Load and replicate the U/V samples
static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) {
const __m128i zero = _mm_setzero_si128();
- const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
+ const __m128i tmp0 = _mm_cvtsi32_si128(WebPMemToInt32(src));
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples
}
@@ -130,7 +132,7 @@
const __m128i rg0 = _mm_packus_epi16(*B, *A);
const __m128i ba0 = _mm_packus_epi16(*R, *G);
#endif
- const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
+ const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0);
const __m128i rb1 = _mm_unpacklo_epi8(rg0, ba0); // rbrbrbrbrb...
const __m128i ga1 = _mm_unpackhi_epi8(rg0, ba0); // gagagagaga...
const __m128i rb2 = _mm_and_si128(rb1, mask_0xf0);
@@ -147,9 +149,10 @@
const __m128i r0 = _mm_packus_epi16(*R, *R);
const __m128i g0 = _mm_packus_epi16(*G, *G);
const __m128i b0 = _mm_packus_epi16(*B, *B);
- const __m128i r1 = _mm_and_si128(r0, _mm_set1_epi8(0xf8));
+ const __m128i r1 = _mm_and_si128(r0, _mm_set1_epi8((char)0xf8));
const __m128i b1 = _mm_and_si128(_mm_srli_epi16(b0, 3), _mm_set1_epi8(0x1f));
- const __m128i g1 = _mm_srli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0xe0)), 5);
+ const __m128i g1 =
+ _mm_srli_epi16(_mm_and_si128(g0, _mm_set1_epi8((char)0xe0)), 5);
const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3);
const __m128i rg = _mm_or_si128(r1, g1);
const __m128i gb = _mm_or_si128(g2, b1);
@@ -747,128 +750,9 @@
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
}
-//------------------------------------------------------------------------------
-
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- uint64_t diff = 0;
- uint32_t tmp[4];
- int i;
- const __m128i zero = _mm_setzero_si128();
- const __m128i max = _mm_set1_epi16(MAX_Y);
- const __m128i one = _mm_set1_epi16(1);
- __m128i sum = zero;
-
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
- const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
- const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
- const __m128i D = _mm_sub_epi16(A, B); // diff_y
- const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
- const __m128i F = _mm_add_epi16(C, D); // new_y
- const __m128i G = _mm_or_si128(E, one); // -1 or 1
- const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
- const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
- _mm_storeu_si128((__m128i*)(dst + i), H);
- sum = _mm_add_epi32(sum, I);
- }
- _mm_storeu_si128((__m128i*)tmp, sum);
- diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
- for (; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)dst[i] + diff_y;
- dst[i] = clip_y(new_y);
- diff += (uint64_t)abs(diff_y);
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i = 0;
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
- const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
- const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
- const __m128i D = _mm_sub_epi16(A, B); // diff_uv
- const __m128i E = _mm_add_epi16(C, D); // new_uv
- _mm_storeu_si128((__m128i*)(dst + i), E);
- }
- for (; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- const __m128i kCst8 = _mm_set1_epi16(8);
- const __m128i max = _mm_set1_epi16(MAX_Y);
- const __m128i zero = _mm_setzero_si128();
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
- const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
- const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
- const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
- const __m128i a0b1 = _mm_add_epi16(a0, b1);
- const __m128i a1b0 = _mm_add_epi16(a1, b0);
- const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
- const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
- const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
- const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
- const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
- const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
- const __m128i d0 = _mm_add_epi16(c1, a0);
- const __m128i d1 = _mm_add_epi16(c0, a1);
- const __m128i e0 = _mm_srai_epi16(d0, 1);
- const __m128i e1 = _mm_srai_epi16(d1, 1);
- const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
- const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
- const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
- const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
- const __m128i h0 = _mm_add_epi16(g0, f0);
- const __m128i h1 = _mm_add_epi16(g1, f1);
- const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
- const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
- _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
- _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
- }
- for (; i < len; ++i) {
- // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
- // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
- // We reuse the common sub-expressions.
- const int a0b1 = A[i + 0] + B[i + 1];
- const int a1b0 = A[i + 1] + B[i + 0];
- const int a0a1b0b1 = a0b1 + a1b0 + 8;
- const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
- const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
- out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
- }
-}
-
-#undef MAX_Y
-
-//------------------------------------------------------------------------------
-
-extern void WebPInitSharpYUVSSE2(void);
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVSSE2(void) {
- WebPSharpYUVUpdateY = SharpYUVUpdateY_SSE2;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_SSE2;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_SSE2;
-}
-
#else // !WEBP_USE_SSE2
WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2)
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2)
-WEBP_DSP_INIT_STUB(WebPInitSharpYUVSSE2)
#endif // WEBP_USE_SSE2
diff --git a/src/dsp/yuv_sse41.c b/src/dsp/yuv_sse41.c
index 579d1f7..f79b802 100644
--- a/src/dsp/yuv_sse41.c
+++ b/src/dsp/yuv_sse41.c
@@ -15,10 +15,12 @@
#if defined(WEBP_USE_SSE41)
-#include "src/dsp/common_sse41.h"
#include <stdlib.h>
#include <smmintrin.h>
+#include "src/dsp/common_sse41.h"
+#include "src/utils/utils.h"
+
//-----------------------------------------------------------------------------
// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
@@ -74,7 +76,7 @@
// Load and replicate the U/V samples
static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) {
const __m128i zero = _mm_setzero_si128();
- const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
+ const __m128i tmp0 = _mm_cvtsi32_si128(WebPMemToInt32(src));
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples
}
diff --git a/src/enc/Makefile.am b/src/enc/Makefile.am
new file mode 100644
index 0000000..2fec804
--- /dev/null
+++ b/src/enc/Makefile.am
@@ -0,0 +1,43 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+noinst_LTLIBRARIES = libwebpencode.la
+
+libwebpencode_la_SOURCES =
+libwebpencode_la_SOURCES += alpha_enc.c
+libwebpencode_la_SOURCES += analysis_enc.c
+libwebpencode_la_SOURCES += backward_references_cost_enc.c
+libwebpencode_la_SOURCES += backward_references_enc.c
+libwebpencode_la_SOURCES += backward_references_enc.h
+libwebpencode_la_SOURCES += config_enc.c
+libwebpencode_la_SOURCES += cost_enc.c
+libwebpencode_la_SOURCES += cost_enc.h
+libwebpencode_la_SOURCES += filter_enc.c
+libwebpencode_la_SOURCES += frame_enc.c
+libwebpencode_la_SOURCES += histogram_enc.c
+libwebpencode_la_SOURCES += histogram_enc.h
+libwebpencode_la_SOURCES += iterator_enc.c
+libwebpencode_la_SOURCES += near_lossless_enc.c
+libwebpencode_la_SOURCES += picture_enc.c
+libwebpencode_la_SOURCES += picture_csp_enc.c
+libwebpencode_la_SOURCES += picture_psnr_enc.c
+libwebpencode_la_SOURCES += picture_rescale_enc.c
+libwebpencode_la_SOURCES += picture_tools_enc.c
+libwebpencode_la_SOURCES += predictor_enc.c
+libwebpencode_la_SOURCES += quant_enc.c
+libwebpencode_la_SOURCES += syntax_enc.c
+libwebpencode_la_SOURCES += token_enc.c
+libwebpencode_la_SOURCES += tree_enc.c
+libwebpencode_la_SOURCES += vp8i_enc.h
+libwebpencode_la_SOURCES += vp8l_enc.c
+libwebpencode_la_SOURCES += vp8li_enc.h
+libwebpencode_la_SOURCES += webp_enc.c
+
+libwebpencodeinclude_HEADERS =
+libwebpencodeinclude_HEADERS += ../webp/encode.h
+libwebpencodeinclude_HEADERS += ../webp/types.h
+noinst_HEADERS =
+noinst_HEADERS += ../webp/format_constants.h
+
+libwebpencode_la_LIBADD = ../../sharpyuv/libsharpyuv.la
+libwebpencode_la_LDFLAGS = -lm
+libwebpencode_la_CPPFLAGS = $(AM_CPPFLAGS)
+libwebpencodeincludedir = $(includedir)/webp
diff --git a/src/enc/alpha_enc.c b/src/enc/alpha_enc.c
index 0b54f3e..7d20558 100644
--- a/src/enc/alpha_enc.c
+++ b/src/enc/alpha_enc.c
@@ -13,6 +13,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "src/enc/vp8i_enc.h"
#include "src/dsp/dsp.h"
@@ -86,7 +87,7 @@
// a decoder bug related to alpha with color cache.
// See: https://code.google.com/p/webp/issues/detail?id=239
// Need to re-enable this later.
- ok = (VP8LEncodeStream(&config, &picture, bw, 0 /*use_cache*/) == VP8_ENC_OK);
+ ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
if (!ok) {
@@ -148,6 +149,7 @@
}
} else {
VP8LBitWriterWipeOut(&tmp_bw);
+ memset(&result->bw, 0, sizeof(result->bw));
return 0;
}
}
@@ -162,7 +164,7 @@
header = method | (filter << 2);
if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
- VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size);
+ if (!VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size)) ok = 0;
ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
ok = ok && VP8BitWriterAppend(&result->bw, output, output_size);
diff --git a/src/enc/analysis_enc.c b/src/enc/analysis_enc.c
index ebb7842..a0001ac 100644
--- a/src/enc/analysis_enc.c
+++ b/src/enc/analysis_enc.c
@@ -391,12 +391,14 @@
return ok;
}
+#ifdef WEBP_USE_THREAD
static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
int i;
for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
dst->alpha += src->alpha;
dst->uv_alpha += src->uv_alpha;
}
+#endif
// initialize the job struct with some tasks to perform
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
@@ -425,10 +427,10 @@
(enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled.
if (do_segments) {
const int last_row = enc->mb_h_;
- // We give a little more than a half work to the main thread.
- const int split_row = (9 * last_row + 15) >> 4;
const int total_mb = last_row * enc->mb_w_;
#ifdef WEBP_USE_THREAD
+ // We give a little more than a half work to the main thread.
+ const int split_row = (9 * last_row + 15) >> 4;
const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
#else
@@ -438,6 +440,7 @@
WebPGetWorkerInterface();
SegmentJob main_job;
if (do_mt) {
+#ifdef WEBP_USE_THREAD
SegmentJob side_job;
// Note the use of '&' instead of '&&' because we must call the functions
// no matter what.
@@ -455,6 +458,7 @@
}
worker_interface->End(&side_job.worker);
if (ok) MergeJobs(&side_job, &main_job); // merge results together
+#endif // WEBP_USE_THREAD
} else {
// Even for single-thread case, we use the generic Worker tools.
InitSegmentJob(enc, &main_job, 0, last_row);
diff --git a/src/enc/backward_references_cost_enc.c b/src/enc/backward_references_cost_enc.c
index 5eb24d4..6968ef3 100644
--- a/src/enc/backward_references_cost_enc.c
+++ b/src/enc/backward_references_cost_enc.c
@@ -15,10 +15,11 @@
//
#include <assert.h>
+#include <float.h>
+#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
-#include "src/dsp/lossless_common.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
@@ -30,15 +31,15 @@
const PixOrCopy v);
typedef struct {
- double alpha_[VALUES_IN_BYTE];
- double red_[VALUES_IN_BYTE];
- double blue_[VALUES_IN_BYTE];
- double distance_[NUM_DISTANCE_CODES];
- double* literal_;
+ float alpha_[VALUES_IN_BYTE];
+ float red_[VALUES_IN_BYTE];
+ float blue_[VALUES_IN_BYTE];
+ float distance_[NUM_DISTANCE_CODES];
+ float* literal_;
} CostModel;
static void ConvertPopulationCountTableToBitEstimates(
- int num_symbols, const uint32_t population_counts[], double output[]) {
+ int num_symbols, const uint32_t population_counts[], float output[]) {
uint32_t sum = 0;
int nonzeros = 0;
int i;
@@ -51,7 +52,7 @@
if (nonzeros <= 1) {
memset(output, 0, num_symbols * sizeof(*output));
} else {
- const double logsum = VP8LFastLog2(sum);
+ const float logsum = VP8LFastLog2(sum);
for (i = 0; i < num_symbols; ++i) {
output[i] = logsum - VP8LFastLog2(population_counts[i]);
}
@@ -75,8 +76,8 @@
}
ConvertPopulationCountTableToBitEstimates(
- VP8LHistogramNumCodes(histo->palette_code_bits_),
- histo->literal_, m->literal_);
+ VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_,
+ m->literal_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo->red_, m->red_);
ConvertPopulationCountTableToBitEstimates(
@@ -92,27 +93,27 @@
return ok;
}
-static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
+static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) {
return m->alpha_[v >> 24] +
m->red_[(v >> 16) & 0xff] +
m->literal_[(v >> 8) & 0xff] +
m->blue_[v & 0xff];
}
-static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
+static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) {
const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
return m->literal_[literal_idx];
}
-static WEBP_INLINE double GetLengthCost(const CostModel* const m,
- uint32_t length) {
+static WEBP_INLINE float GetLengthCost(const CostModel* const m,
+ uint32_t length) {
int code, extra_bits;
VP8LPrefixEncodeBits(length, &code, &extra_bits);
return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
}
-static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
- uint32_t distance) {
+static WEBP_INLINE float GetDistanceCost(const CostModel* const m,
+ uint32_t distance) {
int code, extra_bits;
VP8LPrefixEncodeBits(distance, &code, &extra_bits);
return m->distance_[code] + extra_bits;
@@ -122,20 +123,20 @@
const uint32_t* const argb, VP8LColorCache* const hashers,
const CostModel* const cost_model, int idx, int use_color_cache,
float prev_cost, float* const cost, uint16_t* const dist_array) {
- double cost_val = prev_cost;
+ float cost_val = prev_cost;
const uint32_t color = argb[idx];
const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
if (ix >= 0) {
// use_color_cache is true and hashers contains color
- const double mul0 = 0.68;
+ const float mul0 = 0.68f;
cost_val += GetCacheCost(cost_model, ix) * mul0;
} else {
- const double mul1 = 0.82;
+ const float mul1 = 0.82f;
if (use_color_cache) VP8LColorCacheInsert(hashers, color);
cost_val += GetLiteralCost(cost_model, color) * mul1;
}
if (cost[idx] > cost_val) {
- cost[idx] = (float)cost_val;
+ cost[idx] = cost_val;
dist_array[idx] = 1; // only one is inserted.
}
}
@@ -172,7 +173,7 @@
// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval.
typedef struct {
- double cost_;
+ float cost_;
int start_;
int end_; // Exclusive.
} CostCacheInterval;
@@ -187,7 +188,7 @@
int count_; // The number of stored intervals.
CostCacheInterval* cache_intervals_;
size_t cache_intervals_size_;
- double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
+ float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
float* costs_;
uint16_t* dist_array_;
// Most of the time, we only need few intervals -> use a free-list, to avoid
@@ -262,10 +263,13 @@
CostManagerInitFreeList(manager);
// Fill in the cost_cache_.
- manager->cache_intervals_size_ = 1;
- manager->cost_cache_[0] = GetLengthCost(cost_model, 0);
- for (i = 1; i < cost_cache_size; ++i) {
+ // Has to be done in two passes due to a GCC bug on i686
+ // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
+ for (i = 0; i < cost_cache_size; ++i) {
manager->cost_cache_[i] = GetLengthCost(cost_model, i);
+ }
+ manager->cache_intervals_size_ = 1;
+ for (i = 1; i < cost_cache_size; ++i) {
// Get the number of bound intervals.
if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) {
++manager->cache_intervals_size_;
@@ -294,7 +298,7 @@
cur->end_ = 1;
cur->cost_ = manager->cost_cache_[0];
for (i = 1; i < cost_cache_size; ++i) {
- const double cost_val = manager->cost_cache_[i];
+ const float cost_val = manager->cost_cache_[i];
if (cost_val != cur->cost_) {
++cur;
// Initialize an interval.
@@ -303,6 +307,8 @@
}
cur->end_ = i + 1;
}
+ assert((size_t)(cur - manager->cache_intervals_) + 1 ==
+ manager->cache_intervals_size_);
}
manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_));
@@ -311,7 +317,7 @@
return 0;
}
// Set the initial costs_ high for every pixel as we will keep the minimum.
- for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f;
+ for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX;
return 1;
}
@@ -457,7 +463,7 @@
// If handling the interval or one of its subintervals becomes to heavy, its
// contribution is added to the costs right away.
static WEBP_INLINE void PushInterval(CostManager* const manager,
- double distance_cost, int position,
+ float distance_cost, int position,
int len) {
size_t i;
CostInterval* interval = manager->head_;
@@ -474,7 +480,7 @@
const int k = j - position;
float cost_tmp;
assert(k >= 0 && k < MAX_LENGTH);
- cost_tmp = (float)(distance_cost + manager->cost_cache_[k]);
+ cost_tmp = distance_cost + manager->cost_cache_[k];
if (manager->costs_[j] > cost_tmp) {
manager->costs_[j] = cost_tmp;
@@ -492,7 +498,7 @@
const int end = position + (cost_cache_intervals[i].end_ > len
? len
: cost_cache_intervals[i].end_);
- const float cost = (float)(distance_cost + cost_cache_intervals[i].cost_);
+ const float cost = distance_cost + cost_cache_intervals[i].cost_;
for (; interval != NULL && interval->start_ < end;
interval = interval_next) {
@@ -570,8 +576,7 @@
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
const size_t literal_array_size =
- sizeof(double) * (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
- ((cache_bits > 0) ? (1 << cache_bits) : 0));
+ sizeof(float) * (VP8LHistogramNumCodes(cache_bits));
const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
CostModel* const cost_model =
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
@@ -579,13 +584,13 @@
CostManager* cost_manager =
(CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager));
int offset_prev = -1, len_prev = -1;
- double offset_cost = -1;
+ float offset_cost = -1.f;
int first_offset_is_constant = -1; // initialized with 'impossible' value
int reach = 0;
if (cost_model == NULL || cost_manager == NULL) goto Error;
- cost_model->literal_ = (double*)(cost_model + 1);
+ cost_model->literal_ = (float*)(cost_model + 1);
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
@@ -675,7 +680,7 @@
}
ok = !refs->error_;
-Error:
+ Error:
if (cc_init) VP8LColorCacheClear(&hashers);
CostManagerClear(cost_manager);
WebPSafeFree(cost_model);
diff --git a/src/enc/backward_references_enc.c b/src/enc/backward_references_enc.c
index d5e931e..49a0fac 100644
--- a/src/enc/backward_references_enc.c
+++ b/src/enc/backward_references_enc.c
@@ -10,6 +10,8 @@
// Author: Jyrki Alakuijala (jyrki@google.com)
//
+#include "src/enc/backward_references_enc.h"
+
#include <assert.h>
#include <float.h>
#include <math.h>
@@ -17,10 +19,11 @@
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
+#include "src/enc/vp8i_enc.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#define MIN_BLOCK_SIZE 256 // minimum block size for backward references
@@ -255,10 +258,13 @@
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
- int low_effort) {
+ int low_effort, const WebPPicture* const pic,
+ int percent_range, int* const percent) {
const int size = xsize * ysize;
const int iter_max = GetMaxItersForQuality(quality);
const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
+ int remaining_percent = percent_range;
+ int percent_start = *percent;
int pos;
int argb_comp;
uint32_t base_position;
@@ -276,7 +282,13 @@
hash_to_first_index =
(int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
- if (hash_to_first_index == NULL) return 0;
+ if (hash_to_first_index == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+
+ percent_range = remaining_percent / 2;
+ remaining_percent -= percent_range;
// Set the int32_t array to -1.
memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
@@ -323,12 +335,22 @@
hash_to_first_index[hash_code] = pos++;
argb_comp = argb_comp_next;
}
+
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * pos / (size - 2), percent)) {
+ WebPSafeFree(hash_to_first_index);
+ return 0;
+ }
}
// Process the penultimate pixel.
chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
WebPSafeFree(hash_to_first_index);
+ percent_start += percent_range;
+ if (!WebPReportProgress(pic, percent_start, percent)) return 0;
+ percent_range = remaining_percent;
+
// Find the best match interval at each pixel, defined by an offset to the
// pixel and a length. The right-most pixel cannot match anything to the right
// (hence a best length of 0) and the left-most pixel nothing to the left
@@ -417,8 +439,17 @@
max_base_position = base_position;
}
}
+
+ if (!WebPReportProgress(pic,
+ percent_start + percent_range *
+ (size - 2 - base_position) /
+ (size - 2),
+ percent)) {
+ return 0;
+ }
}
- return 1;
+
+ return WebPReportProgress(pic, percent_start + percent_range, percent);
}
static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
@@ -728,7 +759,7 @@
int* const best_cache_bits) {
int i;
const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits;
- double entropy_min = MAX_ENTROPY;
+ float entropy_min = MAX_ENTROPY;
int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
@@ -813,14 +844,14 @@
}
for (i = 0; i <= cache_bits_max; ++i) {
- const double entropy = VP8LHistogramEstimateBits(histos[i]);
+ const float entropy = VP8LHistogramEstimateBits(histos[i]);
if (i == 0 || entropy < entropy_min) {
entropy_min = entropy;
*best_cache_bits = i;
}
}
ok = 1;
-Error:
+ Error:
for (i = 0; i <= cache_bits_max; ++i) {
if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
VP8LFreeHistogram(histos[i]);
@@ -890,7 +921,7 @@
int i, lz77_type;
// Index 0 is for a color cache, index 1 for no cache (if needed).
int lz77_types_best[2] = {0, 0};
- double bit_costs_best[2] = {DBL_MAX, DBL_MAX};
+ float bit_costs_best[2] = {FLT_MAX, FLT_MAX};
VP8LHashChain hash_chain_box;
VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1];
int status = 0;
@@ -902,7 +933,7 @@
for (lz77_type = 1; lz77_types_to_try;
lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) {
int res = 0;
- double bit_cost = 0.;
+ float bit_cost = 0.f;
if ((lz77_types_to_try & lz77_type) == 0) continue;
switch (lz77_type) {
case kLZ77RLE:
@@ -976,7 +1007,7 @@
const VP8LHashChain* const hash_chain_tmp =
(lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box;
const int cache_bits = (i == 1) ? 0 : *cache_bits_best;
- double bit_cost_trace;
+ float bit_cost_trace;
if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
hash_chain_tmp, &refs[i],
refs_tmp)) {
@@ -1001,31 +1032,37 @@
}
status = 1;
-Error:
+ Error:
VP8LHashChainClear(&hash_chain_box);
VP8LFreeHistogram(histo);
return status;
}
-WebPEncodingError VP8LGetBackwardReferences(
+int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
- int* const cache_bits_best) {
+ int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
+ int* const percent) {
if (low_effort) {
VP8LBackwardRefs* refs_best;
*cache_bits_best = cache_bits_max;
refs_best = GetBackwardReferencesLowEffort(
width, height, argb, cache_bits_best, hash_chain, refs);
- if (refs_best == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (refs_best == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
// Set it in first position.
BackwardRefsSwap(refs_best, &refs[0]);
} else {
if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try,
cache_bits_max, do_no_cache, hash_chain, refs,
cache_bits_best)) {
- return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
}
}
- return VP8_ENC_OK;
+
+ return WebPReportProgress(pic, *percent + percent_range, percent);
}
diff --git a/src/enc/backward_references_enc.h b/src/enc/backward_references_enc.h
index 4c0267b..4dff1c2 100644
--- a/src/enc/backward_references_enc.h
+++ b/src/enc/backward_references_enc.h
@@ -134,10 +134,11 @@
// Must be called first, to set size.
int VP8LHashChainInit(VP8LHashChain* const p, int size);
-// Pre-compute the best matches for argb.
+// Pre-compute the best matches for argb. pic and percent are for progress.
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
- int low_effort);
+ int low_effort, const WebPPicture* const pic,
+ int percent_range, int* const percent);
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
@@ -227,11 +228,14 @@
// VP8LBackwardRefs is put in the first element, the best value with no-cache in
// the second element.
// In both cases, the last element is used as temporary internally.
-WebPEncodingError VP8LGetBackwardReferences(
+// pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
+int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
- int* const cache_bits_best);
+ int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
+ int* const percent);
#ifdef __cplusplus
}
diff --git a/src/enc/histogram_enc.c b/src/enc/histogram_enc.c
index 38a0ceb..8418def 100644
--- a/src/enc/histogram_enc.c
+++ b/src/enc/histogram_enc.c
@@ -13,15 +13,17 @@
#include "src/webp/config.h"
#endif
+#include <float.h>
#include <math.h>
-#include "src/enc/backward_references_enc.h"
-#include "src/enc/histogram_enc.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
+#include "src/enc/backward_references_enc.h"
+#include "src/enc/histogram_enc.h"
+#include "src/enc/vp8i_enc.h"
#include "src/utils/utils.h"
-#define MAX_COST 1.e38
+#define MAX_BIT_COST FLT_MAX
// Number of partitions for the three dominant (literal, red and blue) symbol
// costs.
@@ -228,8 +230,8 @@
// -----------------------------------------------------------------------------
// Entropy-related functions.
-static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) {
- double mix;
+static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) {
+ float mix;
if (entropy->nonzeros < 5) {
if (entropy->nonzeros <= 1) {
return 0;
@@ -238,67 +240,67 @@
// Let's mix in a bit of entropy to favor good clustering when
// distributions of these are combined.
if (entropy->nonzeros == 2) {
- return 0.99 * entropy->sum + 0.01 * entropy->entropy;
+ return 0.99f * entropy->sum + 0.01f * entropy->entropy;
}
// No matter what the entropy says, we cannot be better than min_limit
// with Huffman coding. I am mixing a bit of entropy into the
// min_limit since it produces much better (~0.5 %) compression results
// perhaps because of better entropy clustering.
if (entropy->nonzeros == 3) {
- mix = 0.95;
+ mix = 0.95f;
} else {
- mix = 0.7; // nonzeros == 4.
+ mix = 0.7f; // nonzeros == 4.
}
} else {
- mix = 0.627;
+ mix = 0.627f;
}
{
- double min_limit = 2 * entropy->sum - entropy->max_val;
- min_limit = mix * min_limit + (1.0 - mix) * entropy->entropy;
+ float min_limit = 2.f * entropy->sum - entropy->max_val;
+ min_limit = mix * min_limit + (1.f - mix) * entropy->entropy;
return (entropy->entropy < min_limit) ? min_limit : entropy->entropy;
}
}
-double VP8LBitsEntropy(const uint32_t* const array, int n) {
+float VP8LBitsEntropy(const uint32_t* const array, int n) {
VP8LBitEntropy entropy;
VP8LBitsEntropyUnrefined(array, n, &entropy);
return BitsEntropyRefine(&entropy);
}
-static double InitialHuffmanCost(void) {
+static float InitialHuffmanCost(void) {
// Small bias because Huffman code length is typically not stored in
// full length.
static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
- static const double kSmallBias = 9.1;
+ static const float kSmallBias = 9.1f;
return kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
}
// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3)
-static double FinalHuffmanCost(const VP8LStreaks* const stats) {
+static float FinalHuffmanCost(const VP8LStreaks* const stats) {
// The constants in this function are experimental and got rounded from
// their original values in 1/8 when switched to 1/1024.
- double retval = InitialHuffmanCost();
+ float retval = InitialHuffmanCost();
// Second coefficient: Many zeros in the histogram are covered efficiently
// by a run-length encode. Originally 2/8.
- retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1];
+ retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1];
// Second coefficient: Constant values are encoded less efficiently, but still
// RLE'ed. Originally 6/8.
- retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1];
+ retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1];
// 0s are usually encoded more efficiently than non-0s.
// Originally 15/8.
- retval += 1.796875 * stats->streaks[0][0];
+ retval += 1.796875f * stats->streaks[0][0];
// Originally 26/8.
- retval += 3.28125 * stats->streaks[1][0];
+ retval += 3.28125f * stats->streaks[1][0];
return retval;
}
// Get the symbol entropy for the distribution 'population'.
// Set 'trivial_sym', if there's only one symbol present in the distribution.
-static double PopulationCost(const uint32_t* const population, int length,
- uint32_t* const trivial_sym,
- uint8_t* const is_used) {
+static float PopulationCost(const uint32_t* const population, int length,
+ uint32_t* const trivial_sym,
+ uint8_t* const is_used) {
VP8LBitEntropy bit_entropy;
VP8LStreaks stats;
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
@@ -314,11 +316,10 @@
// trivial_at_end is 1 if the two histograms only have one element that is
// non-zero: both the zero-th one, or both the last one.
-static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
- const uint32_t* const Y,
- int length, int is_X_used,
- int is_Y_used,
- int trivial_at_end) {
+static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X,
+ const uint32_t* const Y, int length,
+ int is_X_used, int is_Y_used,
+ int trivial_at_end) {
VP8LStreaks stats;
if (trivial_at_end) {
// This configuration is due to palettization that transforms an indexed
@@ -356,7 +357,7 @@
}
// Estimates the Entropy + Huffman + other block overhead size cost.
-double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
+float VP8LHistogramEstimateBits(VP8LHistogram* const p) {
return
PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
NULL, &p->is_used_[0])
@@ -373,8 +374,7 @@
static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
const VP8LHistogram* const b,
- double cost_threshold,
- double* cost) {
+ float cost_threshold, float* cost) {
const int palette_code_bits = a->palette_code_bits_;
int trivial_at_end = 0;
assert(a->palette_code_bits_ == b->palette_code_bits_);
@@ -439,12 +439,11 @@
// Since the previous score passed is 'cost_threshold', we only need to compare
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
// early.
-static double HistogramAddEval(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out,
- double cost_threshold) {
- double cost = 0;
- const double sum_cost = a->bit_cost_ + b->bit_cost_;
+static float HistogramAddEval(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out, float cost_threshold) {
+ float cost = 0;
+ const float sum_cost = a->bit_cost_ + b->bit_cost_;
cost_threshold += sum_cost;
if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) {
@@ -459,10 +458,10 @@
// Same as HistogramAddEval(), except that the resulting histogram
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
// the term C(b) which is constant over all the evaluations.
-static double HistogramAddThresh(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- double cost_threshold) {
- double cost;
+static float HistogramAddThresh(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ float cost_threshold) {
+ float cost;
assert(a != NULL && b != NULL);
cost = -a->bit_cost_;
GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
@@ -473,24 +472,22 @@
// The structure to keep track of cost range for the three dominant entropy
// symbols.
-// TODO(skal): Evaluate if float can be used here instead of double for
-// representing the entropy costs.
typedef struct {
- double literal_max_;
- double literal_min_;
- double red_max_;
- double red_min_;
- double blue_max_;
- double blue_min_;
+ float literal_max_;
+ float literal_min_;
+ float red_max_;
+ float red_min_;
+ float blue_max_;
+ float blue_min_;
} DominantCostRange;
static void DominantCostRangeInit(DominantCostRange* const c) {
c->literal_max_ = 0.;
- c->literal_min_ = MAX_COST;
+ c->literal_min_ = MAX_BIT_COST;
c->red_max_ = 0.;
- c->red_min_ = MAX_COST;
+ c->red_min_ = MAX_BIT_COST;
c->blue_max_ = 0.;
- c->blue_min_ = MAX_COST;
+ c->blue_min_ = MAX_BIT_COST;
}
static void UpdateDominantCostRange(
@@ -505,10 +502,9 @@
static void UpdateHistogramCost(VP8LHistogram* const h) {
uint32_t alpha_sym, red_sym, blue_sym;
- const double alpha_cost =
- PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym,
- &h->is_used_[3]);
- const double distance_cost =
+ const float alpha_cost =
+ PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]);
+ const float distance_cost =
PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
@@ -529,10 +525,10 @@
}
}
-static int GetBinIdForEntropy(double min, double max, double val) {
- const double range = max - min;
+static int GetBinIdForEntropy(float min, float max, float val) {
+ const float range = max - min;
if (range > 0.) {
- const double delta = val - min;
+ const float delta = val - min;
return (int)((NUM_PARTITIONS - 1e-6) * delta / range);
} else {
return 0;
@@ -641,15 +637,11 @@
// Merges some histograms with same bin_id together if it's advantageous.
// Sets the remaining histograms to NULL.
-static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
- int* num_used,
- const uint16_t* const clusters,
- uint16_t* const cluster_mappings,
- VP8LHistogram* cur_combo,
- const uint16_t* const bin_map,
- int num_bins,
- double combine_cost_factor,
- int low_effort) {
+static void HistogramCombineEntropyBin(
+ VP8LHistogramSet* const image_histo, int* num_used,
+ const uint16_t* const clusters, uint16_t* const cluster_mappings,
+ VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins,
+ float combine_cost_factor, int low_effort) {
VP8LHistogram** const histograms = image_histo->histograms;
int idx;
struct {
@@ -679,11 +671,10 @@
cluster_mappings[clusters[idx]] = clusters[first];
} else {
// try to merge #idx into #first (both share the same bin_id)
- const double bit_cost = histograms[idx]->bit_cost_;
- const double bit_cost_thresh = -bit_cost * combine_cost_factor;
- const double curr_cost_diff =
- HistogramAddEval(histograms[first], histograms[idx],
- cur_combo, bit_cost_thresh);
+ const float bit_cost = histograms[idx]->bit_cost_;
+ const float bit_cost_thresh = -bit_cost * combine_cost_factor;
+ const float curr_cost_diff = HistogramAddEval(
+ histograms[first], histograms[idx], cur_combo, bit_cost_thresh);
if (curr_cost_diff < bit_cost_thresh) {
// Try to merge two histograms only if the combo is a trivial one or
// the two candidate histograms are already non-trivial.
@@ -731,8 +722,8 @@
typedef struct {
int idx1;
int idx2;
- double cost_diff;
- double cost_combo;
+ float cost_diff;
+ float cost_combo;
} HistogramPair;
typedef struct {
@@ -787,10 +778,9 @@
// Update the cost diff and combo of a pair of histograms. This needs to be
// called when the the histograms have been merged with a third one.
static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
- const VP8LHistogram* const h2,
- double threshold,
+ const VP8LHistogram* const h2, float threshold,
HistogramPair* const pair) {
- const double sum_cost = h1->bit_cost_ + h2->bit_cost_;
+ const float sum_cost = h1->bit_cost_ + h2->bit_cost_;
pair->cost_combo = 0.;
GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo);
pair->cost_diff = pair->cost_combo - sum_cost;
@@ -799,9 +789,9 @@
// Create a pair from indices "idx1" and "idx2" provided its cost
// is inferior to "threshold", a negative entropy.
// It returns the cost of the pair, or 0. if it superior to threshold.
-static double HistoQueuePush(HistoQueue* const histo_queue,
- VP8LHistogram** const histograms, int idx1,
- int idx2, double threshold) {
+static float HistoQueuePush(HistoQueue* const histo_queue,
+ VP8LHistogram** const histograms, int idx1,
+ int idx2, float threshold) {
const VP8LHistogram* h1;
const VP8LHistogram* h2;
HistogramPair pair;
@@ -945,8 +935,8 @@
++tries_with_no_success < num_tries_no_success;
++iter) {
int* mapping_index;
- double best_cost =
- (histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff;
+ float best_cost =
+ (histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff;
int best_idx1 = -1, best_idx2 = 1;
const uint32_t rand_range = (*num_used - 1) * (*num_used);
// (*num_used) / 2 was chosen empirically. Less means faster but worse
@@ -955,7 +945,7 @@
// Pick random samples.
for (j = 0; *num_used >= 2 && j < num_tries; ++j) {
- double curr_cost;
+ float curr_cost;
// Choose two different histograms at random and try to combine them.
const uint32_t tmp = MyRand(&seed) % rand_range;
uint32_t idx1 = tmp / (*num_used - 1);
@@ -1034,7 +1024,7 @@
*do_greedy = (*num_used <= min_cluster_size);
ok = 1;
-End:
+ End:
HistoQueueClear(&histo_queue);
WebPSafeFree(mappings);
return ok;
@@ -1057,7 +1047,7 @@
if (out_size > 1) {
for (i = 0; i < in_size; ++i) {
int best_out = 0;
- double best_bits = MAX_COST;
+ float best_bits = MAX_BIT_COST;
int k;
if (in_histo[i] == NULL) {
// Arbitrarily set to the previous value if unused to help future LZ77.
@@ -1065,7 +1055,7 @@
continue;
}
for (k = 0; k < out_size; ++k) {
- double cur_bits;
+ float cur_bits;
cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
if (k == 0 || cur_bits < best_bits) {
best_bits = cur_bits;
@@ -1093,13 +1083,13 @@
}
}
-static double GetCombineCostFactor(int histo_size, int quality) {
- double combine_cost_factor = 0.16;
+static float GetCombineCostFactor(int histo_size, int quality) {
+ float combine_cost_factor = 0.16f;
if (quality < 90) {
- if (histo_size > 256) combine_cost_factor /= 2.;
- if (histo_size > 512) combine_cost_factor /= 2.;
- if (histo_size > 1024) combine_cost_factor /= 2.;
- if (quality <= 50) combine_cost_factor /= 2.;
+ if (histo_size > 256) combine_cost_factor /= 2.f;
+ if (histo_size > 512) combine_cost_factor /= 2.f;
+ if (histo_size > 1024) combine_cost_factor /= 2.f;
+ if (quality <= 50) combine_cost_factor /= 2.f;
}
return combine_cost_factor;
}
@@ -1169,13 +1159,13 @@
}
int VP8LGetHistoImageSymbols(int xsize, int ysize,
- const VP8LBackwardRefs* const refs,
- int quality, int low_effort,
- int histogram_bits, int cache_bits,
+ const VP8LBackwardRefs* const refs, int quality,
+ int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
- uint16_t* const histogram_symbols) {
- int ok = 0;
+ uint16_t* const histogram_symbols,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int histo_xsize =
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
const int histo_ysize =
@@ -1192,7 +1182,10 @@
WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
int num_used = image_histo_raw_size;
- if (orig_histo == NULL || map_tmp == NULL) goto Error;
+ if (orig_histo == NULL || map_tmp == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
// Construct the histograms from backward references.
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
@@ -1206,16 +1199,15 @@
if (entropy_combine) {
uint16_t* const bin_map = map_tmp;
- const double combine_cost_factor =
+ const float combine_cost_factor =
GetCombineCostFactor(image_histo_raw_size, quality);
const uint32_t num_clusters = num_used;
HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
// Collapse histograms with similar entropy.
- HistogramCombineEntropyBin(image_histo, &num_used, histogram_symbols,
- cluster_mappings, tmp_histo, bin_map,
- entropy_combine_num_bins, combine_cost_factor,
- low_effort);
+ HistogramCombineEntropyBin(
+ image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo,
+ bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort);
OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters,
map_tmp, histogram_symbols);
}
@@ -1229,11 +1221,13 @@
int do_greedy;
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
&do_greedy)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
if (do_greedy) {
RemoveEmptyHistograms(image_histo);
if (!HistogramCombineGreedy(image_histo, &num_used)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
}
@@ -1243,10 +1237,12 @@
RemoveEmptyHistograms(image_histo);
HistogramRemap(orig_histo, image_histo, histogram_symbols);
- ok = 1;
+ if (!WebPReportProgress(pic, *percent + percent_range, percent)) {
+ goto Error;
+ }
Error:
VP8LFreeHistogramSet(orig_histo);
WebPSafeFree(map_tmp);
- return ok;
+ return (pic->error_code == VP8_ENC_OK);
}
diff --git a/src/enc/histogram_enc.h b/src/enc/histogram_enc.h
index c3428b5..4c0bb97 100644
--- a/src/enc/histogram_enc.h
+++ b/src/enc/histogram_enc.h
@@ -40,10 +40,10 @@
int palette_code_bits_;
uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha
// literal symbols are single valued.
- double bit_cost_; // cached value of bit cost.
- double literal_cost_; // Cached values of dominant entropy costs:
- double red_cost_; // literal, red & blue.
- double blue_cost_;
+ float bit_cost_; // cached value of bit cost.
+ float literal_cost_; // Cached values of dominant entropy costs:
+ float red_cost_; // literal, red & blue.
+ float blue_cost_;
uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram;
@@ -105,21 +105,23 @@
((palette_code_bits > 0) ? (1 << palette_code_bits) : 0);
}
-// Builds the histogram image.
+// Builds the histogram image. pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
int VP8LGetHistoImageSymbols(int xsize, int ysize,
- const VP8LBackwardRefs* const refs,
- int quality, int low_effort,
- int histogram_bits, int cache_bits,
+ const VP8LBackwardRefs* const refs, int quality,
+ int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
- uint16_t* const histogram_symbols);
+ uint16_t* const histogram_symbols,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent);
// Returns the entropy for the symbols in the input array.
-double VP8LBitsEntropy(const uint32_t* const array, int n);
+float VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
-double VP8LHistogramEstimateBits(VP8LHistogram* const p);
+float VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus
}
diff --git a/src/enc/picture_csp_enc.c b/src/enc/picture_csp_enc.c
index 35eede9..78c8ca4 100644
--- a/src/enc/picture_csp_enc.c
+++ b/src/enc/picture_csp_enc.c
@@ -15,12 +15,19 @@
#include <stdlib.h>
#include <math.h>
+#include "sharpyuv/sharpyuv.h"
+#include "sharpyuv/sharpyuv_csp.h"
#include "src/enc/vp8i_enc.h"
#include "src/utils/random_utils.h"
#include "src/utils/utils.h"
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/yuv.h"
+#include "src/dsp/cpu.h"
+
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h>
+#endif
// Uncomment to disable gamma-compression during RGB->U/V averaging
#define USE_GAMMA_COMPRESSION
@@ -62,10 +69,12 @@
int WebPPictureHasTransparency(const WebPPicture* picture) {
if (picture == NULL) return 0;
if (picture->use_argb) {
- const int alpha_offset = ALPHA_OFFSET;
- return CheckNonOpaque((const uint8_t*)picture->argb + alpha_offset,
- picture->width, picture->height,
- 4, picture->argb_stride * sizeof(*picture->argb));
+ if (picture->argb != NULL) {
+ return CheckNonOpaque((const uint8_t*)picture->argb + ALPHA_OFFSET,
+ picture->width, picture->height,
+ 4, picture->argb_stride * sizeof(*picture->argb));
+ }
+ return 0;
}
return CheckNonOpaque(picture->a, picture->width, picture->height,
1, picture->a_stride);
@@ -76,16 +85,16 @@
#if defined(USE_GAMMA_COMPRESSION)
-// gamma-compensates loss of resolution during chroma subsampling
-#define kGamma 0.80 // for now we use a different gamma value than kGammaF
-#define kGammaFix 12 // fixed-point precision for linear values
-#define kGammaScale ((1 << kGammaFix) - 1)
-#define kGammaTabFix 7 // fixed-point fractional bits precision
-#define kGammaTabScale (1 << kGammaTabFix)
-#define kGammaTabRounder (kGammaTabScale >> 1)
-#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
+// Gamma correction compensates loss of resolution during chroma subsampling.
+#define GAMMA_FIX 12 // fixed-point precision for linear values
+#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision
+#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX))
+static const double kGamma = 0.80;
+static const int kGammaScale = ((1 << GAMMA_FIX) - 1);
+static const int kGammaTabScale = (1 << GAMMA_TAB_FIX);
+static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1);
-static int kLinearToGammaTab[kGammaTabSize + 1];
+static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1];
static uint16_t kGammaToLinearTab[256];
static volatile int kGammaTablesOk = 0;
static void InitGammaTables(void);
@@ -93,13 +102,13 @@
WEBP_DSP_INIT_FUNC(InitGammaTables) {
if (!kGammaTablesOk) {
int v;
- const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
+ const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale;
const double norm = 1. / 255.;
for (v = 0; v <= 255; ++v) {
kGammaToLinearTab[v] =
(uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
}
- for (v = 0; v <= kGammaTabSize; ++v) {
+ for (v = 0; v <= GAMMA_TAB_SIZE; ++v) {
kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
}
kGammaTablesOk = 1;
@@ -111,12 +120,12 @@
}
static WEBP_INLINE int Interpolate(int v) {
- const int tab_pos = v >> (kGammaTabFix + 2); // integer part
+ const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part
const int x = v & ((kGammaTabScale << 2) - 1); // fractional part
const int v0 = kLinearToGammaTab[tab_pos];
const int v1 = kLinearToGammaTab[tab_pos + 1];
const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate
- assert(tab_pos + 1 < kGammaTabSize + 1);
+ assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1);
return y;
}
@@ -124,7 +133,7 @@
// U/V value, suitable for RGBToU/V calls.
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
const int y = Interpolate(base_value << shift); // final uplifted value
- return (y + kGammaTabRounder) >> kGammaTabFix; // descale
+ return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale
}
#else
@@ -158,415 +167,26 @@
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
-static const int kNumIterations = 4;
static const int kMinDimensionIterativeConversion = 4;
-// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
-// banding sometimes. Better use extra precision.
-#define SFIX 2 // fixed-point precision of RGB and Y/W
-typedef int16_t fixed_t; // signed type with extra SFIX precision for UV
-typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
-
-#define SHALF (1 << SFIX >> 1)
-#define MAX_Y_T ((256 << SFIX) - 1)
-#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
-
-#if defined(USE_GAMMA_COMPRESSION)
-
-// We use tables of different size and precision for the Rec709 / BT2020
-// transfer function.
-#define kGammaF (1./0.45)
-static uint32_t kLinearToGammaTabS[kGammaTabSize + 2];
-#define GAMMA_TO_LINEAR_BITS 14
-static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX
-static volatile int kGammaTablesSOk = 0;
-static void InitGammaTablesS(void);
-
-WEBP_DSP_INIT_FUNC(InitGammaTablesS) {
- assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values
- if (!kGammaTablesSOk) {
- int v;
- const double norm = 1. / MAX_Y_T;
- const double scale = 1. / kGammaTabSize;
- const double a = 0.09929682680944;
- const double thresh = 0.018053968510807;
- const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
- for (v = 0; v <= MAX_Y_T; ++v) {
- const double g = norm * v;
- double value;
- if (g <= thresh * 4.5) {
- value = g / 4.5;
- } else {
- const double a_rec = 1. / (1. + a);
- value = pow(a_rec * (g + a), kGammaF);
- }
- kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
- }
- for (v = 0; v <= kGammaTabSize; ++v) {
- const double g = scale * v;
- double value;
- if (g <= thresh) {
- value = 4.5 * g;
- } else {
- value = (1. + a) * pow(g, 1. / kGammaF) - a;
- }
- // we already incorporate the 1/2 rounding constant here
- kLinearToGammaTabS[v] =
- (uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1);
- }
- // to prevent small rounding errors to cause read-overflow:
- kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize];
- kGammaTablesSOk = 1;
- }
-}
-
-// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS
-static WEBP_INLINE uint32_t GammaToLinearS(int v) {
- return kGammaToLinearTabS[v];
-}
-
-static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
- // 'value' is in GAMMA_TO_LINEAR_BITS fractional precision
- const uint32_t v = value * kGammaTabSize;
- const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS;
- // fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision
- const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS); // fractional part
- // v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1])
- const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0];
- const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1];
- // Final interpolation. Note that rounding is already included.
- const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
- const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS);
- return result;
-}
-
-#else
-
-static void InitGammaTablesS(void) {}
-static WEBP_INLINE uint32_t GammaToLinearS(int v) {
- return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T;
-}
-static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
- return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS;
-}
-
-#endif // USE_GAMMA_COMPRESSION
-
-//------------------------------------------------------------------------------
-
-static uint8_t clip_8b(fixed_t v) {
- return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
-}
-
-static fixed_y_t clip_y(int y) {
- return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
-}
-
-//------------------------------------------------------------------------------
-
-static int RGBToGray(int r, int g, int b) {
- const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
- return (luma >> YUV_FIX);
-}
-
-static uint32_t ScaleDown(int a, int b, int c, int d) {
- const uint32_t A = GammaToLinearS(a);
- const uint32_t B = GammaToLinearS(b);
- const uint32_t C = GammaToLinearS(c);
- const uint32_t D = GammaToLinearS(d);
- return LinearToGammaS((A + B + C + D + 2) >> 2);
-}
-
-static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t R = GammaToLinearS(src[0 * w + i]);
- const uint32_t G = GammaToLinearS(src[1 * w + i]);
- const uint32_t B = GammaToLinearS(src[2 * w + i]);
- const uint32_t Y = RGBToGray(R, G, B);
- dst[i] = (fixed_y_t)LinearToGammaS(Y);
- }
-}
-
-static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
- fixed_t* dst, int uv_w) {
- int i;
- for (i = 0; i < uv_w; ++i) {
- const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
- src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
- const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
- src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
- const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
- src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
- const int W = RGBToGray(r, g, b);
- dst[0 * uv_w] = (fixed_t)(r - W);
- dst[1 * uv_w] = (fixed_t)(g - W);
- dst[2 * uv_w] = (fixed_t)(b - W);
- dst += 1;
- src1 += 2;
- src2 += 2;
- }
-}
-
-static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
- int i;
- for (i = 0; i < w; ++i) {
- y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
- }
-}
-
-//------------------------------------------------------------------------------
-
-static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
- const int v0 = (A * 3 + B + 2) >> 2;
- return clip_y(v0 + W0);
-}
-
-//------------------------------------------------------------------------------
-
-static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
- return ((fixed_y_t)a << SFIX) | SHALF;
-}
-
-static void ImportOneRow(const uint8_t* const r_ptr,
- const uint8_t* const g_ptr,
- const uint8_t* const b_ptr,
- int step,
- int pic_width,
- fixed_y_t* const dst) {
- int i;
- const int w = (pic_width + 1) & ~1;
- for (i = 0; i < pic_width; ++i) {
- const int off = i * step;
- dst[i + 0 * w] = UpLift(r_ptr[off]);
- dst[i + 1 * w] = UpLift(g_ptr[off]);
- dst[i + 2 * w] = UpLift(b_ptr[off]);
- }
- if (pic_width & 1) { // replicate rightmost pixel
- dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
- dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
- dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
- }
-}
-
-static void InterpolateTwoRows(const fixed_y_t* const best_y,
- const fixed_t* prev_uv,
- const fixed_t* cur_uv,
- const fixed_t* next_uv,
- int w,
- fixed_y_t* out1,
- fixed_y_t* out2) {
- const int uv_w = w >> 1;
- const int len = (w - 1) >> 1; // length to filter
- int k = 3;
- while (k-- > 0) { // process each R/G/B segments in turn
- // special boundary case for i==0
- out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
- out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
-
- WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
- WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
-
- // special boundary case for i == w - 1 when w is even
- if (!(w & 1)) {
- out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
- best_y[w - 1 + 0]);
- out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
- best_y[w - 1 + w]);
- }
- out1 += w;
- out2 += w;
- prev_uv += uv_w;
- cur_uv += uv_w;
- next_uv += uv_w;
- }
-}
-
-static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
- const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
- return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
-}
-
-static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
- const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
- return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
-}
-
-static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
- const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER;
- return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
-}
-
-static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
- WebPPicture* const picture) {
- int i, j;
- uint8_t* dst_y = picture->y;
- uint8_t* dst_u = picture->u;
- uint8_t* dst_v = picture->v;
- const fixed_t* const best_uv_base = best_uv;
- const int w = (picture->width + 1) & ~1;
- const int h = (picture->height + 1) & ~1;
- const int uv_w = w >> 1;
- const int uv_h = h >> 1;
- for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
- for (i = 0; i < picture->width; ++i) {
- const int off = (i >> 1);
- const int W = best_y[i];
- const int r = best_uv[off + 0 * uv_w] + W;
- const int g = best_uv[off + 1 * uv_w] + W;
- const int b = best_uv[off + 2 * uv_w] + W;
- dst_y[i] = ConvertRGBToY(r, g, b);
- }
- best_y += w;
- best_uv += (j & 1) * 3 * uv_w;
- dst_y += picture->y_stride;
- }
- for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
- for (i = 0; i < uv_w; ++i) {
- const int off = i;
- const int r = best_uv[off + 0 * uv_w];
- const int g = best_uv[off + 1 * uv_w];
- const int b = best_uv[off + 2 * uv_w];
- dst_u[i] = ConvertRGBToU(r, g, b);
- dst_v[i] = ConvertRGBToV(r, g, b);
- }
- best_uv += 3 * uv_w;
- dst_u += picture->uv_stride;
- dst_v += picture->uv_stride;
- }
- return 1;
-}
-
//------------------------------------------------------------------------------
// Main function
-#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
-
static int PreprocessARGB(const uint8_t* r_ptr,
const uint8_t* g_ptr,
const uint8_t* b_ptr,
int step, int rgb_stride,
WebPPicture* const picture) {
- // we expand the right/bottom border if needed
- const int w = (picture->width + 1) & ~1;
- const int h = (picture->height + 1) & ~1;
- const int uv_w = w >> 1;
- const int uv_h = h >> 1;
- uint64_t prev_diff_y_sum = ~0;
- int j, iter;
-
- // TODO(skal): allocate one big memory chunk. But for now, it's easier
- // for valgrind debugging to have several chunks.
- fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
- fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
- fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
- fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
- fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
- fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
- fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
- fixed_y_t* best_y = best_y_base;
- fixed_y_t* target_y = target_y_base;
- fixed_t* best_uv = best_uv_base;
- fixed_t* target_uv = target_uv_base;
- const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
- int ok;
-
- if (best_y_base == NULL || best_uv_base == NULL ||
- target_y_base == NULL || target_uv_base == NULL ||
- best_rgb_y == NULL || best_rgb_uv == NULL ||
- tmp_buffer == NULL) {
- ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
- goto End;
+ const int ok = SharpYuvConvert(
+ r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8,
+ picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v,
+ picture->uv_stride, /*yuv_bit_depth=*/8, picture->width,
+ picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp));
+ if (!ok) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
- assert(picture->width >= kMinDimensionIterativeConversion);
- assert(picture->height >= kMinDimensionIterativeConversion);
-
- WebPInitConvertARGBToYUV();
-
- // Import RGB samples to W/RGB representation.
- for (j = 0; j < picture->height; j += 2) {
- const int is_last_row = (j == picture->height - 1);
- fixed_y_t* const src1 = tmp_buffer + 0 * w;
- fixed_y_t* const src2 = tmp_buffer + 3 * w;
-
- // prepare two rows of input
- ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
- if (!is_last_row) {
- ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
- step, picture->width, src2);
- } else {
- memcpy(src2, src1, 3 * w * sizeof(*src2));
- }
- StoreGray(src1, best_y + 0, w);
- StoreGray(src2, best_y + w, w);
-
- UpdateW(src1, target_y, w);
- UpdateW(src2, target_y + w, w);
- UpdateChroma(src1, src2, target_uv, uv_w);
- memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
- best_y += 2 * w;
- best_uv += 3 * uv_w;
- target_y += 2 * w;
- target_uv += 3 * uv_w;
- r_ptr += 2 * rgb_stride;
- g_ptr += 2 * rgb_stride;
- b_ptr += 2 * rgb_stride;
- }
-
- // Iterate and resolve clipping conflicts.
- for (iter = 0; iter < kNumIterations; ++iter) {
- const fixed_t* cur_uv = best_uv_base;
- const fixed_t* prev_uv = best_uv_base;
- uint64_t diff_y_sum = 0;
-
- best_y = best_y_base;
- best_uv = best_uv_base;
- target_y = target_y_base;
- target_uv = target_uv_base;
- for (j = 0; j < h; j += 2) {
- fixed_y_t* const src1 = tmp_buffer + 0 * w;
- fixed_y_t* const src2 = tmp_buffer + 3 * w;
- {
- const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
- InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
- prev_uv = cur_uv;
- cur_uv = next_uv;
- }
-
- UpdateW(src1, best_rgb_y + 0 * w, w);
- UpdateW(src2, best_rgb_y + 1 * w, w);
- UpdateChroma(src1, src2, best_rgb_uv, uv_w);
-
- // update two rows of Y and one row of RGB
- diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
- WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
-
- best_y += 2 * w;
- best_uv += 3 * uv_w;
- target_y += 2 * w;
- target_uv += 3 * uv_w;
- }
- // test exit condition
- if (iter > 0) {
- if (diff_y_sum < diff_y_threshold) break;
- if (diff_y_sum > prev_diff_y_sum) break;
- }
- prev_diff_y_sum = diff_y_sum;
- }
- // final reconstruction
- ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
-
- End:
- WebPSafeFree(best_y_base);
- WebPSafeFree(best_uv_base);
- WebPSafeFree(target_y_base);
- WebPSafeFree(target_uv_base);
- WebPSafeFree(best_rgb_y);
- WebPSafeFree(best_rgb_uv);
- WebPSafeFree(tmp_buffer);
return ok;
}
-#undef SAFE_ALLOC
//------------------------------------------------------------------------------
// "Fast" regular RGB->YUV
@@ -591,8 +211,8 @@
// and constant are adjusted very tightly to fit 32b arithmetic.
// In particular, they use the fact that the operands for 'v / a' are actually
// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
-// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
-// overflow is: kGammaFix + kAlphaFix <= 31.
+// with ai in [0..255] and pi in [0..1<<GAMMA_FIX). The constraint to avoid
+// overflow is: GAMMA_FIX + kAlphaFix <= 31.
static const uint32_t kInvAlpha[4 * 0xff + 1] = {
0, /* alpha = 0 */
524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
@@ -818,11 +438,20 @@
dst[0] = SUM4(r_ptr + j, step);
dst[1] = SUM4(g_ptr + j, step);
dst[2] = SUM4(b_ptr + j, step);
+ // MemorySanitizer may raise false positives with data that passes through
+ // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles.
+ // See https://crbug.com/webp/573.
+#ifdef WEBP_MSAN
+ dst[3] = 0;
+#endif
}
if (width & 1) {
dst[0] = SUM2(r_ptr + j);
dst[1] = SUM2(g_ptr + j);
dst[2] = SUM2(b_ptr + j);
+#ifdef WEBP_MSAN
+ dst[3] = 0;
+#endif
}
}
@@ -839,6 +468,8 @@
}
}
+extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
+
static int ImportYUVAFromRGBA(const uint8_t* r_ptr,
const uint8_t* g_ptr,
const uint8_t* b_ptr,
@@ -863,18 +494,18 @@
use_iterative_conversion = 0;
}
- if (!WebPPictureAllocYUVA(picture, width, height)) {
+ if (!WebPPictureAllocYUVA(picture)) {
return 0;
}
if (has_alpha) {
assert(step == 4);
#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
- assert(kAlphaFix + kGammaFix <= 31);
+ assert(kAlphaFix + GAMMA_FIX <= 31);
#endif
}
if (use_iterative_conversion) {
- InitGammaTablesS();
+ SharpYuvInit(VP8GetCPUInfo);
if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
return 0;
}
@@ -1044,7 +675,7 @@
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
// Allocate a new argb buffer (discarding the previous one).
- if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
+ if (!WebPPictureAllocARGB(picture)) return 0;
picture->use_argb = 1;
// Convert
@@ -1106,6 +737,8 @@
const int width = picture->width;
const int height = picture->height;
+ if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0;
+
if (!picture->use_argb) {
const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
@@ -1163,24 +796,24 @@
#if !defined(WEBP_REDUCE_CSP)
int WebPPictureImportBGR(WebPPicture* picture,
- const uint8_t* rgb, int rgb_stride) {
- return (picture != NULL && rgb != NULL)
- ? Import(picture, rgb, rgb_stride, 3, 1, 0)
+ const uint8_t* bgr, int bgr_stride) {
+ return (picture != NULL && bgr != NULL)
+ ? Import(picture, bgr, bgr_stride, 3, 1, 0)
: 0;
}
int WebPPictureImportBGRA(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 1, 1)
+ const uint8_t* bgra, int bgra_stride) {
+ return (picture != NULL && bgra != NULL)
+ ? Import(picture, bgra, bgra_stride, 4, 1, 1)
: 0;
}
int WebPPictureImportBGRX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 1, 0)
+ const uint8_t* bgrx, int bgrx_stride) {
+ return (picture != NULL && bgrx != NULL)
+ ? Import(picture, bgrx, bgrx_stride, 4, 1, 0)
: 0;
}
@@ -1201,9 +834,9 @@
}
int WebPPictureImportRGBX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 0, 0)
+ const uint8_t* rgbx, int rgbx_stride) {
+ return (picture != NULL && rgbx != NULL)
+ ? Import(picture, rgbx, rgbx_stride, 4, 0, 0)
: 0;
}
diff --git a/src/enc/picture_enc.c b/src/enc/picture_enc.c
index c691622..3af6383 100644
--- a/src/enc/picture_enc.c
+++ b/src/enc/picture_enc.c
@@ -45,6 +45,22 @@
//------------------------------------------------------------------------------
+int WebPValidatePicture(const WebPPicture* const picture) {
+ if (picture == NULL) return 0;
+ if (picture->width <= 0 || picture->height <= 0) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
+ }
+ if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||
+ picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
+ }
+ if (picture->colorspace != WEBP_YUV420 &&
+ picture->colorspace != WEBP_YUV420A) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ }
+ return 1;
+}
+
static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
picture->memory_argb_ = NULL;
picture->argb = NULL;
@@ -63,18 +79,17 @@
WebPPictureResetBufferYUVA(picture);
}
-int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
+int WebPPictureAllocARGB(WebPPicture* const picture) {
void* memory;
+ const int width = picture->width;
+ const int height = picture->height;
const uint64_t argb_size = (uint64_t)width * height;
- assert(picture != NULL);
+ if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_argb_);
WebPPictureResetBufferARGB(picture);
- if (width <= 0 || height <= 0) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
- }
// allocate a new buffer.
memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));
if (memory == NULL) {
@@ -86,10 +101,10 @@
return 1;
}
-int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
- const WebPEncCSP uv_csp =
- (WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK);
+int WebPPictureAllocYUVA(WebPPicture* const picture) {
const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ const int width = picture->width;
+ const int height = picture->height;
const int y_stride = width;
const int uv_width = (int)(((int64_t)width + 1) >> 1);
const int uv_height = (int)(((int64_t)height + 1) >> 1);
@@ -98,15 +113,11 @@
uint64_t y_size, uv_size, a_size, total_size;
uint8_t* mem;
- assert(picture != NULL);
+ if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_);
WebPPictureResetBufferYUVA(picture);
- if (uv_csp != WEBP_YUV420) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
- }
-
// alpha
a_width = has_alpha ? width : 0;
a_stride = a_width;
@@ -152,15 +163,12 @@
int WebPPictureAlloc(WebPPicture* picture) {
if (picture != NULL) {
- const int width = picture->width;
- const int height = picture->height;
-
WebPPictureFree(picture); // erase previous buffer
if (!picture->use_argb) {
- return WebPPictureAllocYUVA(picture, width, height);
+ return WebPPictureAllocYUVA(picture);
} else {
- return WebPPictureAllocARGB(picture, width, height);
+ return WebPPictureAllocARGB(picture);
}
}
return 1;
diff --git a/src/enc/picture_rescale_enc.c b/src/enc/picture_rescale_enc.c
index a75f5d9..839f91c 100644
--- a/src/enc/picture_rescale_enc.c
+++ b/src/enc/picture_rescale_enc.c
@@ -13,14 +13,15 @@
#include "src/webp/encode.h"
-#if !defined(WEBP_REDUCE_SIZE)
-
#include <assert.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
+
+#if !defined(WEBP_REDUCE_SIZE)
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
+#endif // !defined(WEBP_REDUCE_SIZE)
#define HALVE(x) (((x) + 1) >> 1)
@@ -56,6 +57,7 @@
return 1;
}
+#if !defined(WEBP_REDUCE_SIZE)
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
if (src == NULL || dst == NULL) return 0;
if (src == dst) return 1;
@@ -81,6 +83,7 @@
}
return 1;
}
+#endif // !defined(WEBP_REDUCE_SIZE)
int WebPPictureIsView(const WebPPicture* picture) {
if (picture == NULL) return 0;
@@ -120,6 +123,7 @@
return 1;
}
+#if !defined(WEBP_REDUCE_SIZE)
//------------------------------------------------------------------------------
// Picture cropping
@@ -198,34 +202,34 @@
}
}
-int WebPPictureRescale(WebPPicture* pic, int width, int height) {
+int WebPPictureRescale(WebPPicture* picture, int width, int height) {
WebPPicture tmp;
int prev_width, prev_height;
rescaler_t* work;
- if (pic == NULL) return 0;
- prev_width = pic->width;
- prev_height = pic->height;
+ if (picture == NULL) return 0;
+ prev_width = picture->width;
+ prev_height = picture->height;
if (!WebPRescalerGetScaledDimensions(
prev_width, prev_height, &width, &height)) {
return 0;
}
- PictureGrabSpecs(pic, &tmp);
+ PictureGrabSpecs(picture, &tmp);
tmp.width = width;
tmp.height = height;
if (!WebPPictureAlloc(&tmp)) return 0;
- if (!pic->use_argb) {
+ if (!picture->use_argb) {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
return 0;
}
// If present, we need to rescale alpha first (for AlphaMultiplyY).
- if (pic->a != NULL) {
+ if (picture->a != NULL) {
WebPInitAlphaProcessing();
- if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
+ if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
return 0;
}
@@ -233,17 +237,15 @@
// We take transparency into account on the luma plane only. That's not
// totally exact blending, but still is a good approximation.
- AlphaMultiplyY(pic, 0);
- if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
+ AlphaMultiplyY(picture, 0);
+ if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1) ||
- !RescalePlane(pic->u,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.u,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
- !RescalePlane(pic->v,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.v,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
+ !RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height),
+ picture->uv_stride, tmp.u, HALVE(width), HALVE(height),
+ tmp.uv_stride, work, 1) ||
+ !RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
+ picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
+ tmp.uv_stride, work, 1)) {
return 0;
}
AlphaMultiplyY(&tmp, 1);
@@ -257,18 +259,17 @@
// weighting first (black-matting), scale the RGB values, and remove
// the premultiplication afterward (while preserving the alpha channel).
WebPInitAlphaProcessing();
- AlphaMultiplyARGB(pic, 0);
- if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
- pic->argb_stride * 4,
- (uint8_t*)tmp.argb, width, height,
- tmp.argb_stride * 4, work, 4)) {
+ AlphaMultiplyARGB(picture, 0);
+ if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
+ picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
+ height, tmp.argb_stride * 4, work, 4)) {
return 0;
}
AlphaMultiplyARGB(&tmp, 1);
}
- WebPPictureFree(pic);
+ WebPPictureFree(picture);
WebPSafeFree(work);
- *pic = tmp;
+ *picture = tmp;
return 1;
}
@@ -280,23 +281,6 @@
return 0;
}
-int WebPPictureIsView(const WebPPicture* picture) {
- (void)picture;
- return 0;
-}
-
-int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst) {
- (void)src;
- (void)left;
- (void)top;
- (void)width;
- (void)height;
- (void)dst;
- return 0;
-}
-
int WebPPictureCrop(WebPPicture* pic,
int left, int top, int width, int height) {
(void)pic;
diff --git a/src/enc/picture_tools_enc.c b/src/enc/picture_tools_enc.c
index 38cb015..147cc18 100644
--- a/src/enc/picture_tools_enc.c
+++ b/src/enc/picture_tools_enc.c
@@ -190,27 +190,28 @@
return (0xff000000u | (r << 16) | (g << 8) | b);
}
-void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
+void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) {
const int red = (background_rgb >> 16) & 0xff;
const int green = (background_rgb >> 8) & 0xff;
const int blue = (background_rgb >> 0) & 0xff;
int x, y;
- if (pic == NULL) return;
- if (!pic->use_argb) {
- const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop
+ if (picture == NULL) return;
+ if (!picture->use_argb) {
+ // omit last pixel during u/v loop
+ const int uv_width = (picture->width >> 1);
const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF);
// VP8RGBToU/V expects the u/v values summed over four pixels
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
- const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
- uint8_t* y_ptr = pic->y;
- uint8_t* u_ptr = pic->u;
- uint8_t* v_ptr = pic->v;
- uint8_t* a_ptr = pic->a;
+ const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ uint8_t* y_ptr = picture->y;
+ uint8_t* u_ptr = picture->u;
+ uint8_t* v_ptr = picture->v;
+ uint8_t* a_ptr = picture->a;
if (!has_alpha || a_ptr == NULL) return; // nothing to do
- for (y = 0; y < pic->height; ++y) {
+ for (y = 0; y < picture->height; ++y) {
// Luma blending
- for (x = 0; x < pic->width; ++x) {
+ for (x = 0; x < picture->width; ++x) {
const uint8_t alpha = a_ptr[x];
if (alpha < 0xff) {
y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
@@ -219,7 +220,7 @@
// Chroma blending every even line
if ((y & 1) == 0) {
uint8_t* const a_ptr2 =
- (y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
+ (y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride;
for (x = 0; x < uv_width; ++x) {
// Average four alpha values into a single blending weight.
// TODO(skal): might lead to visible contouring. Can we do better?
@@ -229,24 +230,24 @@
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
- if (pic->width & 1) { // rightmost pixel
+ if (picture->width & 1) { // rightmost pixel
const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
} else {
- u_ptr += pic->uv_stride;
- v_ptr += pic->uv_stride;
+ u_ptr += picture->uv_stride;
+ v_ptr += picture->uv_stride;
}
- memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
- a_ptr += pic->a_stride;
- y_ptr += pic->y_stride;
+ memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque
+ a_ptr += picture->a_stride;
+ y_ptr += picture->y_stride;
}
} else {
- uint32_t* argb = pic->argb;
+ uint32_t* argb = picture->argb;
const uint32_t background = MakeARGB32(red, green, blue);
- for (y = 0; y < pic->height; ++y) {
- for (x = 0; x < pic->width; ++x) {
+ for (y = 0; y < picture->height; ++y) {
+ for (x = 0; x < picture->width; ++x) {
const int alpha = (argb[x] >> 24) & 0xff;
if (alpha != 0xff) {
if (alpha > 0) {
@@ -262,7 +263,7 @@
}
}
}
- argb += pic->argb_stride;
+ argb += picture->argb_stride;
}
}
}
diff --git a/src/enc/predictor_enc.c b/src/enc/predictor_enc.c
index 2b5c767..b3d44b5 100644
--- a/src/enc/predictor_enc.c
+++ b/src/enc/predictor_enc.c
@@ -16,6 +16,7 @@
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
+#include "src/enc/vp8i_enc.h"
#include "src/enc/vp8li_enc.h"
#define MAX_DIFF_COST (1e30f)
@@ -31,10 +32,10 @@
// Methods to calculate Entropy (Shannon).
static float PredictionCostSpatial(const int counts[256], int weight_0,
- double exp_val) {
+ float exp_val) {
const int significant_symbols = 256 >> 4;
- const double exp_decay_factor = 0.6;
- double bits = weight_0 * counts[0];
+ const float exp_decay_factor = 0.6f;
+ float bits = (float)weight_0 * counts[0];
int i;
for (i = 1; i < significant_symbols; ++i) {
bits += exp_val * (counts[i] + counts[256 - i]);
@@ -46,9 +47,9 @@
static float PredictionCostSpatialHistogram(const int accumulated[4][256],
const int tile[4][256]) {
int i;
- double retval = 0;
+ float retval = 0.f;
for (i = 0; i < 4; ++i) {
- const double kExpValue = 0.94;
+ const float kExpValue = 0.94f;
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]);
}
@@ -472,12 +473,15 @@
// with respect to predictions. If near_lossless_quality < 100, applies
// near lossless processing, shaving off more bits of residuals for lower
// qualities.
-void VP8LResidualImage(int width, int height, int bits, int low_effort,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image, int near_lossless_quality,
- int exact, int used_subtract_green) {
+int VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image, int near_lossless_quality,
+ int exact, int used_subtract_green,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int tiles_per_row = VP8LSubSampleSize(width, bits);
const int tiles_per_col = VP8LSubSampleSize(height, bits);
+ int percent_start = *percent;
int tile_y;
int histo[4][256];
const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality);
@@ -491,17 +495,24 @@
for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
int tile_x;
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
- const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
- bits, histo, argb_scratch, argb, max_quantization, exact,
- used_subtract_green, image);
+ const int pred = GetBestPredictorForTile(
+ width, height, tile_x, tile_y, bits, histo, argb_scratch, argb,
+ max_quantization, exact, used_subtract_green, image);
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
}
+
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * tile_y / tiles_per_col,
+ percent)) {
+ return 0;
+ }
}
}
CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb,
low_effort, max_quantization, exact,
used_subtract_green);
+ return WebPReportProgress(pic, percent_start + percent_range, percent);
}
//------------------------------------------------------------------------------
@@ -532,7 +543,7 @@
const int counts[256]) {
// Favor low entropy, locally and globally.
// Favor small absolute values for PredictionCostSpatial
- static const double kExpValue = 2.4;
+ static const float kExpValue = 2.4f;
return VP8LCombinedShannonEntropy(counts, accumulated) +
PredictionCostSpatial(counts, 3, kExpValue);
}
@@ -714,11 +725,14 @@
}
}
-void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
- uint32_t* const argb, uint32_t* image) {
+int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int max_tile_size = 1 << bits;
const int tile_xsize = VP8LSubSampleSize(width, bits);
const int tile_ysize = VP8LSubSampleSize(height, bits);
+ int percent_start = *percent;
int accumulated_red_histo[256] = { 0 };
int accumulated_blue_histo[256] = { 0 };
int tile_x, tile_y;
@@ -768,5 +782,11 @@
}
}
}
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * tile_y / tile_ysize,
+ percent)) {
+ return 0;
+ }
}
+ return 1;
}
diff --git a/src/enc/quant_enc.c b/src/enc/quant_enc.c
index 6cede28..6d8202d 100644
--- a/src/enc/quant_enc.c
+++ b/src/enc/quant_enc.c
@@ -533,7 +533,8 @@
rd->score = MAX_COST;
}
-static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst,
+ const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D = src->D;
dst->SD = src->SD;
dst->R = src->R;
@@ -542,7 +543,8 @@
dst->score = src->score;
}
-static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst,
+ const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D += src->D;
dst->SD += src->SD;
dst->R += src->R;
@@ -588,10 +590,10 @@
// Coefficient type.
enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 };
-static int TrellisQuantizeBlock(const VP8Encoder* const enc,
+static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
int16_t in[16], int16_t out[16],
int ctx0, int coeff_type,
- const VP8Matrix* const mtx,
+ const VP8Matrix* WEBP_RESTRICT const mtx,
int lambda) {
const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type];
CostArrayPtr const costs =
@@ -767,9 +769,9 @@
// all at once. Output is the reconstructed block in *yuv_out, and the
// quantized levels in *levels.
-static int ReconstructIntra16(VP8EncIterator* const it,
- VP8ModeScore* const rd,
- uint8_t* const yuv_out,
+static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
+ uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
@@ -819,10 +821,10 @@
return nz;
}
-static int ReconstructIntra4(VP8EncIterator* const it,
+static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it,
int16_t levels[16],
- const uint8_t* const src,
- uint8_t* const yuv_out,
+ const uint8_t* WEBP_RESTRICT const src,
+ uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode];
@@ -855,7 +857,8 @@
// Quantize as usual, but also compute and return the quantization error.
// Error is already divided by DSHIFT.
-static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) {
+static int QuantizeSingle(int16_t* WEBP_RESTRICT const v,
+ const VP8Matrix* WEBP_RESTRICT const mtx) {
int V = *v;
const int sign = (V < 0);
if (sign) V = -V;
@@ -869,9 +872,10 @@
return (sign ? -V : V) >> DSCALE;
}
-static void CorrectDCValues(const VP8EncIterator* const it,
- const VP8Matrix* const mtx,
- int16_t tmp[][16], VP8ModeScore* const rd) {
+static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it,
+ const VP8Matrix* WEBP_RESTRICT const mtx,
+ int16_t tmp[][16],
+ VP8ModeScore* WEBP_RESTRICT const rd) {
// | top[0] | top[1]
// --------+--------+---------
// left[0] | tmp[0] tmp[1] <-> err0 err1
@@ -902,8 +906,8 @@
}
}
-static void StoreDiffusionErrors(VP8EncIterator* const it,
- const VP8ModeScore* const rd) {
+static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it,
+ const VP8ModeScore* WEBP_RESTRICT const rd) {
int ch;
for (ch = 0; ch <= 1; ++ch) {
int8_t* const top = it->top_derr_[it->x_][ch];
@@ -922,8 +926,9 @@
//------------------------------------------------------------------------------
-static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
- uint8_t* const yuv_out, int mode) {
+static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
+ uint8_t* WEBP_RESTRICT const yuv_out, int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode];
const uint8_t* const src = it->yuv_in_ + U_OFF_ENC;
@@ -994,7 +999,8 @@
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
}
-static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
+static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT rd) {
const int kNumBlocks = 16;
VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i16_;
@@ -1054,7 +1060,7 @@
//------------------------------------------------------------------------------
// return the cost array corresponding to the surrounding prediction modes.
-static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
+static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it,
const uint8_t modes[16]) {
const int preds_w = it->enc_->preds_w_;
const int x = (it->i4_ & 3), y = it->i4_ >> 2;
@@ -1063,7 +1069,8 @@
return VP8FixedCostsI4[top][left];
}
-static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i4_;
@@ -1159,7 +1166,8 @@
//------------------------------------------------------------------------------
-static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const int kNumBlocks = 8;
const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_uv_;
@@ -1211,7 +1219,8 @@
//------------------------------------------------------------------------------
// Final reconstruction and quantization.
-static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const int is_i16 = (it->mb_->type_ == 1);
int nz = 0;
@@ -1236,9 +1245,9 @@
}
// Refine intra16/intra4 sub-modes based on distortion only (not rate).
-static void RefineUsingDistortion(VP8EncIterator* const it,
+static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
int try_both_modes, int refine_uv_mode,
- VP8ModeScore* const rd) {
+ VP8ModeScore* WEBP_RESTRICT const rd) {
score_t best_score = MAX_COST;
int nz = 0;
int mode;
@@ -1352,7 +1361,8 @@
//------------------------------------------------------------------------------
// Entry point
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt) {
int is_skipped;
const int method = it->enc_->method_;
diff --git a/src/enc/vp8i_enc.h b/src/enc/vp8i_enc.h
index b4bba08..c9927c4 100644
--- a/src/enc/vp8i_enc.h
+++ b/src/enc/vp8i_enc.h
@@ -31,8 +31,8 @@
// version numbers
#define ENC_MAJ_VERSION 1
-#define ENC_MIN_VERSION 2
-#define ENC_REV_VERSION 2
+#define ENC_MIN_VERSION 3
+#define ENC_REV_VERSION 0
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@@ -470,7 +470,8 @@
// Sets up segment's quantization values, base_quant_ and filter strengths.
void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
// Pick best modes and fills the levels. Returns true if skipped.
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt);
// in alpha.c
@@ -490,19 +491,24 @@
// misc utils for picture_*.c:
+// Returns true if 'picture' is non-NULL and dimensions/colorspace are within
+// their valid ranges. If returning false, the 'error_code' in 'picture' is
+// updated.
+int WebPValidatePicture(const WebPPicture* const picture);
+
// Remove reference to the ARGB/YUVA buffer (doesn't free anything).
void WebPPictureResetBuffers(WebPPicture* const picture);
-// Allocates ARGB buffer of given dimension (previous one is always free'd).
-// Preserves the YUV(A) buffer. Returns false in case of error (invalid param,
-// out-of-memory).
-int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
+// Allocates ARGB buffer according to set width/height (previous one is
+// always free'd). Preserves the YUV(A) buffer. Returns false in case of error
+// (invalid param, out-of-memory).
+int WebPPictureAllocARGB(WebPPicture* const picture);
-// Allocates YUVA buffer of given dimension (previous one is always free'd).
-// Uses picture->csp to determine whether an alpha buffer is needed.
+// Allocates YUVA buffer according to set width/height (previous one is always
+// free'd). Uses picture->csp to determine whether an alpha buffer is needed.
// Preserves the ARGB buffer.
// Returns false in case of error (invalid param, out-of-memory).
-int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
+int WebPPictureAllocYUVA(WebPPicture* const picture);
// Replace samples that are fully transparent by 'color' to help compressibility
// (no guarantee, though). Assumes pic->use_argb is true.
diff --git a/src/enc/vp8l_enc.c b/src/enc/vp8l_enc.c
index 38aabb8..cb5549a 100644
--- a/src/enc/vp8l_enc.c
+++ b/src/enc/vp8l_enc.c
@@ -15,15 +15,16 @@
#include <assert.h>
#include <stdlib.h>
+#include "src/dsp/lossless.h"
+#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/enc/vp8i_enc.h"
#include "src/enc/vp8li_enc.h"
-#include "src/dsp/lossless.h"
-#include "src/dsp/lossless_common.h"
#include "src/utils/bit_writer_utils.h"
#include "src/utils/huffman_encode_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
// Maximum number of histogram images (sub-blocks).
@@ -183,10 +184,9 @@
}
// Builds the cooccurrence matrix
-static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
- const uint32_t* const palette,
- uint32_t num_colors,
- uint32_t* cooccurrence) {
+static int CoOccurrenceBuild(const WebPPicture* const pic,
+ const uint32_t* const palette, uint32_t num_colors,
+ uint32_t* cooccurrence) {
uint32_t *lines, *line_top, *line_current, *line_tmp;
int x, y;
const uint32_t* src = pic->argb;
@@ -195,7 +195,10 @@
uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
uint32_t palette_sorted[MAX_PALETTE_SIZE];
lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
- if (lines == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (lines == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
line_top = &lines[0];
line_current = &lines[pic->width];
PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
@@ -226,7 +229,7 @@
src += pic->argb_stride;
}
WebPSafeFree(lines);
- return VP8_ENC_OK;
+ return 1;
}
struct Sum {
@@ -237,7 +240,7 @@
// Implements the modified Zeng method from "A Survey on Palette Reordering
// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
// Pinho and Antonio J. R. Neves.
-static WebPEncodingError PaletteSortModifiedZeng(
+static int PaletteSortModifiedZeng(
const WebPPicture* const pic, const uint32_t* const palette_sorted,
uint32_t num_colors, uint32_t* const palette) {
uint32_t i, j, ind;
@@ -247,15 +250,17 @@
uint32_t first, last;
uint32_t num_sums;
// TODO(vrabaud) check whether one color images should use palette or not.
- if (num_colors <= 1) return VP8_ENC_OK;
+ if (num_colors <= 1) return 1;
// Build the co-occurrence matrix.
cooccurrence =
(uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
- if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
- if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) !=
- VP8_ENC_OK) {
+ if (cooccurrence == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+ if (!CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence)) {
WebPSafeFree(cooccurrence);
- return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ return 0;
}
// Initialize the mapping list with the two best indices.
@@ -316,7 +321,7 @@
for (i = 0; i < num_colors; ++i) {
palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
}
- return VP8_ENC_OK;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -357,10 +362,11 @@
kHistoTotal // Must be last.
} HistoIx;
-static void AddSingleSubGreen(int p, uint32_t* const r, uint32_t* const b) {
- const int green = p >> 8; // The upper bits are masked away later.
- ++r[((p >> 16) - green) & 0xff];
- ++b[((p >> 0) - green) & 0xff];
+static void AddSingleSubGreen(uint32_t p,
+ uint32_t* const r, uint32_t* const b) {
+ const int green = (int)p >> 8; // The upper bits are masked away later.
+ ++r[(((int)p >> 16) - green) & 0xff];
+ ++b[(((int)p >> 0) - green) & 0xff];
}
static void AddSingle(uint32_t p,
@@ -434,8 +440,8 @@
curr_row += argb_stride;
}
{
- double entropy_comp[kHistoTotal];
- double entropy[kNumEntropyIx];
+ float entropy_comp[kHistoTotal];
+ float entropy[kNumEntropyIx];
int k;
int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
int j;
@@ -949,11 +955,11 @@
VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
}
-static WebPEncodingError StoreImageToBitMask(
+static int StoreImageToBitMask(
VP8LBitWriter* const bw, int width, int histo_bits,
const VP8LBackwardRefs* const refs,
const uint16_t* histogram_symbols,
- const HuffmanTreeCode* const huffman_codes) {
+ const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) {
const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
// x and y trace the position in the image.
@@ -1006,44 +1012,53 @@
}
VP8LRefsCursorNext(&c);
}
- return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
+ if (bw->error_) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+ return 1;
}
-// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
-static WebPEncodingError EncodeImageNoHuffman(
- VP8LBitWriter* const bw, const uint32_t* const argb,
- VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_array,
- int width, int height, int quality, int low_effort) {
+// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31.
+// pic and percent are for progress.
+static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs_array, int width,
+ int height, int quality, int low_effort,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
int i;
int max_tokens = 0;
- WebPEncodingError err = VP8_ENC_OK;
VP8LBackwardRefs* refs;
HuffmanTreeToken* tokens = NULL;
- HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
- const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
+ HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}};
+ const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol
int cache_bits = 0;
VP8LHistogramSet* histogram_image = NULL;
HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
- 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
+ 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
if (huff_tree == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Calculate backward references from ARGB image.
- if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
- low_effort)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort,
+ pic, percent_range / 2, percent)) {
goto Error;
}
- err = VP8LGetBackwardReferences(
- width, height, argb, quality, /*low_effort=*/0, kLZ77Standard | kLZ77RLE,
- cache_bits, /*do_no_cache=*/0, hash_chain, refs_array, &cache_bits);
- if (err != VP8_ENC_OK) goto Error;
+ if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0,
+ kLZ77Standard | kLZ77RLE, cache_bits,
+ /*do_no_cache=*/0, hash_chain, refs_array,
+ &cache_bits, pic,
+ percent_range - percent_range / 2, percent)) {
+ goto Error;
+ }
refs = &refs_array[0];
histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
if (histogram_image == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
VP8LHistogramSetClear(histogram_image);
@@ -1054,7 +1069,7 @@
// Create Huffman bit lengths and codes for each histogram image.
assert(histogram_image->size == 1);
if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1071,7 +1086,7 @@
tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
if (tokens == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1083,27 +1098,32 @@
}
// Store actual literals.
- err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
- huffman_codes);
+ if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes,
+ pic)) {
+ goto Error;
+ }
Error:
WebPSafeFree(tokens);
WebPSafeFree(huff_tree);
VP8LFreeHistogramSet(histogram_image);
WebPSafeFree(huffman_codes[0].codes);
- return err;
+ return (pic->error_code == VP8_ENC_OK);
}
-static WebPEncodingError EncodeImageInternal(
+// pic and percent are for progress.
+static int EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb,
VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
int height, int quality, int low_effort, int use_cache,
const CrunchConfig* const config, int* cache_bits, int histogram_bits,
- size_t init_byte_position, int* const hdr_size, int* const data_size) {
- WebPEncodingError err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ size_t init_byte_position, int* const hdr_size, int* const data_size,
+ const WebPPicture* const pic, int percent_range, int* const percent) {
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
+ int remaining_percent = percent_range;
+ int percent_start = *percent;
VP8LHistogramSet* histogram_image = NULL;
VP8LHistogram* tmp_histo = NULL;
int histogram_image_size = 0;
@@ -1112,9 +1132,8 @@
3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode* huffman_codes = NULL;
- uint16_t* const histogram_symbols =
- (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
- sizeof(*histogram_symbols));
+ uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc(
+ histogram_image_xysize, sizeof(*histogram_symbols));
int sub_configs_idx;
int cache_bits_init, write_histogram_image;
VP8LBitWriter bw_init = *bw, bw_best;
@@ -1126,14 +1145,27 @@
assert(hdr_size != NULL);
assert(data_size != NULL);
- // Make sure we can allocate the different objects.
memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram));
- if (huff_tree == NULL || histogram_symbols == NULL ||
- !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize) ||
- !VP8LHashChainFill(hash_chain, quality, argb, width, height,
- low_effort)) {
+ if (!VP8LBitWriterInit(&bw_best, 0)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
+
+ // Make sure we can allocate the different objects.
+ if (huff_tree == NULL || histogram_symbols == NULL ||
+ !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
+
+ percent_range = remaining_percent / 5;
+ if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
+ low_effort, pic, percent_range, percent)) {
+ goto Error;
+ }
+ percent_start += percent_range;
+ remaining_percent -= percent_range;
+
if (use_cache) {
// If the value is different from zero, it has been set during the
// palette analysis.
@@ -1142,22 +1174,27 @@
cache_bits_init = 0;
}
// If several iterations will happen, clone into bw_best.
- if (!VP8LBitWriterInit(&bw_best, 0) ||
- ((config->sub_configs_size_ > 1 ||
- config->sub_configs_[0].do_no_cache_) &&
- !VP8LBitWriterClone(bw, &bw_best))) {
+ if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
+ !VP8LBitWriterClone(bw, &bw_best)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
+
for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_;
++sub_configs_idx) {
const CrunchSubConfig* const sub_config =
&config->sub_configs_[sub_configs_idx];
int cache_bits_best, i_cache;
- err = VP8LGetBackwardReferences(width, height, argb, quality, low_effort,
- sub_config->lz77_, cache_bits_init,
- sub_config->do_no_cache_, hash_chain,
- &refs_array[0], &cache_bits_best);
- if (err != VP8_ENC_OK) goto Error;
+ int i_remaining_percent = remaining_percent / config->sub_configs_size_;
+ int i_percent_range = i_remaining_percent / 4;
+ i_remaining_percent -= i_percent_range;
+
+ if (!VP8LGetBackwardReferences(
+ width, height, argb, quality, low_effort, sub_config->lz77_,
+ cache_bits_init, sub_config->do_no_cache_, hash_chain,
+ &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) {
+ goto Error;
+ }
for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) {
const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0;
@@ -1172,11 +1209,17 @@
histogram_image =
VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp);
tmp_histo = VP8LAllocateHistogram(cache_bits_tmp);
- if (histogram_image == NULL || tmp_histo == NULL ||
- !VP8LGetHistoImageSymbols(width, height, &refs_array[i_cache],
- quality, low_effort, histogram_bits,
- cache_bits_tmp, histogram_image, tmp_histo,
- histogram_symbols)) {
+ if (histogram_image == NULL || tmp_histo == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
+
+ i_percent_range = i_remaining_percent / 3;
+ i_remaining_percent -= i_percent_range;
+ if (!VP8LGetHistoImageSymbols(
+ width, height, &refs_array[i_cache], quality, low_effort,
+ histogram_bits, cache_bits_tmp, histogram_image, tmp_histo,
+ histogram_symbols, pic, i_percent_range, percent)) {
goto Error;
}
// Create Huffman bit lengths and codes for each histogram image.
@@ -1189,6 +1232,7 @@
// GetHuffBitLengthsAndCodes().
if (huffman_codes == NULL ||
!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Free combined histograms.
@@ -1211,12 +1255,14 @@
write_histogram_image = (histogram_image_size > 1);
VP8LPutBits(bw, write_histogram_image, 1);
if (write_histogram_image) {
- uint32_t* const histogram_argb =
- (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
- sizeof(*histogram_argb));
+ uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc(
+ histogram_image_xysize, sizeof(*histogram_argb));
int max_index = 0;
uint32_t i;
- if (histogram_argb == NULL) goto Error;
+ if (histogram_argb == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
for (i = 0; i < histogram_image_xysize; ++i) {
const int symbol_index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = (symbol_index << 8);
@@ -1227,12 +1273,17 @@
histogram_image_size = max_index;
VP8LPutBits(bw, histogram_bits - 2, 3);
- err = EncodeImageNoHuffman(
- bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
- VP8LSubSampleSize(width, histogram_bits),
- VP8LSubSampleSize(height, histogram_bits), quality, low_effort);
+ i_percent_range = i_remaining_percent / 2;
+ i_remaining_percent -= i_percent_range;
+ if (!EncodeImageNoHuffman(
+ bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
+ VP8LSubSampleSize(width, histogram_bits),
+ VP8LSubSampleSize(height, histogram_bits), quality, low_effort,
+ pic, i_percent_range, percent)) {
+ WebPSafeFree(histogram_argb);
+ goto Error;
+ }
WebPSafeFree(histogram_argb);
- if (err != VP8_ENC_OK) goto Error;
}
// Store Huffman codes.
@@ -1256,9 +1307,10 @@
}
// Store actual literals.
hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
- err = StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
- histogram_symbols, huffman_codes);
- if (err != VP8_ENC_OK) goto Error;
+ if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
+ histogram_symbols, huffman_codes, pic)) {
+ goto Error;
+ }
// Keep track of the smallest image so far.
if (VP8LBitWriterNumBytes(bw) < bw_size_best) {
bw_size_best = VP8LBitWriterNumBytes(bw);
@@ -1278,7 +1330,10 @@
}
}
VP8LBitWriterSwap(bw, &bw_best);
- err = VP8_ENC_OK;
+
+ if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) {
+ goto Error;
+ }
Error:
WebPSafeFree(tokens);
@@ -1292,7 +1347,7 @@
}
WebPSafeFree(histogram_symbols);
VP8LBitWriterWipeOut(&bw_best);
- return err;
+ return (pic->error_code == VP8_ENC_OK);
}
// -----------------------------------------------------------------------------
@@ -1301,26 +1356,27 @@
static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
VP8LBitWriter* const bw) {
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
- VP8LPutBits(bw, SUBTRACT_GREEN, 2);
+ VP8LPutBits(bw, SUBTRACT_GREEN_TRANSFORM, 2);
VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
}
-static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
- int width, int height,
- int quality, int low_effort,
- int used_subtract_green,
- VP8LBitWriter* const bw) {
+static int ApplyPredictFilter(const VP8LEncoder* const enc, int width,
+ int height, int quality, int low_effort,
+ int used_subtract_green, VP8LBitWriter* const bw,
+ int percent_range, int* const percent) {
const int pred_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, pred_bits);
const int transform_height = VP8LSubSampleSize(height, pred_bits);
// we disable near-lossless quantization if palette is used.
- const int near_lossless_strength = enc->use_palette_ ? 100
- : enc->config_->near_lossless;
+ const int near_lossless_strength =
+ enc->use_palette_ ? 100 : enc->config_->near_lossless;
- VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
- enc->argb_scratch_, enc->transform_data_,
- near_lossless_strength, enc->config_->exact,
- used_subtract_green);
+ if (!VP8LResidualImage(
+ width, height, pred_bits, low_effort, enc->argb_, enc->argb_scratch_,
+ enc->transform_data_, near_lossless_strength, enc->config_->exact,
+ used_subtract_green, enc->pic_, percent_range / 2, percent)) {
+ return 0;
+ }
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
assert(pred_bits >= 2);
@@ -1328,19 +1384,23 @@
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
(VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
- quality, low_effort);
+ quality, low_effort, enc->pic_, percent_range - percent_range / 2,
+ percent);
}
-static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
- int width, int height,
- int quality, int low_effort,
- VP8LBitWriter* const bw) {
+static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width,
+ int height, int quality, int low_effort,
+ VP8LBitWriter* const bw, int percent_range,
+ int* const percent) {
const int ccolor_transform_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
- VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
- enc->argb_, enc->transform_data_);
+ if (!VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
+ enc->argb_, enc->transform_data_, enc->pic_,
+ percent_range / 2, percent)) {
+ return 0;
+ }
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
assert(ccolor_transform_bits >= 2);
@@ -1348,23 +1408,21 @@
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
(VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
- quality, low_effort);
+ quality, low_effort, enc->pic_, percent_range - percent_range / 2,
+ percent);
}
// -----------------------------------------------------------------------------
-static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
- size_t riff_size, size_t vp8l_size) {
+static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size,
+ size_t vp8l_size) {
uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
};
PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
- if (!pic->writer(riff, sizeof(riff), pic)) {
- return VP8_ENC_ERROR_BAD_WRITE;
- }
- return VP8_ENC_OK;
+ return pic->writer(riff, sizeof(riff), pic);
}
static int WriteImageSize(const WebPPicture* const pic,
@@ -1384,36 +1442,29 @@
return !bw->error_;
}
-static WebPEncodingError WriteImage(const WebPPicture* const pic,
- VP8LBitWriter* const bw,
- size_t* const coded_size) {
- WebPEncodingError err = VP8_ENC_OK;
+static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
+ size_t* const coded_size) {
const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
const size_t webpll_size = VP8LBitWriterNumBytes(bw);
const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
const size_t pad = vp8l_size & 1;
const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
- err = WriteRiffHeader(pic, riff_size, vp8l_size);
- if (err != VP8_ENC_OK) goto Error;
-
- if (!pic->writer(webpll_data, webpll_size, pic)) {
- err = VP8_ENC_ERROR_BAD_WRITE;
- goto Error;
+ if (!WriteRiffHeader(pic, riff_size, vp8l_size) ||
+ !pic->writer(webpll_data, webpll_size, pic)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
+ return 0;
}
if (pad) {
const uint8_t pad_byte[1] = { 0 };
if (!pic->writer(pad_byte, 1, pic)) {
- err = VP8_ENC_ERROR_BAD_WRITE;
- goto Error;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
+ return 0;
}
}
*coded_size = CHUNK_HEADER_SIZE + riff_size;
- return VP8_ENC_OK;
-
- Error:
- return err;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -1429,18 +1480,16 @@
// Flags influencing the memory allocated:
// enc->transform_bits_
// enc->use_predict_, enc->use_cross_color_
-static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
- int width, int height) {
- WebPEncodingError err = VP8_ENC_OK;
+static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
+ int height) {
const uint64_t image_size = width * height;
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
// TODO(skal): Clean up by using arithmetic in bytes instead of words.
const uint64_t argb_scratch_size =
- enc->use_predict_
- ? (width + 1) * 2 +
- (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t)
- : 0;
+ enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) /
+ sizeof(uint32_t)
+ : 0;
const uint64_t transform_data_size =
(enc->use_predict_ || enc->use_cross_color_)
? VP8LSubSampleSize(width, enc->transform_bits_) *
@@ -1448,17 +1497,16 @@
: 0;
const uint64_t max_alignment_in_words =
(WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
- const uint64_t mem_size =
- image_size + max_alignment_in_words +
- argb_scratch_size + max_alignment_in_words +
- transform_data_size;
+ const uint64_t mem_size = image_size + max_alignment_in_words +
+ argb_scratch_size + max_alignment_in_words +
+ transform_data_size;
uint32_t* mem = enc->transform_mem_;
if (mem == NULL || mem_size > enc->transform_mem_size_) {
ClearTransformBuffer(enc);
mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
if (mem == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
}
enc->transform_mem_ = mem;
enc->transform_mem_size_ = (size_t)mem_size;
@@ -1471,19 +1519,16 @@
enc->transform_data_ = mem;
enc->current_width_ = width;
- Error:
- return err;
+ return 1;
}
-static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
- WebPEncodingError err = VP8_ENC_OK;
+static int MakeInputImageCopy(VP8LEncoder* const enc) {
const WebPPicture* const picture = enc->pic_;
const int width = picture->width;
const int height = picture->height;
- err = AllocateTransformBuffer(enc, width, height);
- if (err != VP8_ENC_OK) return err;
- if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK;
+ if (!AllocateTransformBuffer(enc, width, height)) return 0;
+ if (enc->argb_content_ == kEncoderARGB) return 1;
{
uint32_t* dst = enc->argb_;
@@ -1497,7 +1542,7 @@
}
enc->argb_content_ = kEncoderARGB;
assert(enc->current_width_ == width);
- return VP8_ENC_OK;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -1559,16 +1604,19 @@
// using 'row' as a temporary buffer of size 'width'.
// We assume that all src[] values have a corresponding entry in the palette.
// Note: src[] can be the same as dst[]
-static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
- uint32_t* dst, uint32_t dst_stride,
- const uint32_t* palette, int palette_size,
- int width, int height, int xbits) {
+static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst,
+ uint32_t dst_stride, const uint32_t* palette,
+ int palette_size, int width, int height, int xbits,
+ const WebPPicture* const pic) {
// TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
// made to work in-place.
uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
int x, y;
- if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (tmp_row == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix));
@@ -1613,7 +1661,7 @@
}
}
WebPSafeFree(tmp_row);
- return VP8_ENC_OK;
+ return 1;
}
#undef APPLY_PALETTE_FOR
#undef PALETTE_INV_SIZE_BITS
@@ -1621,9 +1669,7 @@
#undef APPLY_PALETTE_GREEDY_MAX
// Note: Expects "enc->palette_" to be set properly.
-static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
- int in_place) {
- WebPEncodingError err = VP8_ENC_OK;
+static int MapImageFromPalette(VP8LEncoder* const enc, int in_place) {
const WebPPicture* const pic = enc->pic_;
const int width = pic->width;
const int height = pic->height;
@@ -1641,19 +1687,22 @@
xbits = (palette_size <= 16) ? 1 : 0;
}
- err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
- if (err != VP8_ENC_OK) return err;
-
- err = ApplyPalette(src, src_stride,
+ if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) {
+ return 0;
+ }
+ if (!ApplyPalette(src, src_stride,
enc->argb_, enc->current_width_,
- palette, palette_size, width, height, xbits);
+ palette, palette_size, width, height, xbits, pic)) {
+ return 0;
+ }
enc->argb_content_ = kEncoderPalette;
- return err;
+ return 1;
}
// Save palette_[] to bitstream.
static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
- VP8LEncoder* const enc) {
+ VP8LEncoder* const enc,
+ int percent_range, int* const percent) {
int i;
uint32_t tmp_palette[MAX_PALETTE_SIZE];
const int palette_size = enc->palette_size_;
@@ -1668,7 +1717,7 @@
tmp_palette[0] = palette[0];
return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_,
&enc->refs_[0], palette_size, 1, /*quality=*/20,
- low_effort);
+ low_effort, enc->pic_, percent_range, percent);
}
// -----------------------------------------------------------------------------
@@ -1712,7 +1761,6 @@
CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
int num_crunch_configs_;
int red_and_blue_always_zero_;
- WebPEncodingError err_;
WebPAuxStats* stats_;
} StreamEncodeContext;
@@ -1729,7 +1777,6 @@
#if !defined(WEBP_DISABLE_STATS)
WebPAuxStats* const stats = params->stats_;
#endif
- WebPEncodingError err = VP8_ENC_OK;
const int quality = (int)config->quality;
const int low_effort = (config->method == 0);
#if (WEBP_NEAR_LOSSLESS == 1)
@@ -1737,6 +1784,7 @@
#endif
const int height = picture->height;
const size_t byte_position = VP8LBitWriterNumBytes(bw);
+ int percent = 2; // for WebPProgressHook
#if (WEBP_NEAR_LOSSLESS == 1)
int use_near_lossless = 0;
#endif
@@ -1750,12 +1798,13 @@
if (!VP8LBitWriterInit(&bw_best, 0) ||
(num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
for (idx = 0; idx < num_crunch_configs; ++idx) {
const int entropy_idx = crunch_configs[idx].entropy_idx_;
+ int remaining_percent = 97 / num_crunch_configs, percent_range;
enc->use_palette_ =
(entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial);
enc->use_subtract_green_ =
@@ -1779,11 +1828,10 @@
use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ &&
!enc->use_predict_;
if (use_near_lossless) {
- err = AllocateTransformBuffer(enc, width, height);
- if (err != VP8_ENC_OK) goto Error;
+ if (!AllocateTransformBuffer(enc, width, height)) goto Error;
if ((enc->argb_content_ != kEncoderNearLossless) &&
!VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
enc->argb_content_ = kEncoderNearLossless;
@@ -1805,14 +1853,17 @@
enc->palette_);
} else {
assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
- err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
- enc->palette_size_, enc->palette_);
- if (err != VP8_ENC_OK) goto Error;
+ if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
+ enc->palette_size_, enc->palette_)) {
+ goto Error;
+ }
}
- err = EncodePalette(bw, low_effort, enc);
- if (err != VP8_ENC_OK) goto Error;
- err = MapImageFromPalette(enc, use_delta_palette);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 4;
+ if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
+ if (!MapImageFromPalette(enc, use_delta_palette)) goto Error;
// If using a color cache, do not have it bigger than the number of
// colors.
if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
@@ -1823,8 +1874,7 @@
// In case image is not packed.
if (enc->argb_content_ != kEncoderNearLossless &&
enc->argb_content_ != kEncoderPalette) {
- err = MakeInputImageCopy(enc);
- if (err != VP8_ENC_OK) goto Error;
+ if (!MakeInputImageCopy(enc)) goto Error;
}
// -----------------------------------------------------------------------
@@ -1835,15 +1885,22 @@
}
if (enc->use_predict_) {
- err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
- low_effort, enc->use_subtract_green_, bw);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 3;
+ if (!ApplyPredictFilter(enc, enc->current_width_, height, quality,
+ low_effort, enc->use_subtract_green_, bw,
+ percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
}
if (enc->use_cross_color_) {
- err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
- low_effort, bw);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 2;
+ if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
+ low_effort, bw, percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
}
}
@@ -1851,12 +1908,13 @@
// -------------------------------------------------------------------------
// Encode and write the transformed image.
- err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
- enc->current_width_, height, quality, low_effort,
- use_cache, &crunch_configs[idx],
- &enc->cache_bits_, enc->histo_bits_,
- byte_position, &hdr_size, &data_size);
- if (err != VP8_ENC_OK) goto Error;
+ if (!EncodeImageInternal(
+ bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
+ height, quality, low_effort, use_cache, &crunch_configs[idx],
+ &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
+ &data_size, picture, remaining_percent, &percent)) {
+ goto Error;
+ }
// If we are better than what we already have.
if (VP8LBitWriterNumBytes(bw) < best_size) {
@@ -1886,18 +1944,15 @@
}
VP8LBitWriterSwap(&bw_best, bw);
-Error:
+ Error:
VP8LBitWriterWipeOut(&bw_best);
- params->err_ = err;
// The hook should return false in case of error.
- return (err == VP8_ENC_OK);
+ return (params->picture_->error_code == VP8_ENC_OK);
}
-WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture,
- VP8LBitWriter* const bw_main,
- int use_cache) {
- WebPEncodingError err = VP8_ENC_OK;
+int VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture,
+ VP8LBitWriter* const bw_main, int use_cache) {
VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
VP8LEncoder* enc_side = NULL;
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
@@ -1909,6 +1964,7 @@
// The main thread uses picture->stats, the side thread uses stats_side.
WebPAuxStats stats_side;
VP8LBitWriter bw_side;
+ WebPPicture picture_side;
const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface();
int ok_main;
@@ -1918,11 +1974,14 @@
return 0;
}
+ // Avoid "garbage value" error from Clang's static analysis tool.
+ WebPPictureInit(&picture_side);
+
// Analyze image (entropy, num_palettes etc)
if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
&red_and_blue_always_zero) ||
!EncoderInit(enc_main)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1951,25 +2010,32 @@
StreamEncodeContext* const param =
(idx == 0) ? ¶ms_main : ¶ms_side;
param->config_ = config;
- param->picture_ = picture;
param->use_cache_ = use_cache;
param->red_and_blue_always_zero_ = red_and_blue_always_zero;
if (idx == 0) {
+ param->picture_ = picture;
param->stats_ = picture->stats;
param->bw_ = bw_main;
param->enc_ = enc_main;
} else {
+ // Create a side picture (error_code is not thread-safe).
+ if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width,
+ picture->height, &picture_side)) {
+ assert(0);
+ }
+ picture_side.progress_hook = NULL; // Progress hook is not thread-safe.
+ param->picture_ = &picture_side; // No need to free a view afterwards.
param->stats_ = (picture->stats == NULL) ? NULL : &stats_side;
// Create a side bit writer.
if (!VP8LBitWriterClone(bw_main, &bw_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
param->bw_ = &bw_side;
// Create a side encoder.
- enc_side = VP8LEncoderNew(config, picture);
+ enc_side = VP8LEncoderNew(config, &picture_side);
if (enc_side == NULL || !EncoderInit(enc_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Copy the values that were computed for the main encoder.
@@ -1993,7 +2059,7 @@
// Start the second thread if needed.
if (num_crunch_configs_side != 0) {
if (!worker_interface->Reset(&worker_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
#if !defined(WEBP_DISABLE_STATS)
@@ -2003,8 +2069,6 @@
memcpy(&stats_side, picture->stats, sizeof(stats_side));
}
#endif
- // This line is only useful to remove a Clang static analyzer warning.
- params_side.err_ = VP8_ENC_OK;
worker_interface->Launch(&worker_side);
}
// Execute the main thread.
@@ -2016,7 +2080,10 @@
const int ok_side = worker_interface->Sync(&worker_side);
worker_interface->End(&worker_side);
if (!ok_main || !ok_side) {
- err = ok_main ? params_side.err_ : params_main.err_;
+ if (picture->error_code == VP8_ENC_OK) {
+ assert(picture_side.error_code != VP8_ENC_OK);
+ WebPEncodingSetError(picture, picture_side.error_code);
+ }
goto Error;
}
if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) {
@@ -2027,18 +2094,13 @@
}
#endif
}
- } else {
- if (!ok_main) {
- err = params_main.err_;
- goto Error;
- }
}
-Error:
+ Error:
VP8LBitWriterWipeOut(&bw_side);
VP8LEncoderDelete(enc_main);
VP8LEncoderDelete(enc_side);
- return err;
+ return (picture->error_code == VP8_ENC_OK);
}
#undef CRUNCH_CONFIGS_MAX
@@ -2051,14 +2113,12 @@
size_t coded_size;
int percent = 0;
int initial_size;
- WebPEncodingError err = VP8_ENC_OK;
VP8LBitWriter bw;
if (picture == NULL) return 0;
if (config == NULL || picture->argb == NULL) {
- err = VP8_ENC_ERROR_NULL_PARAMETER;
- WebPEncodingSetError(picture, err);
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
return 0;
}
@@ -2069,13 +2129,13 @@
initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
width * height : width * height * 2;
if (!VP8LBitWriterInit(&bw, initial_size)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
if (!WebPReportProgress(picture, 1, &percent)) {
UserAbort:
- err = VP8_ENC_ERROR_USER_ABORT;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT);
goto Error;
}
// Reset stats (for pure lossless coding)
@@ -2091,28 +2151,26 @@
// Write image size.
if (!WriteImageSize(picture, &bw)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
has_alpha = WebPPictureHasTransparency(picture);
// Write the non-trivial Alpha flag and lossless version.
if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
- if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
+ if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
// Encode main image stream.
- err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/);
- if (err != VP8_ENC_OK) goto Error;
+ if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error;
- if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
+ if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;
// Finish the RIFF chunk.
- err = WriteImage(picture, &bw, &coded_size);
- if (err != VP8_ENC_OK) goto Error;
+ if (!WriteImage(picture, &bw, &coded_size)) goto Error;
if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
@@ -2131,13 +2189,11 @@
}
Error:
- if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- VP8LBitWriterWipeOut(&bw);
- if (err != VP8_ENC_OK) {
- WebPEncodingSetError(picture, err);
- return 0;
+ if (bw.error_) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
- return 1;
+ VP8LBitWriterWipeOut(&bw);
+ return (picture->error_code == VP8_ENC_OK);
}
//------------------------------------------------------------------------------
diff --git a/src/enc/vp8li_enc.h b/src/enc/vp8li_enc.h
index 00de489..3d35e16 100644
--- a/src/enc/vp8li_enc.h
+++ b/src/enc/vp8li_enc.h
@@ -89,9 +89,10 @@
// Encodes the main image stream using the supplied bit writer.
// If 'use_cache' is false, disables the use of color cache.
-WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture,
- VP8LBitWriter* const bw, int use_cache);
+// Returns false in case of error (stored in picture->error_code).
+int VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture, VP8LBitWriter* const bw,
+ int use_cache);
#if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c
@@ -103,13 +104,18 @@
//------------------------------------------------------------------------------
// Image transforms in predictor.c.
-void VP8LResidualImage(int width, int height, int bits, int low_effort,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image, int near_lossless, int exact,
- int used_subtract_green);
+// pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
+int VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image, int near_lossless, int exact,
+ int used_subtract_green, const WebPPicture* const pic,
+ int percent_range, int* const percent);
-void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
- uint32_t* const argb, uint32_t* image);
+int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent);
//------------------------------------------------------------------------------
diff --git a/src/enc/webp_enc.c b/src/enc/webp_enc.c
index ce2db2e..9620e05 100644
--- a/src/enc/webp_enc.c
+++ b/src/enc/webp_enc.c
@@ -336,9 +336,7 @@
if (!WebPValidateConfig(config)) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
- if (pic->width <= 0 || pic->height <= 0) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
- }
+ if (!WebPValidatePicture(pic)) return 0;
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
}
diff --git a/src/libwebp.pc.in b/src/libwebp.pc.in
new file mode 100644
index 0000000..783090e
--- /dev/null
+++ b/src/libwebp.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libwebp
+Description: Library for the WebP graphics format
+Version: @PACKAGE_VERSION@
+Requires.private: libsharpyuv
+Cflags: -I${includedir}
+Libs: -L${libdir} -l@webp_libname_prefix@webp
+Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
diff --git a/src/libwebp.rc b/src/libwebp.rc
new file mode 100644
index 0000000..6b11dc8
--- /dev/null
+++ b/src/libwebp.rc
@@ -0,0 +1,41 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,3,0
+ PRODUCTVERSION 1,0,3,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google, Inc."
+ VALUE "FileDescription", "libwebp DLL"
+ VALUE "FileVersion", "1.3.0"
+ VALUE "InternalName", "libwebp.dll"
+ VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "OriginalFilename", "libwebp.dll"
+ VALUE "ProductName", "WebP Image Codec"
+ VALUE "ProductVersion", "1.3.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
diff --git a/src/libwebpdecoder.pc.in b/src/libwebpdecoder.pc.in
new file mode 100644
index 0000000..134de0e
--- /dev/null
+++ b/src/libwebpdecoder.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libwebpdecoder
+Description: Library for the WebP graphics format (decode only)
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -l@webp_libname_prefix@webpdecoder
+Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
diff --git a/src/libwebpdecoder.rc b/src/libwebpdecoder.rc
new file mode 100644
index 0000000..44e4f26
--- /dev/null
+++ b/src/libwebpdecoder.rc
@@ -0,0 +1,41 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,3,0
+ PRODUCTVERSION 1,0,3,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google, Inc."
+ VALUE "FileDescription", "libwebpdecoder DLL"
+ VALUE "FileVersion", "1.3.0"
+ VALUE "InternalName", "libwebpdecoder.dll"
+ VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "OriginalFilename", "libwebpdecoder.dll"
+ VALUE "ProductName", "WebP Image Decoder"
+ VALUE "ProductVersion", "1.3.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
diff --git a/src/mux/Makefile.am b/src/mux/Makefile.am
new file mode 100644
index 0000000..8f7f739
--- /dev/null
+++ b/src/mux/Makefile.am
@@ -0,0 +1,22 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+lib_LTLIBRARIES = libwebpmux.la
+
+libwebpmux_la_SOURCES =
+libwebpmux_la_SOURCES += anim_encode.c
+libwebpmux_la_SOURCES += animi.h
+libwebpmux_la_SOURCES += muxedit.c
+libwebpmux_la_SOURCES += muxi.h
+libwebpmux_la_SOURCES += muxinternal.c
+libwebpmux_la_SOURCES += muxread.c
+
+libwebpmuxinclude_HEADERS =
+libwebpmuxinclude_HEADERS += ../webp/mux.h
+libwebpmuxinclude_HEADERS += ../webp/mux_types.h
+libwebpmuxinclude_HEADERS += ../webp/types.h
+noinst_HEADERS =
+noinst_HEADERS += ../webp/format_constants.h
+
+libwebpmux_la_LIBADD = ../libwebp.la
+libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:11:0 -lm
+libwebpmuxincludedir = $(includedir)/webp
+pkgconfig_DATA = libwebpmux.pc
diff --git a/src/mux/libwebpmux.pc.in b/src/mux/libwebpmux.pc.in
new file mode 100644
index 0000000..c770daa
--- /dev/null
+++ b/src/mux/libwebpmux.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libwebpmux
+Description: Library for manipulating the WebP graphics format container
+Version: @PACKAGE_VERSION@
+Requires.private: libwebp >= 0.2.0
+Cflags: -I${includedir}
+Libs: -L${libdir} -l@webp_libname_prefix@webpmux
+Libs.private: -lm
diff --git a/src/mux/libwebpmux.rc b/src/mux/libwebpmux.rc
new file mode 100644
index 0000000..a61f537
--- /dev/null
+++ b/src/mux/libwebpmux.rc
@@ -0,0 +1,41 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,3,0
+ PRODUCTVERSION 1,0,3,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google, Inc."
+ VALUE "FileDescription", "libwebpmux DLL"
+ VALUE "FileVersion", "1.3.0"
+ VALUE "InternalName", "libwebpmux.dll"
+ VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "OriginalFilename", "libwebpmux.dll"
+ VALUE "ProductName", "WebP Image Muxer"
+ VALUE "ProductVersion", "1.3.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c
index 02c3ede..63e71a0 100644
--- a/src/mux/muxedit.c
+++ b/src/mux/muxedit.c
@@ -70,6 +70,7 @@
err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
err = ChunkSetHead(&chunk, (LIST)); \
+ if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
} \
return err; \
}
diff --git a/src/mux/muxi.h b/src/mux/muxi.h
index d9bf9b3..7929138 100644
--- a/src/mux/muxi.h
+++ b/src/mux/muxi.h
@@ -28,8 +28,8 @@
// Defines and constants.
#define MUX_MAJ_VERSION 1
-#define MUX_MIN_VERSION 2
-#define MUX_REV_VERSION 2
+#define MUX_MIN_VERSION 3
+#define MUX_REV_VERSION 0
// Chunk object.
typedef struct WebPChunk WebPChunk;
diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c
index b9ee671..75b6b41 100644
--- a/src/mux/muxinternal.c
+++ b/src/mux/muxinternal.c
@@ -155,17 +155,18 @@
WebPMuxError ChunkAppend(WebPChunk* const chunk,
WebPChunk*** const chunk_list) {
+ WebPMuxError err;
assert(chunk_list != NULL && *chunk_list != NULL);
if (**chunk_list == NULL) {
- ChunkSetHead(chunk, *chunk_list);
+ err = ChunkSetHead(chunk, *chunk_list);
} else {
WebPChunk* last_chunk = **chunk_list;
while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_;
- ChunkSetHead(chunk, &last_chunk->next_);
- *chunk_list = &last_chunk->next_;
+ err = ChunkSetHead(chunk, &last_chunk->next_);
+ if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_;
}
- return WEBP_MUX_OK;
+ return err;
}
//------------------------------------------------------------------------------
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
new file mode 100644
index 0000000..a4bff8b
--- /dev/null
+++ b/src/utils/Makefile.am
@@ -0,0 +1,52 @@
+AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
+noinst_LTLIBRARIES = libwebputils.la
+
+if BUILD_LIBWEBPDECODER
+ noinst_LTLIBRARIES += libwebputilsdecode.la
+endif
+
+common_HEADERS = ../webp/types.h
+commondir = $(includedir)/webp
+
+noinst_HEADERS =
+noinst_HEADERS += ../dsp/cpu.h
+noinst_HEADERS += ../dsp/dsp.h
+noinst_HEADERS += ../webp/decode.h
+noinst_HEADERS += ../webp/encode.h
+noinst_HEADERS += ../webp/format_constants.h
+
+COMMON_SOURCES =
+COMMON_SOURCES += bit_reader_utils.c
+COMMON_SOURCES += bit_reader_utils.h
+COMMON_SOURCES += bit_reader_inl_utils.h
+COMMON_SOURCES += color_cache_utils.c
+COMMON_SOURCES += color_cache_utils.h
+COMMON_SOURCES += endian_inl_utils.h
+COMMON_SOURCES += filters_utils.c
+COMMON_SOURCES += filters_utils.h
+COMMON_SOURCES += huffman_utils.c
+COMMON_SOURCES += huffman_utils.h
+COMMON_SOURCES += quant_levels_dec_utils.c
+COMMON_SOURCES += quant_levels_dec_utils.h
+COMMON_SOURCES += rescaler_utils.c
+COMMON_SOURCES += rescaler_utils.h
+COMMON_SOURCES += random_utils.c
+COMMON_SOURCES += random_utils.h
+COMMON_SOURCES += thread_utils.c
+COMMON_SOURCES += thread_utils.h
+COMMON_SOURCES += utils.c
+COMMON_SOURCES += utils.h
+
+ENC_SOURCES =
+ENC_SOURCES += bit_writer_utils.c
+ENC_SOURCES += bit_writer_utils.h
+ENC_SOURCES += huffman_encode_utils.c
+ENC_SOURCES += huffman_encode_utils.h
+ENC_SOURCES += quant_levels_utils.c
+ENC_SOURCES += quant_levels_utils.h
+
+libwebputils_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
+
+if BUILD_LIBWEBPDECODER
+ libwebputilsdecode_la_SOURCES = $(COMMON_SOURCES)
+endif
diff --git a/src/utils/bit_reader_inl_utils.h b/src/utils/bit_reader_inl_utils.h
index 404b9a6..24f3af7 100644
--- a/src/utils/bit_reader_inl_utils.h
+++ b/src/utils/bit_reader_inl_utils.h
@@ -148,9 +148,9 @@
const range_t value = (range_t)(br->value_ >> pos);
const int32_t mask = (int32_t)(split - value) >> 31; // -1 or 0
br->bits_ -= 1;
- br->range_ += mask;
+ br->range_ += (range_t)mask;
br->range_ |= 1;
- br->value_ -= (bit_t)((split + 1) & mask) << pos;
+ br->value_ -= (bit_t)((split + 1) & (uint32_t)mask) << pos;
BT_TRACK(br);
return (v ^ mask) - mask;
}
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
index 0cba0fb..90c2fbf 100644
--- a/src/utils/huffman_utils.c
+++ b/src/utils/huffman_utils.c
@@ -142,7 +142,7 @@
{
int step; // step size to replicate values in current table
- uint32_t low = -1; // low bits for current root entry
+ uint32_t low = 0xffffffffu; // low bits for current root entry
uint32_t mask = total_size - 1; // mask for low bits
uint32_t key = 0; // reversed prefix code
int num_nodes = 1; // number of Huffman tree nodes
diff --git a/src/utils/utils.h b/src/utils/utils.h
index ef04f10..c5ee873 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -64,7 +64,8 @@
// Alignment
#define WEBP_ALIGN_CST 31
-#define WEBP_ALIGN(PTR) (((uintptr_t)(PTR) + WEBP_ALIGN_CST) & ~WEBP_ALIGN_CST)
+#define WEBP_ALIGN(PTR) (((uintptr_t)(PTR) + WEBP_ALIGN_CST) & \
+ ~(uintptr_t)WEBP_ALIGN_CST)
#include <string.h>
// memcpy() is the safe way of moving potentially unaligned 32b memory.
@@ -73,10 +74,19 @@
memcpy(&A, ptr, sizeof(A));
return A;
}
+
+static WEBP_INLINE int32_t WebPMemToInt32(const uint8_t* const ptr) {
+ return (int32_t)WebPMemToUint32(ptr);
+}
+
static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
memcpy(ptr, &val, sizeof(val));
}
+static WEBP_INLINE void WebPInt32ToMem(uint8_t* const ptr, int val) {
+ WebPUint32ToMem(ptr, (uint32_t)val);
+}
+
//------------------------------------------------------------------------------
// Reading/writing data.
diff --git a/src/webp/encode.h b/src/webp/encode.h
index b4c599d..56b68e2 100644
--- a/src/webp/encode.h
+++ b/src/webp/encode.h
@@ -441,7 +441,7 @@
// the original dimension will be lost). Picture 'dst' need not be initialized
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
-// Returns false in case of memory allocation error or invalid parameters.
+// Returns false in case of invalid parameters.
WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
WebPPicture* dst);
@@ -455,7 +455,7 @@
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
+WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
@@ -526,7 +526,7 @@
// Remove the transparency information (if present) by blending the color with
// the background color 'background_rgb' (specified as 24bit RGB triplet).
// After this call, all alpha values are reset to 0xff.
-WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
+WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
//------------------------------------------------------------------------------
// Main call
diff --git a/src/webp/format_constants.h b/src/webp/format_constants.h
index eca6981..999035c 100644
--- a/src/webp/format_constants.h
+++ b/src/webp/format_constants.h
@@ -55,7 +55,7 @@
typedef enum {
PREDICTOR_TRANSFORM = 0,
CROSS_COLOR_TRANSFORM = 1,
- SUBTRACT_GREEN = 2,
+ SUBTRACT_GREEN_TRANSFORM = 2,
COLOR_INDEXING_TRANSFORM = 3
} VP8LImageTransformType;
diff --git a/src/webp/types.h b/src/webp/types.h
index 47f7f2b..f255432 100644
--- a/src/webp/types.h
+++ b/src/webp/types.h
@@ -42,7 +42,11 @@
# if defined(__GNUC__) && __GNUC__ >= 4
# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
# else
-# define WEBP_EXTERN extern
+# if defined(_MSC_VER) && defined(WEBP_DLL)
+# define WEBP_EXTERN __declspec(dllexport)
+# else
+# define WEBP_EXTERN extern
+# endif
# endif /* __GNUC__ >= 4 */
#endif /* WEBP_EXTERN */
diff --git a/swig/README.md b/swig/README.md
new file mode 100644
index 0000000..7fa1c38
--- /dev/null
+++ b/swig/README.md
@@ -0,0 +1,67 @@
+# SWIG bindings
+
+## Building
+
+### JNI SWIG bindings
+
+```shell
+ $ gcc -shared -fPIC -fno-strict-aliasing -O2 \
+ -I/path/to/your/jdk/includes \
+ libwebp_java_wrap.c \
+ -lwebp \
+ -o libwebp_jni.so
+```
+
+Example usage:
+
+```java
+import com.google.webp.libwebp;
+
+import java.lang.reflect.Method;
+
+public class libwebp_jni_example {
+ static {
+ System.loadLibrary("webp_jni");
+ }
+
+ /**
+ * usage: java -cp libwebp.jar:. libwebp_jni_example
+ */
+ public static void main(String argv[]) {
+ final int version = libwebp.WebPGetDecoderVersion();
+ System.out.println("libwebp version: " + Integer.toHexString(version));
+
+ System.out.println("libwebp methods:");
+ final Method[] libwebpMethods = libwebp.class.getDeclaredMethods();
+ for (int i = 0; i < libwebpMethods.length; i++) {
+ System.out.println(libwebpMethods[i]);
+ }
+ }
+}
+```
+
+```shell
+ $ javac -cp libwebp.jar libwebp_jni_example.java
+ $ java -Djava.library.path=. -cp libwebp.jar:. libwebp_jni_example
+```
+
+### Python SWIG bindings:
+
+```shell
+ $ python setup.py build_ext
+ $ python setup.py install --prefix=pylocal
+```
+
+Example usage:
+
+```python
+import glob
+import sys
+sys.path.append(glob.glob('pylocal/lib/python*/site-packages')[0])
+
+from com.google.webp import libwebp
+print "libwebp decoder version: %x" % libwebp.WebPGetDecoderVersion()
+
+print "libwebp attributes:"
+for attr in dir(libwebp): print attr
+```
diff --git a/swig/libwebp.go b/swig/libwebp.go
new file mode 100644
index 0000000..df205aa
--- /dev/null
+++ b/swig/libwebp.go
@@ -0,0 +1,45 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.10
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+package libwebp
+
+import _ "runtime/cgo"
+import "unsafe"
+
+type _ unsafe.Pointer
+
+type _swig_fnptr *byte
+type _swig_memberptr *byte
+
+//extern libwebpSwigCgocall
+func SwigCgocall()
+
+//extern libwebpSwigCgocallDone
+func SwigCgocallDone()
+
+//extern libwebpSwigCgocallBack
+func SwigCgocallBack()
+
+//extern libwebpSwigCgocallBackDone
+func SwigCgocallBackDone()
+
+func WebPGetDecoderVersion() int
+func Wrapped_WebPGetInfo(string, []int, []int) int
+
+// WebPGetInfo has 2 output parameters, provide a version in the more natural
+// go idiom:
+func WebPGetInfo(webp []byte) (ok bool, width int, height int) {
+ w := []int{0}
+ h := []int{0}
+ ok = Wrapped_WebPGetInfo(string(webp), w, h) != 0
+ width = w[0]
+ height = h[0]
+ return
+}
diff --git a/swig/libwebp.jar b/swig/libwebp.jar
new file mode 100644
index 0000000..2fc502b
--- /dev/null
+++ b/swig/libwebp.jar
Binary files differ
diff --git a/swig/libwebp.py b/swig/libwebp.py
new file mode 100644
index 0000000..2d126b5
--- /dev/null
+++ b/swig/libwebp.py
@@ -0,0 +1,235 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 3.0.12
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+from sys import version_info as _swig_python_version_info
+if _swig_python_version_info >= (2, 7, 0):
+ def swig_import_helper():
+ import importlib
+ pkg = __name__.rpartition('.')[0]
+ mname = '.'.join((pkg, '_libwebp')).lstrip('.')
+ try:
+ return importlib.import_module(mname)
+ except ImportError:
+ return importlib.import_module('_libwebp')
+ _libwebp = swig_import_helper()
+ del swig_import_helper
+elif _swig_python_version_info >= (2, 6, 0):
+ def swig_import_helper():
+ from os.path import dirname
+ import imp
+ fp = None
+ try:
+ fp, pathname, description = imp.find_module('_libwebp', [dirname(__file__)])
+ except ImportError:
+ import _libwebp
+ return _libwebp
+ try:
+ _mod = imp.load_module('_libwebp', fp, pathname, description)
+ finally:
+ if fp is not None:
+ fp.close()
+ return _mod
+ _libwebp = swig_import_helper()
+ del swig_import_helper
+else:
+ import _libwebp
+del _swig_python_version_info
+
+try:
+ _swig_property = property
+except NameError:
+ pass # Python < 2.2 doesn't have 'property'.
+
+try:
+ import builtins as __builtin__
+except ImportError:
+ import __builtin__
+
+def _swig_setattr_nondynamic(self, class_type, name, value, static=1):
+ if (name == "thisown"):
+ return self.this.own(value)
+ if (name == "this"):
+ if type(value).__name__ == 'SwigPyObject':
+ self.__dict__[name] = value
+ return
+ method = class_type.__swig_setmethods__.get(name, None)
+ if method:
+ return method(self, value)
+ if (not static):
+ if _newclass:
+ object.__setattr__(self, name, value)
+ else:
+ self.__dict__[name] = value
+ else:
+ raise AttributeError("You cannot add attributes to %s" % self)
+
+
+def _swig_setattr(self, class_type, name, value):
+ return _swig_setattr_nondynamic(self, class_type, name, value, 0)
+
+
+def _swig_getattr(self, class_type, name):
+ if (name == "thisown"):
+ return self.this.own()
+ method = class_type.__swig_getmethods__.get(name, None)
+ if method:
+ return method(self)
+ raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name))
+
+
+def _swig_repr(self):
+ try:
+ strthis = "proxy of " + self.this.__repr__()
+ except __builtin__.Exception:
+ strthis = ""
+ return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
+
+try:
+ _object = object
+ _newclass = 1
+except __builtin__.Exception:
+ class _object:
+ pass
+ _newclass = 0
+
+
+def WebPGetDecoderVersion():
+ """WebPGetDecoderVersion() -> int"""
+ return _libwebp.WebPGetDecoderVersion()
+
+def WebPGetInfo(data):
+ """WebPGetInfo(uint8_t data) -> (width, height)"""
+ return _libwebp.WebPGetInfo(data)
+
+def WebPDecodeRGB(data):
+ """WebPDecodeRGB(uint8_t data) -> (rgb, width, height)"""
+ return _libwebp.WebPDecodeRGB(data)
+
+def WebPDecodeRGBA(data):
+ """WebPDecodeRGBA(uint8_t data) -> (rgb, width, height)"""
+ return _libwebp.WebPDecodeRGBA(data)
+
+def WebPDecodeARGB(data):
+ """WebPDecodeARGB(uint8_t data) -> (rgb, width, height)"""
+ return _libwebp.WebPDecodeARGB(data)
+
+def WebPDecodeBGR(data):
+ """WebPDecodeBGR(uint8_t data) -> (rgb, width, height)"""
+ return _libwebp.WebPDecodeBGR(data)
+
+def WebPDecodeBGRA(data):
+ """WebPDecodeBGRA(uint8_t data) -> (rgb, width, height)"""
+ return _libwebp.WebPDecodeBGRA(data)
+
+def WebPGetEncoderVersion():
+ """WebPGetEncoderVersion() -> int"""
+ return _libwebp.WebPGetEncoderVersion()
+
+def wrap_WebPEncodeRGB(rgb, unused1, unused2, width, height, stride, quality_factor):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeRGB(rgb, unused1, unused2, width, height, stride, quality_factor)
+
+def wrap_WebPEncodeBGR(rgb, unused1, unused2, width, height, stride, quality_factor):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeBGR(rgb, unused1, unused2, width, height, stride, quality_factor)
+
+def wrap_WebPEncodeRGBA(rgb, unused1, unused2, width, height, stride, quality_factor):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeRGBA(rgb, unused1, unused2, width, height, stride, quality_factor)
+
+def wrap_WebPEncodeBGRA(rgb, unused1, unused2, width, height, stride, quality_factor):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeBGRA(rgb, unused1, unused2, width, height, stride, quality_factor)
+
+def wrap_WebPEncodeLosslessRGB(rgb, unused1, unused2, width, height, stride):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeLosslessRGB(rgb, unused1, unused2, width, height, stride)
+
+def wrap_WebPEncodeLosslessBGR(rgb, unused1, unused2, width, height, stride):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeLosslessBGR(rgb, unused1, unused2, width, height, stride)
+
+def wrap_WebPEncodeLosslessRGBA(rgb, unused1, unused2, width, height, stride):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeLosslessRGBA(rgb, unused1, unused2, width, height, stride)
+
+def wrap_WebPEncodeLosslessBGRA(rgb, unused1, unused2, width, height, stride):
+ """private, do not call directly."""
+ return _libwebp.wrap_WebPEncodeLosslessBGRA(rgb, unused1, unused2, width, height, stride)
+
+_UNUSED = 1
+
+
+def WebPEncodeRGB(rgb, width, height, stride, quality_factor):
+ """WebPEncodeRGB(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp"""
+ webp = wrap_WebPEncodeRGB(
+ rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeRGBA(rgb, width, height, stride, quality_factor):
+ """WebPEncodeRGBA(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp"""
+ webp = wrap_WebPEncodeRGBA(
+ rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeBGR(rgb, width, height, stride, quality_factor):
+ """WebPEncodeBGR(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp"""
+ webp = wrap_WebPEncodeBGR(
+ rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeBGRA(rgb, width, height, stride, quality_factor):
+ """WebPEncodeBGRA(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp"""
+ webp = wrap_WebPEncodeBGRA(
+ rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeLosslessRGB(rgb, width, height, stride):
+ """WebPEncodeLosslessRGB(uint8_t rgb, int width, int height, int stride) -> lossless_webp"""
+ webp = wrap_WebPEncodeLosslessRGB(rgb, _UNUSED, _UNUSED, width, height, stride)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeLosslessRGBA(rgb, width, height, stride):
+ """WebPEncodeLosslessRGBA(uint8_t rgb, int width, int height, int stride) -> lossless_webp"""
+ webp = wrap_WebPEncodeLosslessRGBA(rgb, _UNUSED, _UNUSED, width, height, stride)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeLosslessBGR(rgb, width, height, stride):
+ """WebPEncodeLosslessBGR(uint8_t rgb, int width, int height, int stride) -> lossless_webp"""
+ webp = wrap_WebPEncodeLosslessBGR(rgb, _UNUSED, _UNUSED, width, height, stride)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+
+def WebPEncodeLosslessBGRA(rgb, width, height, stride):
+ """WebPEncodeLosslessBGRA(uint8_t rgb, int width, int height, int stride) -> lossless_webp"""
+ webp = wrap_WebPEncodeLosslessBGRA(rgb, _UNUSED, _UNUSED, width, height, stride)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+
+# This file is compatible with both classic and new-style classes.
+
+
diff --git a/swig/libwebp.swig b/swig/libwebp.swig
new file mode 100644
index 0000000..ca38298
--- /dev/null
+++ b/swig/libwebp.swig
@@ -0,0 +1,438 @@
+// Copyright 2011 Google Inc.
+//
+// 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.
+// -----------------------------------------------------------------------------
+//
+// libwebp swig interface definition
+//
+// Author: James Zern (jzern@google.com)
+
+/*
+ Go bindings:
+ $ swig -go \
+ -outdir . \
+ -o libwebp_go_wrap.c libwebp.swig
+
+ Java bindings:
+ $ mkdir -p java/com/google/webp
+ $ swig -java \
+ -package com.google.webp \
+ -outdir java/com/google/webp \
+ -o libwebp_java_wrap.c libwebp.swig
+
+ Python bindings:
+ $ swig -python \
+ -outdir . \
+ -o libwebp_python_wrap.c libwebp.swig
+*/
+
+#ifdef SWIGPYTHON
+%module(package="com.google.webp") libwebp
+%begin %{
+#define SWIG_PYTHON_STRICT_BYTE_CHAR
+%}
+#else
+%module libwebp
+#endif /* SWIGPYTHON */
+
+%include "constraints.i"
+%include "typemaps.i"
+
+#ifdef SWIGGO
+%apply (char* STRING, size_t LENGTH) { (const uint8_t* data, size_t data_size) }
+
+%rename(wrapped_WebPGetInfo) WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+#endif /* SWIGGO */
+
+#ifdef SWIGJAVA
+%include "arrays_java.i";
+%include "enums.swg" /*NB: requires JDK-1.5+
+ See: http://www.swig.org/Doc1.3/Java.html#enumerations */
+
+// map uint8_t* such that a byte[] is used
+%{
+#include "webp/types.h"
+%}
+// from arrays_java.i (signed char)
+JAVA_ARRAYS_DECL(uint8_t, jbyte, Byte, Uint8)
+JAVA_ARRAYS_IMPL(uint8_t, jbyte, Byte, Uint8)
+JAVA_ARRAYS_TYPEMAPS(uint8_t, byte, jbyte, Uint8, "[B")
+%apply uint8_t[] { uint8_t* }
+#endif /* SWIGJAVA */
+
+#ifdef SWIGPYTHON
+%apply (char* STRING, size_t LENGTH) { (const uint8_t* data, size_t data_size) }
+%typemap(out) uint8_t* {
+ $result = PyString_FromStringAndSize(
+ (const char*)$1,
+ ($1 == NULL) ? 0 : ReturnedBufferSize("$symname", arg3, arg4));
+}
+
+%typemap (in) const uint8_t* rgb (Py_buffer rgb_buffer) {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer($input, (const void**)(&$1), &unused);
+ if (!PyObject_CheckBuffer($input)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method '$symname', argument $argnum"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer($input, &rgb_buffer, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method '$symname', unable to get buffer view");
+ }
+ $1 = ($1_ltype)rgb_buffer.buf;
+}
+
+%typemap(freearg) const uint8_t* rgb {
+ PyBuffer_Release(&rgb_buffer$argnum);
+}
+
+%define DECODE_AUTODOC(func)
+%feature("autodoc", #func "(uint8_t data) -> (rgb, width, height)") func;
+%enddef
+
+%feature("autodoc", "1");
+DECODE_AUTODOC(WebPDecodeRGB);
+DECODE_AUTODOC(WebPDecodeRGBA);
+DECODE_AUTODOC(WebPDecodeARGB);
+DECODE_AUTODOC(WebPDecodeBGR);
+DECODE_AUTODOC(WebPDecodeBGRA);
+%feature("autodoc", "WebPGetInfo(uint8_t data) -> (width, height)") WebPGetInfo;
+#endif /* SWIGPYTHON */
+
+//------------------------------------------------------------------------------
+// Decoder specific
+
+%apply int* OUTPUT { int* width, int* height }
+
+int WebPGetDecoderVersion(void);
+int WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+#if defined(SWIGJAVA) || defined(SWIGPYTHON)
+
+// free the buffer returned by these functions after copying into
+// the native type
+%newobject WebPDecodeRGB;
+%newobject WebPDecodeRGBA;
+%newobject WebPDecodeARGB;
+%newobject WebPDecodeBGR;
+%newobject WebPDecodeBGRA;
+%typemap(newfree) uint8_t* "free($1);"
+
+uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+#endif /* SWIGJAVA || SWIGPYTHON */
+
+//------------------------------------------------------------------------------
+// Encoder specific
+
+#if defined(SWIGJAVA) || defined(SWIGPYTHON)
+
+int WebPGetEncoderVersion(void);
+
+#endif /* SWIGJAVA || SWIGPYTHON */
+
+//------------------------------------------------------------------------------
+// Wrapper code additions
+
+%{
+#include "webp/decode.h"
+#include "webp/encode.h"
+%}
+
+#ifdef SWIGJAVA
+%{
+#define FillMeInAsSizeCannotBeDeterminedAutomatically \
+ (result ? (jint)ReturnedBufferSize(__FUNCTION__, arg3, arg4) : 0)
+%}
+#endif /* SWIGJAVA */
+
+#if defined(SWIGJAVA) || defined(SWIGPYTHON)
+%{
+static size_t ReturnedBufferSize(
+ const char* function, int* width, int* height) {
+ static const struct sizemap {
+ const char* function;
+ int size_multiplier;
+ } size_map[] = {
+#ifdef SWIGJAVA
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 },
+#endif
+#ifdef SWIGPYTHON
+ { "WebPDecodeRGB", 3 },
+ { "WebPDecodeRGBA", 4 },
+ { "WebPDecodeARGB", 4 },
+ { "WebPDecodeBGR", 3 },
+ { "WebPDecodeBGRA", 4 },
+ { "wrap_WebPEncodeRGB", 1 },
+ { "wrap_WebPEncodeBGR", 1 },
+ { "wrap_WebPEncodeRGBA", 1 },
+ { "wrap_WebPEncodeBGRA", 1 },
+ { "wrap_WebPEncodeLosslessRGB", 1 },
+ { "wrap_WebPEncodeLosslessBGR", 1 },
+ { "wrap_WebPEncodeLosslessRGBA", 1 },
+ { "wrap_WebPEncodeLosslessBGRA", 1 },
+#endif
+ { NULL, 0 }
+ };
+ const struct sizemap* p;
+ size_t size = 0;
+
+ for (p = size_map; p->function; ++p) {
+ if (!strcmp(function, p->function)) {
+ size = *width * *height * p->size_multiplier;
+ break;
+ }
+ }
+
+ return size;
+}
+%}
+
+%{
+typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ uint8_t** output);
+
+static uint8_t* EncodeLossy(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor,
+ WebPEncodeFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size =
+ encfn(rgb, width, height, stride, quality_factor, &output);
+ // the values of following two will be interpreted by ReturnedBufferSize()
+ // as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+
+static uint8_t* EncodeLossless(const uint8_t* rgb,
+ int width, int height, int stride,
+ WebPEncodeLosslessFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size = encfn(rgb, width, height, stride, &output);
+ // the values of the following two will be interpreted by
+ // ReturnedBufferSize() as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+%}
+
+#endif /* SWIGJAVA || SWIGPYTHON */
+
+//------------------------------------------------------------------------------
+// libwebp/encode wrapper functions
+
+#if defined(SWIGJAVA) || defined(SWIGPYTHON)
+
+%apply int* INPUT { int* unused1, int* unused2 }
+%apply int* OUTPUT { int* output_size }
+
+// free the buffer returned by these functions after copying into
+// the native type
+%newobject wrap_WebPEncodeRGB;
+%newobject wrap_WebPEncodeBGR;
+%newobject wrap_WebPEncodeRGBA;
+%newobject wrap_WebPEncodeBGRA;
+%newobject wrap_WebPEncodeLosslessRGB;
+%newobject wrap_WebPEncodeLosslessBGR;
+%newobject wrap_WebPEncodeLosslessRGBA;
+%newobject wrap_WebPEncodeLosslessBGRA;
+
+#ifdef SWIGJAVA
+// There's no reason to call these directly
+%javamethodmodifiers wrap_WebPEncodeRGB "private";
+%javamethodmodifiers wrap_WebPEncodeBGR "private";
+%javamethodmodifiers wrap_WebPEncodeRGBA "private";
+%javamethodmodifiers wrap_WebPEncodeBGRA "private";
+%javamethodmodifiers wrap_WebPEncodeLosslessRGB "private";
+%javamethodmodifiers wrap_WebPEncodeLosslessBGR "private";
+%javamethodmodifiers wrap_WebPEncodeLosslessRGBA "private";
+%javamethodmodifiers wrap_WebPEncodeLosslessBGRA "private";
+#endif /* SWIGJAVA */
+
+#ifdef SWIGPYTHON
+// This autodoc will serve as a catch-all for wrap_*.
+%feature("autodoc", "private, do not call directly.");
+#endif
+
+%inline %{
+// Changes the return type of WebPEncode* to more closely match Decode*.
+// This also makes it easier to wrap the output buffer in a native type rather
+// than dealing with the return pointer.
+// The additional parameters are to allow reuse of ReturnedBufferSize(),
+// unused2 and output_size will be used in this case.
+#define LOSSY_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride, float quality_factor) { \
+ return EncodeLossy(rgb, width, height, stride, quality_factor, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSY_WRAPPER(WebPEncodeRGB)
+LOSSY_WRAPPER(WebPEncodeBGR)
+LOSSY_WRAPPER(WebPEncodeRGBA)
+LOSSY_WRAPPER(WebPEncodeBGRA)
+
+#undef LOSSY_WRAPPER
+
+#define LOSSLESS_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride) { \
+ return EncodeLossless(rgb, width, height, stride, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGB)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGR)
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA)
+
+#undef LOSSLESS_WRAPPER
+
+%}
+
+#endif /* SWIGJAVA || SWIGPYTHON */
+
+//------------------------------------------------------------------------------
+// Language specific
+
+#ifdef SWIGGO
+%insert(go_wrapper) %{
+
+// WebPGetInfo has 2 output parameters, provide a version in the more natural
+// go idiom:
+func WebPGetInfo(webp []byte) (ok bool, width int, height int) {
+ w := []int{0}
+ h := []int{0}
+ ok = Wrapped_WebPGetInfo(string(webp), w, h) != 0
+ width = w[0]
+ height = h[0]
+ return
+}
+
+%}
+#endif /* SWIGGO */
+
+#ifdef SWIGJAVA
+%{
+/* Work around broken gcj jni.h */
+#ifdef __GCJ_JNI_H__
+# undef JNIEXPORT
+# define JNIEXPORT
+# undef JNICALL
+# define JNICALL
+#endif
+%}
+
+%pragma(java) modulecode=%{
+ private static final int UNUSED = 1;
+ private static int outputSize[] = { 0 };
+%}
+
+
+%define CALL_ENCODE_LOSSY_WRAPPER(func)
+%pragma(java) modulecode=%{
+ public static byte[] func(
+ byte[] rgb, int width, int height, int stride, float quality_factor) {
+ return wrap_##func(
+ rgb, UNUSED, UNUSED, outputSize, width, height, stride, quality_factor);
+ }
+%}
+%enddef
+
+%define CALL_ENCODE_LOSSLESS_WRAPPER(func)
+%pragma(java) modulecode=%{
+ public static byte[] func(
+ byte[] rgb, int width, int height, int stride) {
+ return wrap_##func(
+ rgb, UNUSED, UNUSED, outputSize, width, height, stride);
+ }
+%}
+%enddef
+
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGB)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGBA)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGR)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGRA)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGB)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGR)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA)
+#endif /* SWIGJAVA */
+
+#ifdef SWIGPYTHON
+%pythoncode %{
+_UNUSED = 1
+%}
+
+%define CALL_ENCODE_LOSSY_WRAPPER(func)
+%pythoncode %{
+def func(rgb, width, height, stride, quality_factor):
+ """func(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp"""
+ webp = wrap_##func(
+ rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+%}
+%enddef
+
+%define CALL_ENCODE_LOSSLESS_WRAPPER(func)
+%pythoncode %{
+def func(rgb, width, height, stride):
+ """func(uint8_t rgb, int width, int height, int stride) -> lossless_webp"""
+ webp = wrap_##func(rgb, _UNUSED, _UNUSED, width, height, stride)
+ if len(webp[0]) == 0:
+ return None
+ return webp[0]
+%}
+%enddef
+
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGB)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGBA)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGR)
+CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGRA)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGB)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGR)
+CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA)
+#endif /* SWIGPYTHON */
diff --git a/swig/libwebp_gc.c b/swig/libwebp_gc.c
new file mode 100644
index 0000000..308b7f8
--- /dev/null
+++ b/swig/libwebp_gc.c
@@ -0,0 +1,52 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.10
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+/* This file should be compiled with 6c/8c. */
+#pragma dynimport _ _ "libwebp_go.so"
+
+#include "runtime.h"
+#include "cgocall.h"
+
+#ifdef _64BIT
+#define SWIG_PARM_SIZE 8
+#else
+#define SWIG_PARM_SIZE 4
+#endif
+
+#pragma dynimport _wrap_WebPGetDecoderVersion _wrap_WebPGetDecoderVersion ""
+extern void (*_wrap_WebPGetDecoderVersion)(void*);
+static void (*x_wrap_WebPGetDecoderVersion)(void*) = _wrap_WebPGetDecoderVersion;
+
+void
+·WebPGetDecoderVersion(struct {
+ uint8 x[SWIG_PARM_SIZE];
+} p)
+
+{
+ runtime·cgocall(x_wrap_WebPGetDecoderVersion, &p);
+}
+
+
+
+#pragma dynimport _wrap_wrapped_WebPGetInfo _wrap_wrapped_WebPGetInfo ""
+extern void (*_wrap_wrapped_WebPGetInfo)(void*);
+static void (*x_wrap_wrapped_WebPGetInfo)(void*) = _wrap_wrapped_WebPGetInfo;
+
+void
+·Wrapped_WebPGetInfo(struct {
+ uint8 x[(2 * SWIG_PARM_SIZE) + (3 * SWIG_PARM_SIZE) + (3 * SWIG_PARM_SIZE) + SWIG_PARM_SIZE];
+} p)
+
+{
+ runtime·cgocall(x_wrap_wrapped_WebPGetInfo, &p);
+}
+
+
+
diff --git a/swig/libwebp_go_wrap.c b/swig/libwebp_go_wrap.c
new file mode 100644
index 0000000..351d523
--- /dev/null
+++ b/swig/libwebp_go_wrap.c
@@ -0,0 +1,274 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.10
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+#define SWIGMODULE libwebp
+/* -----------------------------------------------------------------------------
+ * This section contains generic SWIG labels for method/variable
+ * declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+# define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+# define SWIGINLINE inline
+# else
+# define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+# elif defined(__ICC)
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+#endif
+
+#ifndef SWIG_MSC_UNSUPPRESS_4505
+# if defined(_MSC_VER)
+# pragma warning(disable : 4505) /* unreferenced local function has been removed */
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+# define SWIGUNUSEDPARM(p)
+# else
+# define SWIGUNUSEDPARM(p) p SWIGUNUSED
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# ifndef GCC_HASCLASSVISIBILITY
+# define GCC_HASCLASSVISIBILITY
+# endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT
+# else
+# define SWIGEXPORT __declspec(dllexport)
+# endif
+# else
+# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+# define SWIGEXPORT __attribute__ ((visibility("default")))
+# else
+# define SWIGEXPORT
+# endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# define SWIGSTDCALL __stdcall
+# else
+# define SWIGSTDCALL
+# endif
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+
+
+typedef long long intgo;
+typedef unsigned long long uintgo;
+
+
+
+typedef struct { char *p; intgo n; } _gostring_;
+typedef struct { void* array; intgo len; intgo cap; } _goslice_;
+
+
+
+
+#define swiggo_size_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
+#define swiggo_size_assert(t, n) swiggo_size_assert_eq(sizeof(t), n, swiggo_sizeof_##t##_is_not_##n)
+
+swiggo_size_assert(char, 1)
+swiggo_size_assert(short, 2)
+swiggo_size_assert(int, 4)
+typedef long long swiggo_long_long;
+swiggo_size_assert(swiggo_long_long, 8)
+swiggo_size_assert(float, 4)
+swiggo_size_assert(double, 8)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern void crosscall2(void (*fn)(void *, int), void *, int);
+extern void _cgo_allocate(void *, int);
+extern void _cgo_panic(void *, int);
+#ifdef __cplusplus
+}
+#endif
+
+static void *_swig_goallocate(size_t len) {
+ struct {
+ size_t len;
+ void *ret;
+ } a;
+ a.len = len;
+ crosscall2(_cgo_allocate, &a, (int) sizeof a);
+ return a.ret;
+}
+
+static void _swig_gopanic(const char *p) {
+ struct {
+ const char *p;
+ } a;
+ a.p = p;
+ crosscall2(_cgo_panic, &a, (int) sizeof a);
+}
+
+
+
+
+static _gostring_ _swig_makegostring(const char *p, size_t l) {
+ _gostring_ ret;
+ ret.p = (char*)_swig_goallocate(l + 1);
+ memcpy(ret.p, p, l);
+ ret.n = l;
+ return ret;
+}
+
+#define SWIG_contract_assert(expr, msg) \
+ if (!(expr)) { _swig_gopanic(msg); } else
+
+
+#define SWIG_exception(code, msg) _swig_gopanic(msg)
+
+
+#include "webp/decode.h"
+#include "webp/encode.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+_wrap_WebPGetDecoderVersion(void *swig_v)
+{
+ int result;
+
+ struct swigargs {
+ long : 0;
+ intgo result;
+ } *swig_a = (struct swigargs *) swig_v;
+
+
+ result = (int)WebPGetDecoderVersion();
+ swig_a->result = result;
+}
+
+
+void
+_wrap_wrapped_WebPGetInfo(void *swig_v)
+{
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int temp3 ;
+ int temp4 ;
+ int result;
+
+ struct swigargs {
+ _gostring_ arg1;
+ _goslice_ arg3;
+ _goslice_ arg4;
+ long : 0;
+ intgo result;
+ } *swig_a = (struct swigargs *) swig_v;
+
+
+ arg1 = (uint8_t *)swig_a->arg1.p;
+ arg2 = (size_t)swig_a->arg1.n;
+
+ {
+ if (swig_a->arg3.len == 0) {
+ _swig_gopanic("array must contain at least 1 element");
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (swig_a->arg4.len == 0) {
+ _swig_gopanic("array must contain at least 1 element");
+ }
+ arg4 = &temp4;
+ }
+
+ result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4);
+ swig_a->result = result;
+ {
+ int* a = (int *) swig_a->arg3.array;
+ a[0] = temp3;
+ }
+ {
+ int* a = (int *) swig_a->arg4.array;
+ a[0] = temp4;
+ }
+
+
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/swig/libwebp_java_wrap.c b/swig/libwebp_java_wrap.c
new file mode 100644
index 0000000..c8d4b13
--- /dev/null
+++ b/swig/libwebp_java_wrap.c
@@ -0,0 +1,1765 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.4
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGJAVA
+
+/* -----------------------------------------------------------------------------
+ * This section contains generic SWIG labels for method/variable
+ * declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+# define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+# define SWIGINLINE inline
+# else
+# define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+# elif defined(__ICC)
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+#endif
+
+#ifndef SWIG_MSC_UNSUPPRESS_4505
+# if defined(_MSC_VER)
+# pragma warning(disable : 4505) /* unreferenced local function has been removed */
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+# define SWIGUNUSEDPARM(p)
+# else
+# define SWIGUNUSEDPARM(p) p SWIGUNUSED
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# ifndef GCC_HASCLASSVISIBILITY
+# define GCC_HASCLASSVISIBILITY
+# endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT
+# else
+# define SWIGEXPORT __declspec(dllexport)
+# endif
+# else
+# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+# define SWIGEXPORT __attribute__ ((visibility("default")))
+# else
+# define SWIGEXPORT
+# endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# define SWIGSTDCALL __stdcall
+# else
+# define SWIGSTDCALL
+# endif
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+
+/* Fix for jlong on some versions of gcc on Windows */
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ typedef long long __int64;
+#endif
+
+/* Fix for jlong on 64-bit x86 Solaris */
+#if defined(__x86_64)
+# ifdef _LP64
+# undef _LP64
+# endif
+#endif
+
+#include <jni.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Support for throwing Java exceptions */
+typedef enum {
+ SWIG_JavaOutOfMemoryError = 1,
+ SWIG_JavaIOException,
+ SWIG_JavaRuntimeException,
+ SWIG_JavaIndexOutOfBoundsException,
+ SWIG_JavaArithmeticException,
+ SWIG_JavaIllegalArgumentException,
+ SWIG_JavaNullPointerException,
+ SWIG_JavaDirectorPureVirtual,
+ SWIG_JavaUnknownError
+} SWIG_JavaExceptionCodes;
+
+typedef struct {
+ SWIG_JavaExceptionCodes code;
+ const char *java_exception;
+} SWIG_JavaExceptions_t;
+
+
+static void SWIGUNUSED SWIG_JavaThrowException(JNIEnv *jenv, SWIG_JavaExceptionCodes code, const char *msg) {
+ jclass excep;
+ static const SWIG_JavaExceptions_t java_exceptions[] = {
+ { SWIG_JavaOutOfMemoryError, "java/lang/OutOfMemoryError" },
+ { SWIG_JavaIOException, "java/io/IOException" },
+ { SWIG_JavaRuntimeException, "java/lang/RuntimeException" },
+ { SWIG_JavaIndexOutOfBoundsException, "java/lang/IndexOutOfBoundsException" },
+ { SWIG_JavaArithmeticException, "java/lang/ArithmeticException" },
+ { SWIG_JavaIllegalArgumentException, "java/lang/IllegalArgumentException" },
+ { SWIG_JavaNullPointerException, "java/lang/NullPointerException" },
+ { SWIG_JavaDirectorPureVirtual, "java/lang/RuntimeException" },
+ { SWIG_JavaUnknownError, "java/lang/UnknownError" },
+ { (SWIG_JavaExceptionCodes)0, "java/lang/UnknownError" }
+ };
+ const SWIG_JavaExceptions_t *except_ptr = java_exceptions;
+
+ while (except_ptr->code != code && except_ptr->code)
+ except_ptr++;
+
+ (*jenv)->ExceptionClear(jenv);
+ excep = (*jenv)->FindClass(jenv, except_ptr->java_exception);
+ if (excep)
+ (*jenv)->ThrowNew(jenv, excep, msg);
+}
+
+
+/* Contract support */
+
+#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, msg); return nullreturn; } else
+
+/* Errors in SWIG */
+#define SWIG_UnknownError -1
+#define SWIG_IOError -2
+#define SWIG_RuntimeError -3
+#define SWIG_IndexError -4
+#define SWIG_TypeError -5
+#define SWIG_DivisionByZero -6
+#define SWIG_OverflowError -7
+#define SWIG_SyntaxError -8
+#define SWIG_ValueError -9
+#define SWIG_SystemError -10
+#define SWIG_AttributeError -11
+#define SWIG_MemoryError -12
+#define SWIG_NullReferenceError -13
+
+
+
+
+SWIGINTERN void SWIG_JavaException(JNIEnv *jenv, int code, const char *msg) {
+ SWIG_JavaExceptionCodes exception_code = SWIG_JavaUnknownError;
+ switch(code) {
+ case SWIG_MemoryError:
+ exception_code = SWIG_JavaOutOfMemoryError;
+ break;
+ case SWIG_IOError:
+ exception_code = SWIG_JavaIOException;
+ break;
+ case SWIG_SystemError:
+ case SWIG_RuntimeError:
+ exception_code = SWIG_JavaRuntimeException;
+ break;
+ case SWIG_OverflowError:
+ case SWIG_IndexError:
+ exception_code = SWIG_JavaIndexOutOfBoundsException;
+ break;
+ case SWIG_DivisionByZero:
+ exception_code = SWIG_JavaArithmeticException;
+ break;
+ case SWIG_SyntaxError:
+ case SWIG_ValueError:
+ case SWIG_TypeError:
+ exception_code = SWIG_JavaIllegalArgumentException;
+ break;
+ case SWIG_UnknownError:
+ default:
+ exception_code = SWIG_JavaUnknownError;
+ break;
+ }
+ SWIG_JavaThrowException(jenv, exception_code, msg);
+}
+
+
+#if defined(SWIG_NOINCLUDE) || defined(SWIG_NOARRAYS)
+
+
+int SWIG_JavaArrayInSchar (JNIEnv *jenv, jbyte **jarr, signed char **carr, jbyteArray input);
+void SWIG_JavaArrayArgoutSchar (JNIEnv *jenv, jbyte *jarr, signed char *carr, jbyteArray input);
+jbyteArray SWIG_JavaArrayOutSchar (JNIEnv *jenv, signed char *result, jsize sz);
+
+
+int SWIG_JavaArrayInUchar (JNIEnv *jenv, jshort **jarr, unsigned char **carr, jshortArray input);
+void SWIG_JavaArrayArgoutUchar (JNIEnv *jenv, jshort *jarr, unsigned char *carr, jshortArray input);
+jshortArray SWIG_JavaArrayOutUchar (JNIEnv *jenv, unsigned char *result, jsize sz);
+
+
+int SWIG_JavaArrayInShort (JNIEnv *jenv, jshort **jarr, short **carr, jshortArray input);
+void SWIG_JavaArrayArgoutShort (JNIEnv *jenv, jshort *jarr, short *carr, jshortArray input);
+jshortArray SWIG_JavaArrayOutShort (JNIEnv *jenv, short *result, jsize sz);
+
+
+int SWIG_JavaArrayInUshort (JNIEnv *jenv, jint **jarr, unsigned short **carr, jintArray input);
+void SWIG_JavaArrayArgoutUshort (JNIEnv *jenv, jint *jarr, unsigned short *carr, jintArray input);
+jintArray SWIG_JavaArrayOutUshort (JNIEnv *jenv, unsigned short *result, jsize sz);
+
+
+int SWIG_JavaArrayInInt (JNIEnv *jenv, jint **jarr, int **carr, jintArray input);
+void SWIG_JavaArrayArgoutInt (JNIEnv *jenv, jint *jarr, int *carr, jintArray input);
+jintArray SWIG_JavaArrayOutInt (JNIEnv *jenv, int *result, jsize sz);
+
+
+int SWIG_JavaArrayInUint (JNIEnv *jenv, jlong **jarr, unsigned int **carr, jlongArray input);
+void SWIG_JavaArrayArgoutUint (JNIEnv *jenv, jlong *jarr, unsigned int *carr, jlongArray input);
+jlongArray SWIG_JavaArrayOutUint (JNIEnv *jenv, unsigned int *result, jsize sz);
+
+
+int SWIG_JavaArrayInLong (JNIEnv *jenv, jint **jarr, long **carr, jintArray input);
+void SWIG_JavaArrayArgoutLong (JNIEnv *jenv, jint *jarr, long *carr, jintArray input);
+jintArray SWIG_JavaArrayOutLong (JNIEnv *jenv, long *result, jsize sz);
+
+
+int SWIG_JavaArrayInUlong (JNIEnv *jenv, jlong **jarr, unsigned long **carr, jlongArray input);
+void SWIG_JavaArrayArgoutUlong (JNIEnv *jenv, jlong *jarr, unsigned long *carr, jlongArray input);
+jlongArray SWIG_JavaArrayOutUlong (JNIEnv *jenv, unsigned long *result, jsize sz);
+
+
+int SWIG_JavaArrayInLonglong (JNIEnv *jenv, jlong **jarr, jlong **carr, jlongArray input);
+void SWIG_JavaArrayArgoutLonglong (JNIEnv *jenv, jlong *jarr, jlong *carr, jlongArray input);
+jlongArray SWIG_JavaArrayOutLonglong (JNIEnv *jenv, jlong *result, jsize sz);
+
+
+int SWIG_JavaArrayInFloat (JNIEnv *jenv, jfloat **jarr, float **carr, jfloatArray input);
+void SWIG_JavaArrayArgoutFloat (JNIEnv *jenv, jfloat *jarr, float *carr, jfloatArray input);
+jfloatArray SWIG_JavaArrayOutFloat (JNIEnv *jenv, float *result, jsize sz);
+
+
+int SWIG_JavaArrayInDouble (JNIEnv *jenv, jdouble **jarr, double **carr, jdoubleArray input);
+void SWIG_JavaArrayArgoutDouble (JNIEnv *jenv, jdouble *jarr, double *carr, jdoubleArray input);
+jdoubleArray SWIG_JavaArrayOutDouble (JNIEnv *jenv, double *result, jsize sz);
+
+
+#else
+
+
+/* signed char[] support */
+int SWIG_JavaArrayInSchar (JNIEnv *jenv, jbyte **jarr, signed char **carr, jbyteArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetByteArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (signed char*) calloc(sz, sizeof(signed char));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (signed char)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutSchar (JNIEnv *jenv, jbyte *jarr, signed char *carr, jbyteArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jbyte)carr[i];
+ (*jenv)->ReleaseByteArrayElements(jenv, input, jarr, 0);
+}
+
+jbyteArray SWIG_JavaArrayOutSchar (JNIEnv *jenv, signed char *result, jsize sz) {
+ jbyte *arr;
+ int i;
+ jbyteArray jresult = (*jenv)->NewByteArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetByteArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jbyte)result[i];
+ (*jenv)->ReleaseByteArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* unsigned char[] support */
+int SWIG_JavaArrayInUchar (JNIEnv *jenv, jshort **jarr, unsigned char **carr, jshortArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetShortArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (unsigned char*) calloc(sz, sizeof(unsigned char));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (unsigned char)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutUchar (JNIEnv *jenv, jshort *jarr, unsigned char *carr, jshortArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jshort)carr[i];
+ (*jenv)->ReleaseShortArrayElements(jenv, input, jarr, 0);
+}
+
+jshortArray SWIG_JavaArrayOutUchar (JNIEnv *jenv, unsigned char *result, jsize sz) {
+ jshort *arr;
+ int i;
+ jshortArray jresult = (*jenv)->NewShortArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetShortArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jshort)result[i];
+ (*jenv)->ReleaseShortArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* short[] support */
+int SWIG_JavaArrayInShort (JNIEnv *jenv, jshort **jarr, short **carr, jshortArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetShortArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (short*) calloc(sz, sizeof(short));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (short)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutShort (JNIEnv *jenv, jshort *jarr, short *carr, jshortArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jshort)carr[i];
+ (*jenv)->ReleaseShortArrayElements(jenv, input, jarr, 0);
+}
+
+jshortArray SWIG_JavaArrayOutShort (JNIEnv *jenv, short *result, jsize sz) {
+ jshort *arr;
+ int i;
+ jshortArray jresult = (*jenv)->NewShortArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetShortArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jshort)result[i];
+ (*jenv)->ReleaseShortArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* unsigned short[] support */
+int SWIG_JavaArrayInUshort (JNIEnv *jenv, jint **jarr, unsigned short **carr, jintArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (unsigned short*) calloc(sz, sizeof(unsigned short));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (unsigned short)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutUshort (JNIEnv *jenv, jint *jarr, unsigned short *carr, jintArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jint)carr[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, input, jarr, 0);
+}
+
+jintArray SWIG_JavaArrayOutUshort (JNIEnv *jenv, unsigned short *result, jsize sz) {
+ jint *arr;
+ int i;
+ jintArray jresult = (*jenv)->NewIntArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jint)result[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* int[] support */
+int SWIG_JavaArrayInInt (JNIEnv *jenv, jint **jarr, int **carr, jintArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (int*) calloc(sz, sizeof(int));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (int)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutInt (JNIEnv *jenv, jint *jarr, int *carr, jintArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jint)carr[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, input, jarr, 0);
+}
+
+jintArray SWIG_JavaArrayOutInt (JNIEnv *jenv, int *result, jsize sz) {
+ jint *arr;
+ int i;
+ jintArray jresult = (*jenv)->NewIntArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jint)result[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* unsigned int[] support */
+int SWIG_JavaArrayInUint (JNIEnv *jenv, jlong **jarr, unsigned int **carr, jlongArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (unsigned int*) calloc(sz, sizeof(unsigned int));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (unsigned int)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutUint (JNIEnv *jenv, jlong *jarr, unsigned int *carr, jlongArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jlong)carr[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, input, jarr, 0);
+}
+
+jlongArray SWIG_JavaArrayOutUint (JNIEnv *jenv, unsigned int *result, jsize sz) {
+ jlong *arr;
+ int i;
+ jlongArray jresult = (*jenv)->NewLongArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jlong)result[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* long[] support */
+int SWIG_JavaArrayInLong (JNIEnv *jenv, jint **jarr, long **carr, jintArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (long*) calloc(sz, sizeof(long));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (long)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutLong (JNIEnv *jenv, jint *jarr, long *carr, jintArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jint)carr[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, input, jarr, 0);
+}
+
+jintArray SWIG_JavaArrayOutLong (JNIEnv *jenv, long *result, jsize sz) {
+ jint *arr;
+ int i;
+ jintArray jresult = (*jenv)->NewIntArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jint)result[i];
+ (*jenv)->ReleaseIntArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* unsigned long[] support */
+int SWIG_JavaArrayInUlong (JNIEnv *jenv, jlong **jarr, unsigned long **carr, jlongArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (unsigned long*) calloc(sz, sizeof(unsigned long));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (unsigned long)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutUlong (JNIEnv *jenv, jlong *jarr, unsigned long *carr, jlongArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jlong)carr[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, input, jarr, 0);
+}
+
+jlongArray SWIG_JavaArrayOutUlong (JNIEnv *jenv, unsigned long *result, jsize sz) {
+ jlong *arr;
+ int i;
+ jlongArray jresult = (*jenv)->NewLongArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jlong)result[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* jlong[] support */
+int SWIG_JavaArrayInLonglong (JNIEnv *jenv, jlong **jarr, jlong **carr, jlongArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (jlong*) calloc(sz, sizeof(jlong));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (jlong)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutLonglong (JNIEnv *jenv, jlong *jarr, jlong *carr, jlongArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jlong)carr[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, input, jarr, 0);
+}
+
+jlongArray SWIG_JavaArrayOutLonglong (JNIEnv *jenv, jlong *result, jsize sz) {
+ jlong *arr;
+ int i;
+ jlongArray jresult = (*jenv)->NewLongArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jlong)result[i];
+ (*jenv)->ReleaseLongArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* float[] support */
+int SWIG_JavaArrayInFloat (JNIEnv *jenv, jfloat **jarr, float **carr, jfloatArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetFloatArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (float*) calloc(sz, sizeof(float));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (float)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutFloat (JNIEnv *jenv, jfloat *jarr, float *carr, jfloatArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jfloat)carr[i];
+ (*jenv)->ReleaseFloatArrayElements(jenv, input, jarr, 0);
+}
+
+jfloatArray SWIG_JavaArrayOutFloat (JNIEnv *jenv, float *result, jsize sz) {
+ jfloat *arr;
+ int i;
+ jfloatArray jresult = (*jenv)->NewFloatArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetFloatArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jfloat)result[i];
+ (*jenv)->ReleaseFloatArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+/* double[] support */
+int SWIG_JavaArrayInDouble (JNIEnv *jenv, jdouble **jarr, double **carr, jdoubleArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetDoubleArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (double*) calloc(sz, sizeof(double));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (double)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutDouble (JNIEnv *jenv, jdouble *jarr, double *carr, jdoubleArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jdouble)carr[i];
+ (*jenv)->ReleaseDoubleArrayElements(jenv, input, jarr, 0);
+}
+
+jdoubleArray SWIG_JavaArrayOutDouble (JNIEnv *jenv, double *result, jsize sz) {
+ jdouble *arr;
+ int i;
+ jdoubleArray jresult = (*jenv)->NewDoubleArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetDoubleArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jdouble)result[i];
+ (*jenv)->ReleaseDoubleArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+#endif
+
+
+#include "webp/types.h"
+
+
+int SWIG_JavaArrayInUint8 (JNIEnv *jenv, jbyte **jarr, uint8_t **carr, jbyteArray input);
+void SWIG_JavaArrayArgoutUint8 (JNIEnv *jenv, jbyte *jarr, uint8_t *carr, jbyteArray input);
+jbyteArray SWIG_JavaArrayOutUint8 (JNIEnv *jenv, uint8_t *result, jsize sz);
+
+
+/* uint8_t[] support */
+int SWIG_JavaArrayInUint8 (JNIEnv *jenv, jbyte **jarr, uint8_t **carr, jbyteArray input) {
+ int i;
+ jsize sz;
+ if (!input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array");
+ return 0;
+ }
+ sz = (*jenv)->GetArrayLength(jenv, input);
+ *jarr = (*jenv)->GetByteArrayElements(jenv, input, 0);
+ if (!*jarr)
+ return 0;
+ *carr = (uint8_t*) calloc(sz, sizeof(uint8_t));
+ if (!*carr) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed");
+ return 0;
+ }
+ for (i=0; i<sz; i++)
+ (*carr)[i] = (uint8_t)(*jarr)[i];
+ return 1;
+}
+
+void SWIG_JavaArrayArgoutUint8 (JNIEnv *jenv, jbyte *jarr, uint8_t *carr, jbyteArray input) {
+ int i;
+ jsize sz = (*jenv)->GetArrayLength(jenv, input);
+ for (i=0; i<sz; i++)
+ jarr[i] = (jbyte)carr[i];
+ (*jenv)->ReleaseByteArrayElements(jenv, input, jarr, 0);
+}
+
+jbyteArray SWIG_JavaArrayOutUint8 (JNIEnv *jenv, uint8_t *result, jsize sz) {
+ jbyte *arr;
+ int i;
+ jbyteArray jresult = (*jenv)->NewByteArray(jenv, sz);
+ if (!jresult)
+ return NULL;
+ arr = (*jenv)->GetByteArrayElements(jenv, jresult, 0);
+ if (!arr)
+ return NULL;
+ for (i=0; i<sz; i++)
+ arr[i] = (jbyte)result[i];
+ (*jenv)->ReleaseByteArrayElements(jenv, jresult, arr, 0);
+ return jresult;
+}
+
+
+#include "webp/decode.h"
+#include "webp/encode.h"
+
+
+#define FillMeInAsSizeCannotBeDeterminedAutomatically \
+ (result ? (jint)ReturnedBufferSize(__FUNCTION__, arg3, arg4) : 0)
+
+
+static size_t ReturnedBufferSize(
+ const char* function, int* width, int* height) {
+ static const struct sizemap {
+ const char* function;
+ int size_multiplier;
+ } size_map[] = {
+#ifdef SWIGJAVA
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 },
+#endif
+#ifdef SWIGPYTHON
+ { "WebPDecodeRGB", 3 },
+ { "WebPDecodeRGBA", 4 },
+ { "WebPDecodeARGB", 4 },
+ { "WebPDecodeBGR", 3 },
+ { "WebPDecodeBGRA", 4 },
+ { "wrap_WebPEncodeRGB", 1 },
+ { "wrap_WebPEncodeBGR", 1 },
+ { "wrap_WebPEncodeRGBA", 1 },
+ { "wrap_WebPEncodeBGRA", 1 },
+ { "wrap_WebPEncodeLosslessRGB", 1 },
+ { "wrap_WebPEncodeLosslessBGR", 1 },
+ { "wrap_WebPEncodeLosslessRGBA", 1 },
+ { "wrap_WebPEncodeLosslessBGRA", 1 },
+#endif
+ { NULL, 0 }
+ };
+ const struct sizemap* p;
+ size_t size = 0;
+
+ for (p = size_map; p->function; ++p) {
+ if (!strcmp(function, p->function)) {
+ size = *width * *height * p->size_multiplier;
+ break;
+ }
+ }
+
+ return size;
+}
+
+
+typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ uint8_t** output);
+
+static uint8_t* EncodeLossy(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor,
+ WebPEncodeFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size =
+ encfn(rgb, width, height, stride, quality_factor, &output);
+ // the values of following two will be interpreted by ReturnedBufferSize()
+ // as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+
+static uint8_t* EncodeLossless(const uint8_t* rgb,
+ int width, int height, int stride,
+ WebPEncodeLosslessFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size = encfn(rgb, width, height, stride, &output);
+ // the values of the following two will be interpreted by
+ // ReturnedBufferSize() as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+
+
+// Changes the return type of WebPEncode* to more closely match Decode*.
+// This also makes it easier to wrap the output buffer in a native type rather
+// than dealing with the return pointer.
+// The additional parameters are to allow reuse of ReturnedBufferSize(),
+// unused2 and output_size will be used in this case.
+#define LOSSY_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride, float quality_factor) { \
+ return EncodeLossy(rgb, width, height, stride, quality_factor, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSY_WRAPPER(WebPEncodeRGB)
+LOSSY_WRAPPER(WebPEncodeBGR)
+LOSSY_WRAPPER(WebPEncodeRGBA)
+LOSSY_WRAPPER(WebPEncodeBGRA)
+
+#undef LOSSY_WRAPPER
+
+#define LOSSLESS_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride) { \
+ return EncodeLossless(rgb, width, height, stride, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGB)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGR)
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA)
+
+#undef LOSSLESS_WRAPPER
+
+
+
+/* Work around broken gcj jni.h */
+#ifdef __GCJ_JNI_H__
+# undef JNIEXPORT
+# define JNIEXPORT
+# undef JNICALL
+# define JNICALL
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetDecoderVersion(JNIEnv *jenv, jclass jcls) {
+ jint jresult = 0 ;
+ int result;
+
+ (void)jenv;
+ (void)jcls;
+ result = (int)WebPGetDecoderVersion();
+ jresult = (jint)result;
+ return jresult;
+}
+
+
+SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetInfo(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jint jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ int result;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = (jint)result;
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (uint8_t *)WebPDecodeRGB((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (uint8_t *)WebPDecodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeARGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (uint8_t *)WebPDecodeARGB((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (uint8_t *)WebPDecodeBGR((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ jbyte *jarr1 ;
+ int temp3 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (size_t)jarg2;
+ {
+ if (!jarg3) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg3 = &temp3;
+ }
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ result = (uint8_t *)WebPDecodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp3;
+ (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue);
+ }
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetEncoderVersion(JNIEnv *jenv, jclass jcls) {
+ jint jresult = 0 ;
+ int result;
+
+ (void)jenv;
+ (void)jcls;
+ result = (int)WebPGetEncoderVersion();
+ jresult = (jint)result;
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ arg8 = (float)jarg8;
+ result = (uint8_t *)wrap_WebPEncodeRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ arg8 = (float)jarg8;
+ result = (uint8_t *)wrap_WebPEncodeBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ arg8 = (float)jarg8;
+ result = (uint8_t *)wrap_WebPEncodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ arg8 = (float)jarg8;
+ result = (uint8_t *)wrap_WebPEncodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ result = (uint8_t *)wrap_WebPEncodeLosslessRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ result = (uint8_t *)wrap_WebPEncodeLosslessBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ result = (uint8_t *)wrap_WebPEncodeLosslessRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) {
+ jbyteArray jresult = 0 ;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ jbyte *jarr1 ;
+ int temp4 ;
+ uint8_t *result = 0 ;
+
+ (void)jenv;
+ (void)jcls;
+ if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0;
+ arg2 = (int *)&jarg2;
+ arg3 = (int *)&jarg3;
+ {
+ if (!jarg4) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
+ return 0;
+ }
+ if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
+ return 0;
+ }
+ arg4 = &temp4;
+ }
+ arg5 = (int)jarg5;
+ arg6 = (int)jarg6;
+ arg7 = (int)jarg7;
+ result = (uint8_t *)wrap_WebPEncodeLosslessBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically);
+ SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1);
+ {
+ jint jvalue = (jint)temp4;
+ (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue);
+ }
+ free(arg1);
+
+
+
+ free(result);
+ return jresult;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/swig/libwebp_python_wrap.c b/swig/libwebp_python_wrap.c
new file mode 100644
index 0000000..3aa2728
--- /dev/null
+++ b/swig/libwebp_python_wrap.c
@@ -0,0 +1,5628 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 3.0.12
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIG_PYTHON_STRICT_BYTE_CHAR
+
+
+
+#ifndef SWIGPYTHON
+#define SWIGPYTHON
+#endif
+
+#define SWIG_PYTHON_DIRECTOR_NO_VTABLE
+
+/* -----------------------------------------------------------------------------
+ * This section contains generic SWIG labels for method/variable
+ * declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+# define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+# define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+# define SWIGINLINE inline
+# else
+# define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+# elif defined(__ICC)
+# define SWIGUNUSED __attribute__ ((__unused__))
+# else
+# define SWIGUNUSED
+# endif
+#endif
+
+#ifndef SWIG_MSC_UNSUPPRESS_4505
+# if defined(_MSC_VER)
+# pragma warning(disable : 4505) /* unreferenced local function has been removed */
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+# define SWIGUNUSEDPARM(p)
+# else
+# define SWIGUNUSEDPARM(p) p SWIGUNUSED
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if defined(__GNUC__)
+# if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# ifndef GCC_HASCLASSVISIBILITY
+# define GCC_HASCLASSVISIBILITY
+# endif
+# endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT
+# else
+# define SWIGEXPORT __declspec(dllexport)
+# endif
+# else
+# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+# define SWIGEXPORT __attribute__ ((visibility("default")))
+# else
+# define SWIGEXPORT
+# endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# define SWIGSTDCALL __stdcall
+# else
+# define SWIGSTDCALL
+# endif
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */
+#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES)
+# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#endif
+
+/* Intel's compiler complains if a variable which was never initialised is
+ * cast to void, which is a common idiom which we use to indicate that we
+ * are aware a variable isn't used. So we just silence that warning.
+ * See: https://github.com/swig/swig/issues/192 for more discussion.
+ */
+#ifdef __INTEL_COMPILER
+# pragma warning disable 592
+#endif
+
+
+#if defined(_DEBUG) && defined(SWIG_PYTHON_INTERPRETER_NO_DEBUG)
+/* Use debug wrappers with the Python release dll */
+# undef _DEBUG
+# include <Python.h>
+# define _DEBUG
+#else
+# include <Python.h>
+#endif
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic C API SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+ or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "4"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+ You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+ creating a static or dynamic library from the SWIG runtime code.
+ In 99.9% of the cases, SWIG just needs to declare them as 'static'.
+
+ But only do this if strictly necessary, ie, if you have problems
+ with your compiler or suchlike.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/* Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN 0x1
+#define SWIG_CAST_NEW_MEMORY 0x2
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN 0x1
+
+
+/*
+ Flags/methods for returning states.
+
+ The SWIG conversion methods, as ConvertPtr, return an integer
+ that tells if the conversion was successful or not. And if not,
+ an error code can be returned (see swigerrors.swg for the codes).
+
+ Use the following macros/flags to set or process the returning
+ states.
+
+ In old versions of SWIG, code such as the following was usually written:
+
+ if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+ // success code
+ } else {
+ //fail code
+ }
+
+ Now you can be more explicit:
+
+ int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+ if (SWIG_IsOK(res)) {
+ // success code
+ } else {
+ // fail code
+ }
+
+ which is the same really, but now you can also do
+
+ Type *ptr;
+ int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+ if (SWIG_IsOK(res)) {
+ // success code
+ if (SWIG_IsNewObj(res) {
+ ...
+ delete *ptr;
+ } else {
+ ...
+ }
+ } else {
+ // fail code
+ }
+
+ I.e., now SWIG_ConvertPtr can return new objects and you can
+ identify the case and take care of the deallocation. Of course that
+ also requires SWIG_ConvertPtr to return new result values, such as
+
+ int SWIG_ConvertPtr(obj, ptr,...) {
+ if (<obj is ok>) {
+ if (<need new object>) {
+ *ptr = <ptr to new allocated object>;
+ return SWIG_NEWOBJ;
+ } else {
+ *ptr = <ptr to old object>;
+ return SWIG_OLDOBJ;
+ }
+ } else {
+ return SWIG_BADOBJ;
+ }
+ }
+
+ Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+ more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+ SWIG errors code.
+
+ Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+ allows to return the 'cast rank', for example, if you have this
+
+ int food(double)
+ int fooi(int);
+
+ and you call
+
+ food(1) // cast rank '1' (1 -> 1.0)
+ fooi(1) // cast rank '0'
+
+ just use the SWIG_AddCast()/SWIG_CheckState()
+*/
+
+#define SWIG_OK (0)
+#define SWIG_ERROR (-1)
+#define SWIG_IsOK(r) (r >= 0)
+#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError)
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ (SWIG_ERROR)
+#define SWIG_OLDOBJ (SWIG_OK)
+#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+# ifndef SWIG_TypeRank
+# define SWIG_TypeRank unsigned long
+# endif
+# ifndef SWIG_MAXCASTRANK /* Default cast allowed */
+# define SWIG_MAXCASTRANK (2)
+# endif
+# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1)
+# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) {
+ return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) {
+ return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0;
+}
+#else /* no cast-rank mode */
+# define SWIG_AddCast(r) (r)
+# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *, int *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store information on one type */
+typedef struct swig_type_info {
+ const char *name; /* mangled name of this type */
+ const char *str; /* human readable name of this type */
+ swig_dycast_func dcast; /* dynamic cast function down a hierarchy */
+ struct swig_cast_info *cast; /* linked list of types that can cast into this type */
+ void *clientdata; /* language specific type data */
+ int owndata; /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+ swig_type_info *type; /* pointer to type that is equivalent to this type */
+ swig_converter_func converter; /* function to cast the void pointers */
+ struct swig_cast_info *next; /* pointer to next cast in linked list */
+ struct swig_cast_info *prev; /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+ swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */
+ size_t size; /* Number of types in this module */
+ struct swig_module_info *next; /* Pointer to next element in circularly linked list */
+ swig_type_info **type_initial; /* Array of initially generated type structures */
+ swig_cast_info **cast_initial; /* Array of initially generated casting structures */
+ void *clientdata; /* Language specific module data */
+} swig_module_info;
+
+/*
+ Compare two type names skipping the space characters, therefore
+ "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+ Return 0 when the two name types are equivalent, as in
+ strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+ const char *f2, const char *l2) {
+ for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+ while ((*f1 == ' ') && (f1 != l1)) ++f1;
+ while ((*f2 == ' ') && (f2 != l2)) ++f2;
+ if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+ }
+ return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+ Check type equivalence in a name list like <name1>|<name2>|...
+ Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCmp(const char *nb, const char *tb) {
+ int equiv = 1;
+ const char* te = tb + strlen(tb);
+ const char* ne = nb;
+ while (equiv != 0 && *ne) {
+ for (nb = ne; *ne; ++ne) {
+ if (*ne == '|') break;
+ }
+ equiv = SWIG_TypeNameComp(nb, ne, tb, te);
+ if (*ne) ++ne;
+ }
+ return equiv;
+}
+
+/*
+ Check type equivalence in a name list like <name1>|<name2>|...
+ Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+ return SWIG_TypeCmp(nb, tb) == 0 ? 1 : 0;
+}
+
+/*
+ Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+ if (ty) {
+ swig_cast_info *iter = ty->cast;
+ while (iter) {
+ if (strcmp(iter->type->name, c) == 0) {
+ if (iter == ty->cast)
+ return iter;
+ /* Move iter to the top of the linked list */
+ iter->prev->next = iter->next;
+ if (iter->next)
+ iter->next->prev = iter->prev;
+ iter->next = ty->cast;
+ iter->prev = 0;
+ if (ty->cast) ty->cast->prev = iter;
+ ty->cast = iter;
+ return iter;
+ }
+ iter = iter->next;
+ }
+ }
+ return 0;
+}
+
+/*
+ Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) {
+ if (ty) {
+ swig_cast_info *iter = ty->cast;
+ while (iter) {
+ if (iter->type == from) {
+ if (iter == ty->cast)
+ return iter;
+ /* Move iter to the top of the linked list */
+ iter->prev->next = iter->next;
+ if (iter->next)
+ iter->next->prev = iter->prev;
+ iter->next = ty->cast;
+ iter->prev = 0;
+ if (ty->cast) ty->cast->prev = iter;
+ ty->cast = iter;
+ return iter;
+ }
+ iter = iter->next;
+ }
+ }
+ return 0;
+}
+
+/*
+ Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) {
+ return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory);
+}
+
+/*
+ Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+ swig_type_info *lastty = ty;
+ if (!ty || !ty->dcast) return ty;
+ while (ty && (ty->dcast)) {
+ ty = (*ty->dcast)(ptr);
+ if (ty) lastty = ty;
+ }
+ return lastty;
+}
+
+/*
+ Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+ return ty->name;
+}
+
+/*
+ Return the pretty name associated with this type,
+ that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+ /* The "str" field contains the equivalent pretty names of the
+ type, separated by vertical-bar characters. We choose
+ to print the last name, as it is often (?) the most
+ specific. */
+ if (!type) return NULL;
+ if (type->str != NULL) {
+ const char *last_name = type->str;
+ const char *s;
+ for (s = type->str; *s; s++)
+ if (*s == '|') last_name = s+1;
+ return last_name;
+ }
+ else
+ return type->name;
+}
+
+/*
+ Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+ swig_cast_info *cast = ti->cast;
+ /* if (ti->clientdata == clientdata) return; */
+ ti->clientdata = clientdata;
+
+ while (cast) {
+ if (!cast->converter) {
+ swig_type_info *tc = cast->type;
+ if (!tc->clientdata) {
+ SWIG_TypeClientData(tc, clientdata);
+ }
+ }
+ cast = cast->next;
+ }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+ SWIG_TypeClientData(ti, clientdata);
+ ti->owndata = 1;
+}
+
+/*
+ Search for a swig_type_info structure only by mangled name
+ Search is a O(log #types)
+
+ We start searching at module start, and finish searching when start == end.
+ Note: if start == end at the beginning of the function, we go all the way around
+ the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start,
+ swig_module_info *end,
+ const char *name) {
+ swig_module_info *iter = start;
+ do {
+ if (iter->size) {
+ size_t l = 0;
+ size_t r = iter->size - 1;
+ do {
+ /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+ size_t i = (l + r) >> 1;
+ const char *iname = iter->types[i]->name;
+ if (iname) {
+ int compare = strcmp(name, iname);
+ if (compare == 0) {
+ return iter->types[i];
+ } else if (compare < 0) {
+ if (i) {
+ r = i - 1;
+ } else {
+ break;
+ }
+ } else if (compare > 0) {
+ l = i + 1;
+ }
+ } else {
+ break; /* should never happen */
+ }
+ } while (l <= r);
+ }
+ iter = iter->next;
+ } while (iter != end);
+ return 0;
+}
+
+/*
+ Search for a swig_type_info structure for either a mangled name or a human readable name.
+ It first searches the mangled names of the types, which is a O(log #types)
+ If a type is not found it then searches the human readable names, which is O(#types).
+
+ We start searching at module start, and finish searching when start == end.
+ Note: if start == end at the beginning of the function, we go all the way around
+ the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start,
+ swig_module_info *end,
+ const char *name) {
+ /* STEP 1: Search the name field using binary search */
+ swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+ if (ret) {
+ return ret;
+ } else {
+ /* STEP 2: If the type hasn't been found, do a complete search
+ of the str field (the human readable name) */
+ swig_module_info *iter = start;
+ do {
+ size_t i = 0;
+ for (; i < iter->size; ++i) {
+ if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+ return iter->types[i];
+ }
+ iter = iter->next;
+ } while (iter != end);
+ }
+
+ /* neither found a match */
+ return 0;
+}
+
+/*
+ Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+ static const char hex[17] = "0123456789abcdef";
+ const unsigned char *u = (unsigned char *) ptr;
+ const unsigned char *eu = u + sz;
+ for (; u != eu; ++u) {
+ unsigned char uu = *u;
+ *(c++) = hex[(uu & 0xf0) >> 4];
+ *(c++) = hex[uu & 0xf];
+ }
+ return c;
+}
+
+/*
+ Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+ unsigned char *u = (unsigned char *) ptr;
+ const unsigned char *eu = u + sz;
+ for (; u != eu; ++u) {
+ char d = *(c++);
+ unsigned char uu;
+ if ((d >= '0') && (d <= '9'))
+ uu = (unsigned char)((d - '0') << 4);
+ else if ((d >= 'a') && (d <= 'f'))
+ uu = (unsigned char)((d - ('a'-10)) << 4);
+ else
+ return (char *) 0;
+ d = *(c++);
+ if ((d >= '0') && (d <= '9'))
+ uu |= (unsigned char)(d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ uu |= (unsigned char)(d - ('a'-10));
+ else
+ return (char *) 0;
+ *u = uu;
+ }
+ return c;
+}
+
+/*
+ Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+ char *r = buff;
+ if ((2*sizeof(void *) + 2) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,&ptr,sizeof(void *));
+ if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+ strcpy(r,name);
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ *ptr = (void *) 0;
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+ char *r = buff;
+ size_t lname = (name ? strlen(name) : 0);
+ if ((2*sz + 2 + lname) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,ptr,sz);
+ if (lname) {
+ strncpy(r,name,lname+1);
+ } else {
+ *r = 0;
+ }
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ memset(ptr,0,sz);
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Errors in SWIG */
+#define SWIG_UnknownError -1
+#define SWIG_IOError -2
+#define SWIG_RuntimeError -3
+#define SWIG_IndexError -4
+#define SWIG_TypeError -5
+#define SWIG_DivisionByZero -6
+#define SWIG_OverflowError -7
+#define SWIG_SyntaxError -8
+#define SWIG_ValueError -9
+#define SWIG_SystemError -10
+#define SWIG_AttributeError -11
+#define SWIG_MemoryError -12
+#define SWIG_NullReferenceError -13
+
+
+
+/* Compatibility macros for Python 3 */
+#if PY_VERSION_HEX >= 0x03000000
+
+#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type)
+#define PyInt_Check(x) PyLong_Check(x)
+#define PyInt_AsLong(x) PyLong_AsLong(x)
+#define PyInt_FromLong(x) PyLong_FromLong(x)
+#define PyInt_FromSize_t(x) PyLong_FromSize_t(x)
+#define PyString_Check(name) PyBytes_Check(name)
+#define PyString_FromString(x) PyUnicode_FromString(x)
+#define PyString_FromStringAndSize(x, y) PyBytes_FromStringAndSize(x, y)
+#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args)
+#define PyString_AsString(str) PyBytes_AsString(str)
+#define PyString_Size(str) PyBytes_Size(str)
+#define PyString_InternFromString(key) PyUnicode_InternFromString(key)
+#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE
+#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x)
+#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x)
+
+#endif
+
+#ifndef Py_TYPE
+# define Py_TYPE(op) ((op)->ob_type)
+#endif
+
+/* SWIG APIs for compatibility of both Python 2 & 3 */
+
+#if PY_VERSION_HEX >= 0x03000000
+# define SWIG_Python_str_FromFormat PyUnicode_FromFormat
+#else
+# define SWIG_Python_str_FromFormat PyString_FromFormat
+#endif
+
+
+/* Warning: This function will allocate a new string in Python 3,
+ * so please call SWIG_Python_str_DelForPy3(x) to free the space.
+ */
+SWIGINTERN char*
+SWIG_Python_str_AsChar(PyObject *str)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ char *cstr;
+ char *newstr;
+ Py_ssize_t len;
+ str = PyUnicode_AsUTF8String(str);
+ PyBytes_AsStringAndSize(str, &cstr, &len);
+ newstr = (char *) malloc(len+1);
+ memcpy(newstr, cstr, len+1);
+ Py_XDECREF(str);
+ return newstr;
+#else
+ return PyString_AsString(str);
+#endif
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) )
+#else
+# define SWIG_Python_str_DelForPy3(x)
+#endif
+
+
+SWIGINTERN PyObject*
+SWIG_Python_str_FromChar(const char *c)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ return PyUnicode_FromString(c);
+#else
+ return PyString_FromString(c);
+#endif
+}
+
+/* Add PyOS_snprintf for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM)
+# define PyOS_snprintf _snprintf
+# else
+# define PyOS_snprintf snprintf
+# endif
+#endif
+
+/* A crude PyString_FromFormat implementation for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+
+#ifndef SWIG_PYBUFFER_SIZE
+# define SWIG_PYBUFFER_SIZE 1024
+#endif
+
+static PyObject *
+PyString_FromFormat(const char *fmt, ...) {
+ va_list ap;
+ char buf[SWIG_PYBUFFER_SIZE * 2];
+ int res;
+ va_start(ap, fmt);
+ res = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf);
+}
+#endif
+
+#ifndef PyObject_DEL
+# define PyObject_DEL PyObject_Del
+#endif
+
+/* A crude PyExc_StopIteration exception for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+# ifndef PyExc_StopIteration
+# define PyExc_StopIteration PyExc_RuntimeError
+# endif
+# ifndef PyObject_GenericGetAttr
+# define PyObject_GenericGetAttr 0
+# endif
+#endif
+
+/* Py_NotImplemented is defined in 2.1 and up. */
+#if PY_VERSION_HEX < 0x02010000
+# ifndef Py_NotImplemented
+# define Py_NotImplemented PyExc_RuntimeError
+# endif
+#endif
+
+/* A crude PyString_AsStringAndSize implementation for old Pythons */
+#if PY_VERSION_HEX < 0x02010000
+# ifndef PyString_AsStringAndSize
+# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;}
+# endif
+#endif
+
+/* PySequence_Size for old Pythons */
+#if PY_VERSION_HEX < 0x02000000
+# ifndef PySequence_Size
+# define PySequence_Size PySequence_Length
+# endif
+#endif
+
+/* PyBool_FromLong for old Pythons */
+#if PY_VERSION_HEX < 0x02030000
+static
+PyObject *PyBool_FromLong(long ok)
+{
+ PyObject *result = ok ? Py_True : Py_False;
+ Py_INCREF(result);
+ return result;
+}
+#endif
+
+/* Py_ssize_t for old Pythons */
+/* This code is as recommended by: */
+/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+# define PY_SSIZE_T_MAX INT_MAX
+# define PY_SSIZE_T_MIN INT_MIN
+typedef inquiry lenfunc;
+typedef intargfunc ssizeargfunc;
+typedef intintargfunc ssizessizeargfunc;
+typedef intobjargproc ssizeobjargproc;
+typedef intintobjargproc ssizessizeobjargproc;
+typedef getreadbufferproc readbufferproc;
+typedef getwritebufferproc writebufferproc;
+typedef getsegcountproc segcountproc;
+typedef getcharbufferproc charbufferproc;
+static long PyNumber_AsSsize_t (PyObject *x, void *SWIGUNUSEDPARM(exc))
+{
+ long result = 0;
+ PyObject *i = PyNumber_Int(x);
+ if (i) {
+ result = PyInt_AsLong(i);
+ Py_DECREF(i);
+ }
+ return result;
+}
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+#define PyInt_FromSize_t(x) PyInt_FromLong((long)x)
+#endif
+
+#if PY_VERSION_HEX < 0x02040000
+#define Py_VISIT(op) \
+ do { \
+ if (op) { \
+ int vret = visit((op), arg); \
+ if (vret) \
+ return vret; \
+ } \
+ } while (0)
+#endif
+
+#if PY_VERSION_HEX < 0x02030000
+typedef struct {
+ PyTypeObject type;
+ PyNumberMethods as_number;
+ PyMappingMethods as_mapping;
+ PySequenceMethods as_sequence;
+ PyBufferProcs as_buffer;
+ PyObject *name, *slots;
+} PyHeapTypeObject;
+#endif
+
+#if PY_VERSION_HEX < 0x02030000
+typedef destructor freefunc;
+#endif
+
+#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \
+ (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \
+ (PY_MAJOR_VERSION > 3))
+# define SWIGPY_USE_CAPSULE
+# define SWIGPY_CAPSULE_NAME ((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME)
+#endif
+
+#if PY_VERSION_HEX < 0x03020000
+#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type)
+#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name)
+#define Py_hash_t long
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGRUNTIME PyObject*
+SWIG_Python_ErrorType(int code) {
+ PyObject* type = 0;
+ switch(code) {
+ case SWIG_MemoryError:
+ type = PyExc_MemoryError;
+ break;
+ case SWIG_IOError:
+ type = PyExc_IOError;
+ break;
+ case SWIG_RuntimeError:
+ type = PyExc_RuntimeError;
+ break;
+ case SWIG_IndexError:
+ type = PyExc_IndexError;
+ break;
+ case SWIG_TypeError:
+ type = PyExc_TypeError;
+ break;
+ case SWIG_DivisionByZero:
+ type = PyExc_ZeroDivisionError;
+ break;
+ case SWIG_OverflowError:
+ type = PyExc_OverflowError;
+ break;
+ case SWIG_SyntaxError:
+ type = PyExc_SyntaxError;
+ break;
+ case SWIG_ValueError:
+ type = PyExc_ValueError;
+ break;
+ case SWIG_SystemError:
+ type = PyExc_SystemError;
+ break;
+ case SWIG_AttributeError:
+ type = PyExc_AttributeError;
+ break;
+ default:
+ type = PyExc_RuntimeError;
+ }
+ return type;
+}
+
+
+SWIGRUNTIME void
+SWIG_Python_AddErrorMsg(const char* mesg)
+{
+ PyObject *type = 0;
+ PyObject *value = 0;
+ PyObject *traceback = 0;
+
+ if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback);
+ if (value) {
+ char *tmp;
+ PyObject *old_str = PyObject_Str(value);
+ PyErr_Clear();
+ Py_XINCREF(type);
+
+ PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg);
+ SWIG_Python_str_DelForPy3(tmp);
+ Py_DECREF(old_str);
+ Py_DECREF(value);
+ } else {
+ PyErr_SetString(PyExc_RuntimeError, mesg);
+ }
+}
+
+#if defined(SWIG_PYTHON_NO_THREADS)
+# if defined(SWIG_PYTHON_THREADS)
+# undef SWIG_PYTHON_THREADS
+# endif
+#endif
+#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */
+# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL)
+# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */
+# define SWIG_PYTHON_USE_GIL
+# endif
+# endif
+# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */
+# ifndef SWIG_PYTHON_INITIALIZE_THREADS
+# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads()
+# endif
+# ifdef __cplusplus /* C++ code */
+ class SWIG_Python_Thread_Block {
+ bool status;
+ PyGILState_STATE state;
+ public:
+ void end() { if (status) { PyGILState_Release(state); status = false;} }
+ SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {}
+ ~SWIG_Python_Thread_Block() { end(); }
+ };
+ class SWIG_Python_Thread_Allow {
+ bool status;
+ PyThreadState *save;
+ public:
+ void end() { if (status) { PyEval_RestoreThread(save); status = false; }}
+ SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {}
+ ~SWIG_Python_Thread_Allow() { end(); }
+ };
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block
+# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end()
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow
+# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end()
+# else /* C code */
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure()
+# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block)
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread()
+# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow)
+# endif
+# else /* Old thread way, not implemented, user must provide it */
+# if !defined(SWIG_PYTHON_INITIALIZE_THREADS)
+# define SWIG_PYTHON_INITIALIZE_THREADS
+# endif
+# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK)
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
+# endif
+# if !defined(SWIG_PYTHON_THREAD_END_BLOCK)
+# define SWIG_PYTHON_THREAD_END_BLOCK
+# endif
+# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW)
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW
+# endif
+# if !defined(SWIG_PYTHON_THREAD_END_ALLOW)
+# define SWIG_PYTHON_THREAD_END_ALLOW
+# endif
+# endif
+#else /* No thread support */
+# define SWIG_PYTHON_INITIALIZE_THREADS
+# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
+# define SWIG_PYTHON_THREAD_END_BLOCK
+# define SWIG_PYTHON_THREAD_BEGIN_ALLOW
+# define SWIG_PYTHON_THREAD_END_ALLOW
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Python API portion that goes into the runtime
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Constant declarations
+ * ----------------------------------------------------------------------------- */
+
+/* Constant Types */
+#define SWIG_PY_POINTER 4
+#define SWIG_PY_BINARY 5
+
+/* Constant information structure */
+typedef struct swig_const_info {
+ int type;
+ char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_const_info;
+
+
+/* -----------------------------------------------------------------------------
+ * Wrapper of PyInstanceMethod_New() used in Python 3
+ * It is exported to the generated module, used for -fastproxy
+ * ----------------------------------------------------------------------------- */
+#if PY_VERSION_HEX >= 0x03000000
+SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *func)
+{
+ return PyInstanceMethod_New(func);
+}
+#else
+SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(func))
+{
+ return NULL;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * pyrun.swg
+ *
+ * This file contains the runtime support for Python modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ *
+ * ----------------------------------------------------------------------------- */
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0)
+#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own)
+
+#ifdef SWIGPYTHON_BUILTIN
+#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags)
+#else
+#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags)
+#endif
+
+#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags)
+
+#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty)
+#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src)
+#define swig_owntype int
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type)
+#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata) SWIG_Python_GetModule(clientdata)
+#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer)
+#define SWIG_NewClientData(obj) SwigPyClientData_New(obj)
+
+#define SWIG_SetErrorObj SWIG_Python_SetErrorObj
+#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg
+#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code)
+#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg)
+#define SWIG_fail goto fail
+
+
+/* Runtime API implementation */
+
+/* Error manipulation */
+
+SWIGINTERN void
+SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ PyErr_SetObject(errtype, obj);
+ Py_DECREF(obj);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+}
+
+SWIGINTERN void
+SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ PyErr_SetString(errtype, msg);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+}
+
+#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj)
+
+/* Set a constant value */
+
+#if defined(SWIGPYTHON_BUILTIN)
+
+SWIGINTERN void
+SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) {
+ PyObject *s = PyString_InternFromString(key);
+ PyList_Append(seq, s);
+ Py_DECREF(s);
+}
+
+SWIGINTERN void
+SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) {
+#if PY_VERSION_HEX < 0x02030000
+ PyDict_SetItemString(d, (char *)name, obj);
+#else
+ PyDict_SetItemString(d, name, obj);
+#endif
+ Py_DECREF(obj);
+ if (public_interface)
+ SwigPyBuiltin_AddPublicSymbol(public_interface, name);
+}
+
+#else
+
+SWIGINTERN void
+SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) {
+#if PY_VERSION_HEX < 0x02030000
+ PyDict_SetItemString(d, (char *)name, obj);
+#else
+ PyDict_SetItemString(d, name, obj);
+#endif
+ Py_DECREF(obj);
+}
+
+#endif
+
+/* Append a value to the result obj */
+
+SWIGINTERN PyObject*
+SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) {
+#if !defined(SWIG_PYTHON_OUTPUT_TUPLE)
+ if (!result) {
+ result = obj;
+ } else if (result == Py_None) {
+ Py_DECREF(result);
+ result = obj;
+ } else {
+ if (!PyList_Check(result)) {
+ PyObject *o2 = result;
+ result = PyList_New(1);
+ PyList_SetItem(result, 0, o2);
+ }
+ PyList_Append(result,obj);
+ Py_DECREF(obj);
+ }
+ return result;
+#else
+ PyObject* o2;
+ PyObject* o3;
+ if (!result) {
+ result = obj;
+ } else if (result == Py_None) {
+ Py_DECREF(result);
+ result = obj;
+ } else {
+ if (!PyTuple_Check(result)) {
+ o2 = result;
+ result = PyTuple_New(1);
+ PyTuple_SET_ITEM(result, 0, o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SET_ITEM(o3, 0, obj);
+ o2 = result;
+ result = PySequence_Concat(o2, o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+ return result;
+#endif
+}
+
+/* Unpack the argument tuple */
+
+SWIGINTERN Py_ssize_t
+SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs)
+{
+ if (!args) {
+ if (!min && !max) {
+ return 1;
+ } else {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none",
+ name, (min == max ? "" : "at least "), (int)min);
+ return 0;
+ }
+ }
+ if (!PyTuple_Check(args)) {
+ if (min <= 1 && max >= 1) {
+ Py_ssize_t i;
+ objs[0] = args;
+ for (i = 1; i < max; ++i) {
+ objs[i] = 0;
+ }
+ return 2;
+ }
+ PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple");
+ return 0;
+ } else {
+ Py_ssize_t l = PyTuple_GET_SIZE(args);
+ if (l < min) {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d",
+ name, (min == max ? "" : "at least "), (int)min, (int)l);
+ return 0;
+ } else if (l > max) {
+ PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d",
+ name, (min == max ? "" : "at most "), (int)max, (int)l);
+ return 0;
+ } else {
+ Py_ssize_t i;
+ for (i = 0; i < l; ++i) {
+ objs[i] = PyTuple_GET_ITEM(args, i);
+ }
+ for (; l < max; ++l) {
+ objs[l] = 0;
+ }
+ return i + 1;
+ }
+ }
+}
+
+/* A functor is a function object with one single object argument */
+#if PY_VERSION_HEX >= 0x02020000
+#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL);
+#else
+#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj);
+#endif
+
+/*
+ Helper for static pointer initialization for both C and C++ code, for example
+ static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...);
+*/
+#ifdef __cplusplus
+#define SWIG_STATIC_POINTER(var) var
+#else
+#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Pointer declarations
+ * ----------------------------------------------------------------------------- */
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1)
+#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN)
+
+#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1)
+
+#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2)
+#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* How to access Py_None */
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# ifndef SWIG_PYTHON_NO_BUILD_NONE
+# ifndef SWIG_PYTHON_BUILD_NONE
+# define SWIG_PYTHON_BUILD_NONE
+# endif
+# endif
+#endif
+
+#ifdef SWIG_PYTHON_BUILD_NONE
+# ifdef Py_None
+# undef Py_None
+# define Py_None SWIG_Py_None()
+# endif
+SWIGRUNTIMEINLINE PyObject *
+_SWIG_Py_None(void)
+{
+ PyObject *none = Py_BuildValue((char*)"");
+ Py_DECREF(none);
+ return none;
+}
+SWIGRUNTIME PyObject *
+SWIG_Py_None(void)
+{
+ static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None();
+ return none;
+}
+#endif
+
+/* The python void return value */
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Py_Void(void)
+{
+ PyObject *none = Py_None;
+ Py_INCREF(none);
+ return none;
+}
+
+/* SwigPyClientData */
+
+typedef struct {
+ PyObject *klass;
+ PyObject *newraw;
+ PyObject *newargs;
+ PyObject *destroy;
+ int delargs;
+ int implicitconv;
+ PyTypeObject *pytype;
+} SwigPyClientData;
+
+SWIGRUNTIMEINLINE int
+SWIG_Python_CheckImplicit(swig_type_info *ty)
+{
+ SwigPyClientData *data = (SwigPyClientData *)ty->clientdata;
+ return data ? data->implicitconv : 0;
+}
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Python_ExceptionType(swig_type_info *desc) {
+ SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0;
+ PyObject *klass = data ? data->klass : 0;
+ return (klass ? klass : PyExc_RuntimeError);
+}
+
+
+SWIGRUNTIME SwigPyClientData *
+SwigPyClientData_New(PyObject* obj)
+{
+ if (!obj) {
+ return 0;
+ } else {
+ SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData));
+ /* the klass element */
+ data->klass = obj;
+ Py_INCREF(data->klass);
+ /* the newraw method and newargs arguments used to create a new raw instance */
+ if (PyClass_Check(obj)) {
+ data->newraw = 0;
+ data->newargs = obj;
+ Py_INCREF(obj);
+ } else {
+#if (PY_VERSION_HEX < 0x02020000)
+ data->newraw = 0;
+#else
+ data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__");
+#endif
+ if (data->newraw) {
+ Py_INCREF(data->newraw);
+ data->newargs = PyTuple_New(1);
+ PyTuple_SetItem(data->newargs, 0, obj);
+ } else {
+ data->newargs = obj;
+ }
+ Py_INCREF(data->newargs);
+ }
+ /* the destroy method, aka as the C++ delete method */
+ data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__");
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ data->destroy = 0;
+ }
+ if (data->destroy) {
+ int flags;
+ Py_INCREF(data->destroy);
+ flags = PyCFunction_GET_FLAGS(data->destroy);
+#ifdef METH_O
+ data->delargs = !(flags & (METH_O));
+#else
+ data->delargs = 0;
+#endif
+ } else {
+ data->delargs = 0;
+ }
+ data->implicitconv = 0;
+ data->pytype = 0;
+ return data;
+ }
+}
+
+SWIGRUNTIME void
+SwigPyClientData_Del(SwigPyClientData *data) {
+ Py_XDECREF(data->newraw);
+ Py_XDECREF(data->newargs);
+ Py_XDECREF(data->destroy);
+}
+
+/* =============== SwigPyObject =====================*/
+
+typedef struct {
+ PyObject_HEAD
+ void *ptr;
+ swig_type_info *ty;
+ int own;
+ PyObject *next;
+#ifdef SWIGPYTHON_BUILTIN
+ PyObject *dict;
+#endif
+} SwigPyObject;
+
+
+#ifdef SWIGPYTHON_BUILTIN
+
+SWIGRUNTIME PyObject *
+SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
+{
+ SwigPyObject *sobj = (SwigPyObject *)v;
+
+ if (!sobj->dict)
+ sobj->dict = PyDict_New();
+
+ Py_INCREF(sobj->dict);
+ return sobj->dict;
+}
+
+#endif
+
+SWIGRUNTIME PyObject *
+SwigPyObject_long(SwigPyObject *v)
+{
+ return PyLong_FromVoidPtr(v->ptr);
+}
+
+SWIGRUNTIME PyObject *
+SwigPyObject_format(const char* fmt, SwigPyObject *v)
+{
+ PyObject *res = NULL;
+ PyObject *args = PyTuple_New(1);
+ if (args) {
+ if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) {
+ PyObject *ofmt = SWIG_Python_str_FromChar(fmt);
+ if (ofmt) {
+#if PY_VERSION_HEX >= 0x03000000
+ res = PyUnicode_Format(ofmt,args);
+#else
+ res = PyString_Format(ofmt,args);
+#endif
+ Py_DECREF(ofmt);
+ }
+ Py_DECREF(args);
+ }
+ }
+ return res;
+}
+
+SWIGRUNTIME PyObject *
+SwigPyObject_oct(SwigPyObject *v)
+{
+ return SwigPyObject_format("%o",v);
+}
+
+SWIGRUNTIME PyObject *
+SwigPyObject_hex(SwigPyObject *v)
+{
+ return SwigPyObject_format("%x",v);
+}
+
+SWIGRUNTIME PyObject *
+#ifdef METH_NOARGS
+SwigPyObject_repr(SwigPyObject *v)
+#else
+SwigPyObject_repr(SwigPyObject *v, PyObject *args)
+#endif
+{
+ const char *name = SWIG_TypePrettyName(v->ty);
+ PyObject *repr = SWIG_Python_str_FromFormat("<Swig Object of type '%s' at %p>", (name ? name : "unknown"), (void *)v);
+ if (v->next) {
+# ifdef METH_NOARGS
+ PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next);
+# else
+ PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next, args);
+# endif
+# if PY_VERSION_HEX >= 0x03000000
+ PyObject *joined = PyUnicode_Concat(repr, nrep);
+ Py_DecRef(repr);
+ Py_DecRef(nrep);
+ repr = joined;
+# else
+ PyString_ConcatAndDel(&repr,nrep);
+# endif
+ }
+ return repr;
+}
+
+/* We need a version taking two PyObject* parameters so it's a valid
+ * PyCFunction to use in swigobject_methods[]. */
+SWIGRUNTIME PyObject *
+SwigPyObject_repr2(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
+{
+ return SwigPyObject_repr((SwigPyObject*)v);
+}
+
+SWIGRUNTIME int
+SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w)
+{
+ void *i = v->ptr;
+ void *j = w->ptr;
+ return (i < j) ? -1 : ((i > j) ? 1 : 0);
+}
+
+/* Added for Python 3.x, would it also be useful for Python 2.x? */
+SWIGRUNTIME PyObject*
+SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op)
+{
+ PyObject* res;
+ if( op != Py_EQ && op != Py_NE ) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0);
+ return res;
+}
+
+
+SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void);
+
+#ifdef SWIGPYTHON_BUILTIN
+static swig_type_info *SwigPyObject_stype = 0;
+SWIGRUNTIME PyTypeObject*
+SwigPyObject_type(void) {
+ SwigPyClientData *cd;
+ assert(SwigPyObject_stype);
+ cd = (SwigPyClientData*) SwigPyObject_stype->clientdata;
+ assert(cd);
+ assert(cd->pytype);
+ return cd->pytype;
+}
+#else
+SWIGRUNTIME PyTypeObject*
+SwigPyObject_type(void) {
+ static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce();
+ return type;
+}
+#endif
+
+SWIGRUNTIMEINLINE int
+SwigPyObject_Check(PyObject *op) {
+#ifdef SWIGPYTHON_BUILTIN
+ PyTypeObject *target_tp = SwigPyObject_type();
+ if (PyType_IsSubtype(op->ob_type, target_tp))
+ return 1;
+ return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0);
+#else
+ return (Py_TYPE(op) == SwigPyObject_type())
+ || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0);
+#endif
+}
+
+SWIGRUNTIME PyObject *
+SwigPyObject_New(void *ptr, swig_type_info *ty, int own);
+
+SWIGRUNTIME void
+SwigPyObject_dealloc(PyObject *v)
+{
+ SwigPyObject *sobj = (SwigPyObject *) v;
+ PyObject *next = sobj->next;
+ if (sobj->own == SWIG_POINTER_OWN) {
+ swig_type_info *ty = sobj->ty;
+ SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0;
+ PyObject *destroy = data ? data->destroy : 0;
+ if (destroy) {
+ /* destroy is always a VARARGS method */
+ PyObject *res;
+
+ /* PyObject_CallFunction() has the potential to silently drop
+ the active active exception. In cases of unnamed temporary
+ variable or where we just finished iterating over a generator
+ StopIteration will be active right now, and this needs to
+ remain true upon return from SwigPyObject_dealloc. So save
+ and restore. */
+
+ PyObject *val = NULL, *type = NULL, *tb = NULL;
+ PyErr_Fetch(&val, &type, &tb);
+
+ if (data->delargs) {
+ /* we need to create a temporary object to carry the destroy operation */
+ PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0);
+ res = SWIG_Python_CallFunctor(destroy, tmp);
+ Py_DECREF(tmp);
+ } else {
+ PyCFunction meth = PyCFunction_GET_FUNCTION(destroy);
+ PyObject *mself = PyCFunction_GET_SELF(destroy);
+ res = ((*meth)(mself, v));
+ }
+ if (!res)
+ PyErr_WriteUnraisable(destroy);
+
+ PyErr_Restore(val, type, tb);
+
+ Py_XDECREF(res);
+ }
+#if !defined(SWIG_PYTHON_SILENT_MEMLEAK)
+ else {
+ const char *name = SWIG_TypePrettyName(ty);
+ printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown"));
+ }
+#endif
+ }
+ Py_XDECREF(next);
+ PyObject_DEL(v);
+}
+
+SWIGRUNTIME PyObject*
+SwigPyObject_append(PyObject* v, PyObject* next)
+{
+ SwigPyObject *sobj = (SwigPyObject *) v;
+#ifndef METH_O
+ PyObject *tmp = 0;
+ if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL;
+ next = tmp;
+#endif
+ if (!SwigPyObject_Check(next)) {
+ PyErr_SetString(PyExc_TypeError, "Attempt to append a non SwigPyObject");
+ return NULL;
+ }
+ sobj->next = next;
+ Py_INCREF(next);
+ return SWIG_Py_Void();
+}
+
+SWIGRUNTIME PyObject*
+SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+{
+ SwigPyObject *sobj = (SwigPyObject *) v;
+ if (sobj->next) {
+ Py_INCREF(sobj->next);
+ return sobj->next;
+ } else {
+ return SWIG_Py_Void();
+ }
+}
+
+SWIGINTERN PyObject*
+#ifdef METH_NOARGS
+SwigPyObject_disown(PyObject *v)
+#else
+SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+#endif
+{
+ SwigPyObject *sobj = (SwigPyObject *)v;
+ sobj->own = 0;
+ return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject*
+#ifdef METH_NOARGS
+SwigPyObject_acquire(PyObject *v)
+#else
+SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+#endif
+{
+ SwigPyObject *sobj = (SwigPyObject *)v;
+ sobj->own = SWIG_POINTER_OWN;
+ return SWIG_Py_Void();
+}
+
+#ifdef METH_NOARGS
+static PyObject*
+SwigPyObject_disown2(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+{
+ return SwigPyObject_disown(v);
+}
+
+static PyObject*
+SwigPyObject_acquire2(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
+{
+ return SwigPyObject_acquire(v);
+}
+#endif
+
+SWIGINTERN PyObject*
+SwigPyObject_own(PyObject *v, PyObject *args)
+{
+ PyObject *val = 0;
+#if (PY_VERSION_HEX < 0x02020000)
+ if (!PyArg_ParseTuple(args,(char *)"|O:own",&val))
+#elif (PY_VERSION_HEX < 0x02050000)
+ if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val))
+#else
+ if (!PyArg_UnpackTuple(args, "own", 0, 1, &val))
+#endif
+ {
+ return NULL;
+ }
+ else
+ {
+ SwigPyObject *sobj = (SwigPyObject *)v;
+ PyObject *obj = PyBool_FromLong(sobj->own);
+ if (val) {
+#ifdef METH_NOARGS
+ if (PyObject_IsTrue(val)) {
+ SwigPyObject_acquire(v);
+ } else {
+ SwigPyObject_disown(v);
+ }
+#else
+ if (PyObject_IsTrue(val)) {
+ SwigPyObject_acquire(v,args);
+ } else {
+ SwigPyObject_disown(v,args);
+ }
+#endif
+ }
+ return obj;
+ }
+}
+
+#ifdef METH_O
+static PyMethodDef
+swigobject_methods[] = {
+ {(char *)"disown", (PyCFunction)SwigPyObject_disown2, METH_NOARGS, (char *)"releases ownership of the pointer"},
+ {(char *)"acquire", (PyCFunction)SwigPyObject_acquire2,METH_NOARGS, (char *)"acquires ownership of the pointer"},
+ {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"},
+ {(char *)"append", (PyCFunction)SwigPyObject_append, METH_O, (char *)"appends another 'this' object"},
+ {(char *)"next", (PyCFunction)SwigPyObject_next, METH_NOARGS, (char *)"returns the next 'this' object"},
+ {(char *)"__repr__",(PyCFunction)SwigPyObject_repr2, METH_NOARGS, (char *)"returns object representation"},
+ {0, 0, 0, 0}
+};
+#else
+static PyMethodDef
+swigobject_methods[] = {
+ {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"},
+ {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_VARARGS, (char *)"acquires ownership of the pointer"},
+ {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"},
+ {(char *)"append", (PyCFunction)SwigPyObject_append, METH_VARARGS, (char *)"appends another 'this' object"},
+ {(char *)"next", (PyCFunction)SwigPyObject_next, METH_VARARGS, (char *)"returns the next 'this' object"},
+ {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_VARARGS, (char *)"returns object representation"},
+ {0, 0, 0, 0}
+};
+#endif
+
+#if PY_VERSION_HEX < 0x02020000
+SWIGINTERN PyObject *
+SwigPyObject_getattr(SwigPyObject *sobj,char *name)
+{
+ return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name);
+}
+#endif
+
+SWIGRUNTIME PyTypeObject*
+SwigPyObject_TypeOnce(void) {
+ static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer";
+
+ static PyNumberMethods SwigPyObject_as_number = {
+ (binaryfunc)0, /*nb_add*/
+ (binaryfunc)0, /*nb_subtract*/
+ (binaryfunc)0, /*nb_multiply*/
+ /* nb_divide removed in Python 3 */
+#if PY_VERSION_HEX < 0x03000000
+ (binaryfunc)0, /*nb_divide*/
+#endif
+ (binaryfunc)0, /*nb_remainder*/
+ (binaryfunc)0, /*nb_divmod*/
+ (ternaryfunc)0,/*nb_power*/
+ (unaryfunc)0, /*nb_negative*/
+ (unaryfunc)0, /*nb_positive*/
+ (unaryfunc)0, /*nb_absolute*/
+ (inquiry)0, /*nb_nonzero*/
+ 0, /*nb_invert*/
+ 0, /*nb_lshift*/
+ 0, /*nb_rshift*/
+ 0, /*nb_and*/
+ 0, /*nb_xor*/
+ 0, /*nb_or*/
+#if PY_VERSION_HEX < 0x03000000
+ 0, /*nb_coerce*/
+#endif
+ (unaryfunc)SwigPyObject_long, /*nb_int*/
+#if PY_VERSION_HEX < 0x03000000
+ (unaryfunc)SwigPyObject_long, /*nb_long*/
+#else
+ 0, /*nb_reserved*/
+#endif
+ (unaryfunc)0, /*nb_float*/
+#if PY_VERSION_HEX < 0x03000000
+ (unaryfunc)SwigPyObject_oct, /*nb_oct*/
+ (unaryfunc)SwigPyObject_hex, /*nb_hex*/
+#endif
+#if PY_VERSION_HEX >= 0x03050000 /* 3.5 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_matrix_multiply */
+#elif PY_VERSION_HEX >= 0x03000000 /* 3.0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */
+#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */
+#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */
+#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */
+ 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */
+#endif
+ };
+
+ static PyTypeObject swigpyobject_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp = {
+#if PY_VERSION_HEX >= 0x03000000
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+#endif
+ (char *)"SwigPyObject", /* tp_name */
+ sizeof(SwigPyObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)SwigPyObject_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+#if PY_VERSION_HEX < 0x02020000
+ (getattrfunc)SwigPyObject_getattr, /* tp_getattr */
+#else
+ (getattrfunc)0, /* tp_getattr */
+#endif
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03000000
+ 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */
+#else
+ (cmpfunc)SwigPyObject_compare, /* tp_compare */
+#endif
+ (reprfunc)SwigPyObject_repr, /* tp_repr */
+ &SwigPyObject_as_number, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ swigobject_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ swigobject_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#if PY_VERSION_HEX >= 0x02060000
+ 0, /* tp_version_tag */
+#endif
+#if PY_VERSION_HEX >= 0x03040000
+ 0, /* tp_finalize */
+#endif
+#ifdef COUNT_ALLOCS
+ 0, /* tp_allocs */
+ 0, /* tp_frees */
+ 0, /* tp_maxalloc */
+#if PY_VERSION_HEX >= 0x02050000
+ 0, /* tp_prev */
+#endif
+ 0 /* tp_next */
+#endif
+ };
+ swigpyobject_type = tmp;
+ type_init = 1;
+#if PY_VERSION_HEX < 0x02020000
+ swigpyobject_type.ob_type = &PyType_Type;
+#else
+ if (PyType_Ready(&swigpyobject_type) < 0)
+ return NULL;
+#endif
+ }
+ return &swigpyobject_type;
+}
+
+SWIGRUNTIME PyObject *
+SwigPyObject_New(void *ptr, swig_type_info *ty, int own)
+{
+ SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type());
+ if (sobj) {
+ sobj->ptr = ptr;
+ sobj->ty = ty;
+ sobj->own = own;
+ sobj->next = 0;
+ }
+ return (PyObject *)sobj;
+}
+
+/* -----------------------------------------------------------------------------
+ * Implements a simple Swig Packed type, and use it instead of string
+ * ----------------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ void *pack;
+ swig_type_info *ty;
+ size_t size;
+} SwigPyPacked;
+
+SWIGRUNTIME int
+SwigPyPacked_print(SwigPyPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags))
+{
+ char result[SWIG_BUFFER_SIZE];
+ fputs("<Swig Packed ", fp);
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+ fputs("at ", fp);
+ fputs(result, fp);
+ }
+ fputs(v->ty->name,fp);
+ fputs(">", fp);
+ return 0;
+}
+
+SWIGRUNTIME PyObject *
+SwigPyPacked_repr(SwigPyPacked *v)
+{
+ char result[SWIG_BUFFER_SIZE];
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+ return SWIG_Python_str_FromFormat("<Swig Packed at %s%s>", result, v->ty->name);
+ } else {
+ return SWIG_Python_str_FromFormat("<Swig Packed %s>", v->ty->name);
+ }
+}
+
+SWIGRUNTIME PyObject *
+SwigPyPacked_str(SwigPyPacked *v)
+{
+ char result[SWIG_BUFFER_SIZE];
+ if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){
+ return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name);
+ } else {
+ return SWIG_Python_str_FromChar(v->ty->name);
+ }
+}
+
+SWIGRUNTIME int
+SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w)
+{
+ size_t i = v->size;
+ size_t j = w->size;
+ int s = (i < j) ? -1 : ((i > j) ? 1 : 0);
+ return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size);
+}
+
+SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void);
+
+SWIGRUNTIME PyTypeObject*
+SwigPyPacked_type(void) {
+ static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce();
+ return type;
+}
+
+SWIGRUNTIMEINLINE int
+SwigPyPacked_Check(PyObject *op) {
+ return ((op)->ob_type == SwigPyPacked_TypeOnce())
+ || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0);
+}
+
+SWIGRUNTIME void
+SwigPyPacked_dealloc(PyObject *v)
+{
+ if (SwigPyPacked_Check(v)) {
+ SwigPyPacked *sobj = (SwigPyPacked *) v;
+ free(sobj->pack);
+ }
+ PyObject_DEL(v);
+}
+
+SWIGRUNTIME PyTypeObject*
+SwigPyPacked_TypeOnce(void) {
+ static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer";
+ static PyTypeObject swigpypacked_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp = {
+#if PY_VERSION_HEX>=0x03000000
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+#endif
+ (char *)"SwigPyPacked", /* tp_name */
+ sizeof(SwigPyPacked), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)SwigPyPacked_dealloc, /* tp_dealloc */
+ (printfunc)SwigPyPacked_print, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX>=0x03000000
+ 0, /* tp_reserved in 3.0.1 */
+#else
+ (cmpfunc)SwigPyPacked_compare, /* tp_compare */
+#endif
+ (reprfunc)SwigPyPacked_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)SwigPyPacked_str, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ swigpacked_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#if PY_VERSION_HEX >= 0x02060000
+ 0, /* tp_version_tag */
+#endif
+#if PY_VERSION_HEX >= 0x03040000
+ 0, /* tp_finalize */
+#endif
+#ifdef COUNT_ALLOCS
+ 0, /* tp_allocs */
+ 0, /* tp_frees */
+ 0, /* tp_maxalloc */
+#if PY_VERSION_HEX >= 0x02050000
+ 0, /* tp_prev */
+#endif
+ 0 /* tp_next */
+#endif
+ };
+ swigpypacked_type = tmp;
+ type_init = 1;
+#if PY_VERSION_HEX < 0x02020000
+ swigpypacked_type.ob_type = &PyType_Type;
+#else
+ if (PyType_Ready(&swigpypacked_type) < 0)
+ return NULL;
+#endif
+ }
+ return &swigpypacked_type;
+}
+
+SWIGRUNTIME PyObject *
+SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty)
+{
+ SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type());
+ if (sobj) {
+ void *pack = malloc(size);
+ if (pack) {
+ memcpy(pack, ptr, size);
+ sobj->pack = pack;
+ sobj->ty = ty;
+ sobj->size = size;
+ } else {
+ PyObject_DEL((PyObject *) sobj);
+ sobj = 0;
+ }
+ }
+ return (PyObject *) sobj;
+}
+
+SWIGRUNTIME swig_type_info *
+SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size)
+{
+ if (SwigPyPacked_Check(obj)) {
+ SwigPyPacked *sobj = (SwigPyPacked *)obj;
+ if (sobj->size != size) return 0;
+ memcpy(ptr, sobj->pack, size);
+ return sobj->ty;
+ } else {
+ return 0;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGRUNTIMEINLINE PyObject *
+_SWIG_This(void)
+{
+ return SWIG_Python_str_FromChar("this");
+}
+
+static PyObject *swig_this = NULL;
+
+SWIGRUNTIME PyObject *
+SWIG_This(void)
+{
+ if (swig_this == NULL)
+ swig_this = _SWIG_This();
+ return swig_this;
+}
+
+/* #define SWIG_PYTHON_SLOW_GETSET_THIS */
+
+/* TODO: I don't know how to implement the fast getset in Python 3 right now */
+#if PY_VERSION_HEX>=0x03000000
+#define SWIG_PYTHON_SLOW_GETSET_THIS
+#endif
+
+SWIGRUNTIME SwigPyObject *
+SWIG_Python_GetSwigThis(PyObject *pyobj)
+{
+ PyObject *obj;
+
+ if (SwigPyObject_Check(pyobj))
+ return (SwigPyObject *) pyobj;
+
+#ifdef SWIGPYTHON_BUILTIN
+ (void)obj;
+# ifdef PyWeakref_CheckProxy
+ if (PyWeakref_CheckProxy(pyobj)) {
+ pyobj = PyWeakref_GET_OBJECT(pyobj);
+ if (pyobj && SwigPyObject_Check(pyobj))
+ return (SwigPyObject*) pyobj;
+ }
+# endif
+ return NULL;
+#else
+
+ obj = 0;
+
+#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000))
+ if (PyInstance_Check(pyobj)) {
+ obj = _PyInstance_Lookup(pyobj, SWIG_This());
+ } else {
+ PyObject **dictptr = _PyObject_GetDictPtr(pyobj);
+ if (dictptr != NULL) {
+ PyObject *dict = *dictptr;
+ obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0;
+ } else {
+#ifdef PyWeakref_CheckProxy
+ if (PyWeakref_CheckProxy(pyobj)) {
+ PyObject *wobj = PyWeakref_GET_OBJECT(pyobj);
+ return wobj ? SWIG_Python_GetSwigThis(wobj) : 0;
+ }
+#endif
+ obj = PyObject_GetAttr(pyobj,SWIG_This());
+ if (obj) {
+ Py_DECREF(obj);
+ } else {
+ if (PyErr_Occurred()) PyErr_Clear();
+ return 0;
+ }
+ }
+ }
+#else
+ obj = PyObject_GetAttr(pyobj,SWIG_This());
+ if (obj) {
+ Py_DECREF(obj);
+ } else {
+ if (PyErr_Occurred()) PyErr_Clear();
+ return 0;
+ }
+#endif
+ if (obj && !SwigPyObject_Check(obj)) {
+ /* a PyObject is called 'this', try to get the 'real this'
+ SwigPyObject from it */
+ return SWIG_Python_GetSwigThis(obj);
+ }
+ return (SwigPyObject *)obj;
+#endif
+}
+
+/* Acquire a pointer value */
+
+SWIGRUNTIME int
+SWIG_Python_AcquirePtr(PyObject *obj, int own) {
+ if (own == SWIG_POINTER_OWN) {
+ SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj);
+ if (sobj) {
+ int oldown = sobj->own;
+ sobj->own = own;
+ return oldown;
+ }
+ }
+ return 0;
+}
+
+/* Convert a pointer value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) {
+ int res;
+ SwigPyObject *sobj;
+ int implicit_conv = (flags & SWIG_POINTER_IMPLICIT_CONV) != 0;
+
+ if (!obj)
+ return SWIG_ERROR;
+ if (obj == Py_None && !implicit_conv) {
+ if (ptr)
+ *ptr = 0;
+ return SWIG_OK;
+ }
+
+ res = SWIG_ERROR;
+
+ sobj = SWIG_Python_GetSwigThis(obj);
+ if (own)
+ *own = 0;
+ while (sobj) {
+ void *vptr = sobj->ptr;
+ if (ty) {
+ swig_type_info *to = sobj->ty;
+ if (to == ty) {
+ /* no type cast needed */
+ if (ptr) *ptr = vptr;
+ break;
+ } else {
+ swig_cast_info *tc = SWIG_TypeCheck(to->name,ty);
+ if (!tc) {
+ sobj = (SwigPyObject *)sobj->next;
+ } else {
+ if (ptr) {
+ int newmemory = 0;
+ *ptr = SWIG_TypeCast(tc,vptr,&newmemory);
+ if (newmemory == SWIG_CAST_NEW_MEMORY) {
+ assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */
+ if (own)
+ *own = *own | SWIG_CAST_NEW_MEMORY;
+ }
+ }
+ break;
+ }
+ }
+ } else {
+ if (ptr) *ptr = vptr;
+ break;
+ }
+ }
+ if (sobj) {
+ if (own)
+ *own = *own | sobj->own;
+ if (flags & SWIG_POINTER_DISOWN) {
+ sobj->own = 0;
+ }
+ res = SWIG_OK;
+ } else {
+ if (implicit_conv) {
+ SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0;
+ if (data && !data->implicitconv) {
+ PyObject *klass = data->klass;
+ if (klass) {
+ PyObject *impconv;
+ data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/
+ impconv = SWIG_Python_CallFunctor(klass, obj);
+ data->implicitconv = 0;
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ impconv = 0;
+ }
+ if (impconv) {
+ SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv);
+ if (iobj) {
+ void *vptr;
+ res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0);
+ if (SWIG_IsOK(res)) {
+ if (ptr) {
+ *ptr = vptr;
+ /* transfer the ownership to 'ptr' */
+ iobj->own = 0;
+ res = SWIG_AddCast(res);
+ res = SWIG_AddNewMask(res);
+ } else {
+ res = SWIG_AddCast(res);
+ }
+ }
+ }
+ Py_DECREF(impconv);
+ }
+ }
+ }
+ }
+ if (!SWIG_IsOK(res) && obj == Py_None) {
+ if (ptr)
+ *ptr = 0;
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ res = SWIG_OK;
+ }
+ }
+ return res;
+}
+
+/* Convert a function ptr value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) {
+ if (!PyCFunction_Check(obj)) {
+ return SWIG_ConvertPtr(obj, ptr, ty, 0);
+ } else {
+ void *vptr = 0;
+
+ /* here we get the method pointer for callbacks */
+ const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc);
+ const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0;
+ if (desc)
+ desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0;
+ if (!desc)
+ return SWIG_ERROR;
+ if (ty) {
+ swig_cast_info *tc = SWIG_TypeCheck(desc,ty);
+ if (tc) {
+ int newmemory = 0;
+ *ptr = SWIG_TypeCast(tc,vptr,&newmemory);
+ assert(!newmemory); /* newmemory handling not yet implemented */
+ } else {
+ return SWIG_ERROR;
+ }
+ } else {
+ *ptr = vptr;
+ }
+ return SWIG_OK;
+ }
+}
+
+/* Convert a packed value value */
+
+SWIGRUNTIME int
+SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) {
+ swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz);
+ if (!to) return SWIG_ERROR;
+ if (ty) {
+ if (to != ty) {
+ /* check type cast? */
+ swig_cast_info *tc = SWIG_TypeCheck(to->name,ty);
+ if (!tc) return SWIG_ERROR;
+ }
+ }
+ return SWIG_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * Create a new pointer object
+ * ----------------------------------------------------------------------------- */
+
+/*
+ Create a new instance object, without calling __init__, and set the
+ 'this' attribute.
+*/
+
+SWIGRUNTIME PyObject*
+SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
+{
+#if (PY_VERSION_HEX >= 0x02020000)
+ PyObject *inst = 0;
+ PyObject *newraw = data->newraw;
+ if (newraw) {
+ inst = PyObject_Call(newraw, data->newargs, NULL);
+ if (inst) {
+#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
+ PyObject **dictptr = _PyObject_GetDictPtr(inst);
+ if (dictptr != NULL) {
+ PyObject *dict = *dictptr;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ *dictptr = dict;
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ }
+ }
+#else
+ PyObject *key = SWIG_This();
+ PyObject_SetAttr(inst, key, swig_this);
+#endif
+ }
+ } else {
+#if PY_VERSION_HEX >= 0x03000000
+ inst = ((PyTypeObject*) data->newargs)->tp_new((PyTypeObject*) data->newargs, Py_None, Py_None);
+ if (inst) {
+ PyObject_SetAttr(inst, SWIG_This(), swig_this);
+ Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+ }
+#else
+ PyObject *dict = PyDict_New();
+ if (dict) {
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ inst = PyInstance_NewRaw(data->newargs, dict);
+ Py_DECREF(dict);
+ }
+#endif
+ }
+ return inst;
+#else
+#if (PY_VERSION_HEX >= 0x02010000)
+ PyObject *inst = 0;
+ PyObject *dict = PyDict_New();
+ if (dict) {
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ inst = PyInstance_NewRaw(data->newargs, dict);
+ Py_DECREF(dict);
+ }
+ return (PyObject *) inst;
+#else
+ PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type);
+ if (inst == NULL) {
+ return NULL;
+ }
+ inst->in_class = (PyClassObject *)data->newargs;
+ Py_INCREF(inst->in_class);
+ inst->in_dict = PyDict_New();
+ if (inst->in_dict == NULL) {
+ Py_DECREF(inst);
+ return NULL;
+ }
+#ifdef Py_TPFLAGS_HAVE_WEAKREFS
+ inst->in_weakreflist = NULL;
+#endif
+#ifdef Py_TPFLAGS_GC
+ PyObject_GC_Init(inst);
+#endif
+ PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this);
+ return (PyObject *) inst;
+#endif
+#endif
+}
+
+SWIGRUNTIME void
+SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
+{
+ PyObject *dict;
+#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
+ PyObject **dictptr = _PyObject_GetDictPtr(inst);
+ if (dictptr != NULL) {
+ dict = *dictptr;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ *dictptr = dict;
+ }
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ return;
+ }
+#endif
+ dict = PyObject_GetAttrString(inst, (char*)"__dict__");
+ PyDict_SetItem(dict, SWIG_This(), swig_this);
+ Py_DECREF(dict);
+}
+
+
+SWIGINTERN PyObject *
+SWIG_Python_InitShadowInstance(PyObject *args) {
+ PyObject *obj[2];
+ if (!SWIG_Python_UnpackTuple(args, "swiginit", 2, 2, obj)) {
+ return NULL;
+ } else {
+ SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]);
+ if (sthis) {
+ SwigPyObject_append((PyObject*) sthis, obj[1]);
+ } else {
+ SWIG_Python_SetSwigThis(obj[0], obj[1]);
+ }
+ return SWIG_Py_Void();
+ }
+}
+
+/* Create a new pointer object */
+
+SWIGRUNTIME PyObject *
+SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) {
+ SwigPyClientData *clientdata;
+ PyObject * robj;
+ int own;
+
+ if (!ptr)
+ return SWIG_Py_Void();
+
+ clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0;
+ own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0;
+ if (clientdata && clientdata->pytype) {
+ SwigPyObject *newobj;
+ if (flags & SWIG_BUILTIN_TP_INIT) {
+ newobj = (SwigPyObject*) self;
+ if (newobj->ptr) {
+ PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0);
+ while (newobj->next)
+ newobj = (SwigPyObject *) newobj->next;
+ newobj->next = next_self;
+ newobj = (SwigPyObject *)next_self;
+#ifdef SWIGPYTHON_BUILTIN
+ newobj->dict = 0;
+#endif
+ }
+ } else {
+ newobj = PyObject_New(SwigPyObject, clientdata->pytype);
+#ifdef SWIGPYTHON_BUILTIN
+ newobj->dict = 0;
+#endif
+ }
+ if (newobj) {
+ newobj->ptr = ptr;
+ newobj->ty = type;
+ newobj->own = own;
+ newobj->next = 0;
+ return (PyObject*) newobj;
+ }
+ return SWIG_Py_Void();
+ }
+
+ assert(!(flags & SWIG_BUILTIN_TP_INIT));
+
+ robj = SwigPyObject_New(ptr, type, own);
+ if (robj && clientdata && !(flags & SWIG_POINTER_NOSHADOW)) {
+ PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj);
+ Py_DECREF(robj);
+ robj = inst;
+ }
+ return robj;
+}
+
+/* Create a new packed object */
+
+SWIGRUNTIMEINLINE PyObject *
+SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
+ return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void();
+}
+
+/* -----------------------------------------------------------------------------*
+ * Get type list
+ * -----------------------------------------------------------------------------*/
+
+#ifdef SWIG_LINK_RUNTIME
+void *SWIG_ReturnGlobalTypeList(void *);
+#endif
+
+SWIGRUNTIME swig_module_info *
+SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) {
+ static void *type_pointer = (void *)0;
+ /* first check if module already created */
+ if (!type_pointer) {
+#ifdef SWIG_LINK_RUNTIME
+ type_pointer = SWIG_ReturnGlobalTypeList((void *)0);
+#else
+# ifdef SWIGPY_USE_CAPSULE
+ type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0);
+# else
+ type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION,
+ (char*)"type_pointer" SWIG_TYPE_TABLE_NAME);
+# endif
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ type_pointer = (void *)0;
+ }
+#endif
+ }
+ return (swig_module_info *) type_pointer;
+}
+
+#if PY_MAJOR_VERSION < 2
+/* PyModule_AddObject function was introduced in Python 2.0. The following function
+ is copied out of Python/modsupport.c in python version 2.3.4 */
+SWIGINTERN int
+PyModule_AddObject(PyObject *m, char *name, PyObject *o)
+{
+ PyObject *dict;
+ if (!PyModule_Check(m)) {
+ PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs module as first arg");
+ return SWIG_ERROR;
+ }
+ if (!o) {
+ PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs non-NULL value");
+ return SWIG_ERROR;
+ }
+
+ dict = PyModule_GetDict(m);
+ if (dict == NULL) {
+ /* Internal error -- modules must have a dict! */
+ PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__",
+ PyModule_GetName(m));
+ return SWIG_ERROR;
+ }
+ if (PyDict_SetItemString(dict, name, o))
+ return SWIG_ERROR;
+ Py_DECREF(o);
+ return SWIG_OK;
+}
+#endif
+
+SWIGRUNTIME void
+#ifdef SWIGPY_USE_CAPSULE
+SWIG_Python_DestroyModule(PyObject *obj)
+#else
+SWIG_Python_DestroyModule(void *vptr)
+#endif
+{
+#ifdef SWIGPY_USE_CAPSULE
+ swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME);
+#else
+ swig_module_info *swig_module = (swig_module_info *) vptr;
+#endif
+ swig_type_info **types = swig_module->types;
+ size_t i;
+ for (i =0; i < swig_module->size; ++i) {
+ swig_type_info *ty = types[i];
+ if (ty->owndata) {
+ SwigPyClientData *data = (SwigPyClientData *) ty->clientdata;
+ if (data) SwigPyClientData_Del(data);
+ }
+ }
+ Py_DECREF(SWIG_This());
+ swig_this = NULL;
+}
+
+SWIGRUNTIME void
+SWIG_Python_SetModule(swig_module_info *swig_module) {
+#if PY_VERSION_HEX >= 0x03000000
+ /* Add a placeholder module object into sys.modules */
+ PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION);
+#else
+ static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */
+ PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table);
+#endif
+#ifdef SWIGPY_USE_CAPSULE
+ PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule);
+ if (pointer && module) {
+ PyModule_AddObject(module, (char*)"type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer);
+ } else {
+ Py_XDECREF(pointer);
+ }
+#else
+ PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule);
+ if (pointer && module) {
+ PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer);
+ } else {
+ Py_XDECREF(pointer);
+ }
+#endif
+}
+
+/* The python cached type query */
+SWIGRUNTIME PyObject *
+SWIG_Python_TypeCache(void) {
+ static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New();
+ return cache;
+}
+
+SWIGRUNTIME swig_type_info *
+SWIG_Python_TypeQuery(const char *type)
+{
+ PyObject *cache = SWIG_Python_TypeCache();
+ PyObject *key = SWIG_Python_str_FromChar(type);
+ PyObject *obj = PyDict_GetItem(cache, key);
+ swig_type_info *descriptor;
+ if (obj) {
+#ifdef SWIGPY_USE_CAPSULE
+ descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL);
+#else
+ descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj);
+#endif
+ } else {
+ swig_module_info *swig_module = SWIG_GetModule(0);
+ descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type);
+ if (descriptor) {
+#ifdef SWIGPY_USE_CAPSULE
+ obj = PyCapsule_New((void*) descriptor, NULL, NULL);
+#else
+ obj = PyCObject_FromVoidPtr(descriptor, NULL);
+#endif
+ PyDict_SetItem(cache, key, obj);
+ Py_DECREF(obj);
+ }
+ }
+ Py_DECREF(key);
+ return descriptor;
+}
+
+/*
+ For backward compatibility only
+*/
+#define SWIG_POINTER_EXCEPTION 0
+#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg)
+#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags)
+
+SWIGRUNTIME int
+SWIG_Python_AddErrMesg(const char* mesg, int infront)
+{
+ if (PyErr_Occurred()) {
+ PyObject *type = 0;
+ PyObject *value = 0;
+ PyObject *traceback = 0;
+ PyErr_Fetch(&type, &value, &traceback);
+ if (value) {
+ char *tmp;
+ PyObject *old_str = PyObject_Str(value);
+ Py_XINCREF(type);
+ PyErr_Clear();
+ if (infront) {
+ PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str));
+ } else {
+ PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg);
+ }
+ SWIG_Python_str_DelForPy3(tmp);
+ Py_DECREF(old_str);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+SWIGRUNTIME int
+SWIG_Python_ArgFail(int argnum)
+{
+ if (PyErr_Occurred()) {
+ /* add information about failing argument */
+ char mesg[256];
+ PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum);
+ return SWIG_Python_AddErrMesg(mesg, 1);
+ } else {
+ return 0;
+ }
+}
+
+SWIGRUNTIMEINLINE const char *
+SwigPyObject_GetDesc(PyObject *self)
+{
+ SwigPyObject *v = (SwigPyObject *)self;
+ swig_type_info *ty = v ? v->ty : 0;
+ return ty ? ty->str : "";
+}
+
+SWIGRUNTIME void
+SWIG_Python_TypeError(const char *type, PyObject *obj)
+{
+ if (type) {
+#if defined(SWIG_COBJECT_TYPES)
+ if (obj && SwigPyObject_Check(obj)) {
+ const char *otype = (const char *) SwigPyObject_GetDesc(obj);
+ if (otype) {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received",
+ type, otype);
+ return;
+ }
+ } else
+#endif
+ {
+ const char *otype = (obj ? obj->ob_type->tp_name : 0);
+ if (otype) {
+ PyObject *str = PyObject_Str(obj);
+ const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0;
+ if (cstr) {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received",
+ type, otype, cstr);
+ SWIG_Python_str_DelForPy3(cstr);
+ } else {
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received",
+ type, otype);
+ }
+ Py_XDECREF(str);
+ return;
+ }
+ }
+ PyErr_Format(PyExc_TypeError, "a '%s' is expected", type);
+ } else {
+ PyErr_Format(PyExc_TypeError, "unexpected type is received");
+ }
+}
+
+
+/* Convert a pointer value, signal an exception on a type mismatch */
+SWIGRUNTIME void *
+SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) {
+ void *result;
+ if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) {
+ PyErr_Clear();
+#if SWIG_POINTER_EXCEPTION
+ if (flags) {
+ SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj);
+ SWIG_Python_ArgFail(argnum);
+ }
+#endif
+ }
+ return result;
+}
+
+#ifdef SWIGPYTHON_BUILTIN
+SWIGRUNTIME int
+SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) {
+ PyTypeObject *tp = obj->ob_type;
+ PyObject *descr;
+ PyObject *encoded_name;
+ descrsetfunc f;
+ int res = -1;
+
+# ifdef Py_USING_UNICODE
+ if (PyString_Check(name)) {
+ name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL);
+ if (!name)
+ return -1;
+ } else if (!PyUnicode_Check(name))
+# else
+ if (!PyString_Check(name))
+# endif
+ {
+ PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name);
+ return -1;
+ } else {
+ Py_INCREF(name);
+ }
+
+ if (!tp->tp_dict) {
+ if (PyType_Ready(tp) < 0)
+ goto done;
+ }
+
+ descr = _PyType_Lookup(tp, name);
+ f = NULL;
+ if (descr != NULL)
+ f = descr->ob_type->tp_descr_set;
+ if (!f) {
+ if (PyString_Check(name)) {
+ encoded_name = name;
+ Py_INCREF(name);
+ } else {
+ encoded_name = PyUnicode_AsUTF8String(name);
+ }
+ PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name));
+ Py_DECREF(encoded_name);
+ } else {
+ res = f(descr, obj, value);
+ }
+
+ done:
+ Py_DECREF(name);
+ return res;
+}
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0)
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else
+
+
+
+ #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0)
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_int swig_types[1]
+#define SWIGTYPE_p_uint8_t swig_types[2]
+static swig_type_info *swig_types[4];
+static swig_module_info swig_module = {swig_types, 3, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#if (PY_VERSION_HEX <= 0x02000000)
+# if !defined(SWIG_PYTHON_CLASSIC)
+# error "This python version requires swig to be run with the '-classic' option"
+# endif
+#endif
+
+/*-----------------------------------------------
+ @(target):= _libwebp.so
+ ------------------------------------------------*/
+#if PY_VERSION_HEX >= 0x03000000
+# define SWIG_init PyInit__libwebp
+
+#else
+# define SWIG_init init_libwebp
+
+#endif
+#define SWIG_name "_libwebp"
+
+#define SWIGVERSION 0x030012
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a))
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a))
+
+
+SWIGINTERNINLINE PyObject*
+ SWIG_From_int (int value)
+{
+ return PyInt_FromLong((long) value);
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+ static int init = 0;
+ static swig_type_info* info = 0;
+ if (!init) {
+ info = SWIG_TypeQuery("_p_char");
+ init = 1;
+ }
+ return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
+{
+#if PY_VERSION_HEX>=0x03000000
+#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
+ if (PyBytes_Check(obj))
+#else
+ if (PyUnicode_Check(obj))
+#endif
+#else
+ if (PyString_Check(obj))
+#endif
+ {
+ char *cstr; Py_ssize_t len;
+#if PY_VERSION_HEX>=0x03000000
+#if !defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
+ if (!alloc && cptr) {
+ /* We can't allow converting without allocation, since the internal
+ representation of string in Python 3 is UCS-2/UCS-4 but we require
+ a UTF-8 representation.
+ TODO(bhy) More detailed explanation */
+ return SWIG_RuntimeError;
+ }
+ obj = PyUnicode_AsUTF8String(obj);
+ if(alloc) *alloc = SWIG_NEWOBJ;
+#endif
+ PyBytes_AsStringAndSize(obj, &cstr, &len);
+#else
+ PyString_AsStringAndSize(obj, &cstr, &len);
+#endif
+ if (cptr) {
+ if (alloc) {
+ /*
+ In python the user should not be able to modify the inner
+ string representation. To warranty that, if you define
+ SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string
+ buffer is always returned.
+
+ The default behavior is just to return the pointer value,
+ so, be careful.
+ */
+#if defined(SWIG_PYTHON_SAFE_CSTRINGS)
+ if (*alloc != SWIG_OLDOBJ)
+#else
+ if (*alloc == SWIG_NEWOBJ)
+#endif
+ {
+ *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1));
+ *alloc = SWIG_NEWOBJ;
+ } else {
+ *cptr = cstr;
+ *alloc = SWIG_OLDOBJ;
+ }
+ } else {
+#if PY_VERSION_HEX>=0x03000000
+#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
+ *cptr = PyBytes_AsString(obj);
+#else
+ assert(0); /* Should never reach here with Unicode strings in Python 3 */
+#endif
+#else
+ *cptr = SWIG_Python_str_AsChar(obj);
+#endif
+ }
+ }
+ if (psize) *psize = len + 1;
+#if PY_VERSION_HEX>=0x03000000 && !defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
+ Py_XDECREF(obj);
+#endif
+ return SWIG_OK;
+ } else {
+#if defined(SWIG_PYTHON_2_UNICODE)
+#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
+#error "Cannot use both SWIG_PYTHON_2_UNICODE and SWIG_PYTHON_STRICT_BYTE_CHAR at once"
+#endif
+#if PY_VERSION_HEX<0x03000000
+ if (PyUnicode_Check(obj)) {
+ char *cstr; Py_ssize_t len;
+ if (!alloc && cptr) {
+ return SWIG_RuntimeError;
+ }
+ obj = PyUnicode_AsUTF8String(obj);
+ if (PyString_AsStringAndSize(obj, &cstr, &len) != -1) {
+ if (cptr) {
+ if (alloc) *alloc = SWIG_NEWOBJ;
+ *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1));
+ }
+ if (psize) *psize = len + 1;
+
+ Py_XDECREF(obj);
+ return SWIG_OK;
+ } else {
+ Py_XDECREF(obj);
+ }
+ }
+#endif
+#endif
+
+ swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+ if (pchar_descriptor) {
+ void* vptr = 0;
+ if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) {
+ if (cptr) *cptr = (char *) vptr;
+ if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0;
+ if (alloc) *alloc = SWIG_OLDOBJ;
+ return SWIG_OK;
+ }
+ }
+ }
+ return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_double (PyObject *obj, double *val)
+{
+ int res = SWIG_TypeError;
+ if (PyFloat_Check(obj)) {
+ if (val) *val = PyFloat_AsDouble(obj);
+ return SWIG_OK;
+#if PY_VERSION_HEX < 0x03000000
+ } else if (PyInt_Check(obj)) {
+ if (val) *val = (double) PyInt_AsLong(obj);
+ return SWIG_OK;
+#endif
+ } else if (PyLong_Check(obj)) {
+ double v = PyLong_AsDouble(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ int dispatch = 0;
+ double d = PyFloat_AsDouble(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = d;
+ return SWIG_AddCast(SWIG_OK);
+ } else {
+ PyErr_Clear();
+ }
+ if (!dispatch) {
+ long v = PyLong_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_AddCast(SWIG_AddCast(SWIG_OK));
+ } else {
+ PyErr_Clear();
+ }
+ }
+ }
+#endif
+ return res;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+ double x = *d;
+ if ((min <= x && x <= max)) {
+ double fx = floor(x);
+ double cx = ceil(x);
+ double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+ if ((errno == EDOM) || (errno == ERANGE)) {
+ errno = 0;
+ } else {
+ double summ, reps, diff;
+ if (rd < x) {
+ diff = x - rd;
+ } else if (rd > x) {
+ diff = rd - x;
+ } else {
+ return 1;
+ }
+ summ = rd + x;
+ reps = diff/summ;
+ if (reps < 8*DBL_EPSILON) {
+ *d = rd;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val)
+{
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check(obj)) {
+ long v = PyInt_AsLong(obj);
+ if (v >= 0) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ return SWIG_OverflowError;
+ }
+ } else
+#endif
+ if (PyLong_Check(obj)) {
+ unsigned long v = PyLong_AsUnsignedLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ return SWIG_OverflowError;
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ int dispatch = 0;
+ unsigned long v = PyLong_AsUnsignedLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_AddCast(SWIG_OK);
+ } else {
+ PyErr_Clear();
+ }
+ if (!dispatch) {
+ double d;
+ int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d));
+ if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) {
+ if (val) *val = (unsigned long)(d);
+ return res;
+ }
+ }
+ }
+#endif
+ return SWIG_TypeError;
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+# define LLONG_MAX __LONG_LONG_MAX__
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+#if defined(LLONG_MAX) && !defined(SWIG_LONG_LONG_AVAILABLE)
+# define SWIG_LONG_LONG_AVAILABLE
+#endif
+
+
+#ifdef SWIG_LONG_LONG_AVAILABLE
+SWIGINTERN int
+SWIG_AsVal_unsigned_SS_long_SS_long (PyObject *obj, unsigned long long *val)
+{
+ int res = SWIG_TypeError;
+ if (PyLong_Check(obj)) {
+ unsigned long long v = PyLong_AsUnsignedLongLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ res = SWIG_OverflowError;
+ }
+ } else {
+ unsigned long v;
+ res = SWIG_AsVal_unsigned_SS_long (obj,&v);
+ if (SWIG_IsOK(res)) {
+ if (val) *val = v;
+ return res;
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ const double mant_max = 1LL << DBL_MANT_DIG;
+ double d;
+ res = SWIG_AsVal_double (obj,&d);
+ if (SWIG_IsOK(res) && !SWIG_CanCastAsInteger(&d, 0, mant_max))
+ return SWIG_OverflowError;
+ if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, mant_max)) {
+ if (val) *val = (unsigned long long)(d);
+ return SWIG_AddCast(res);
+ }
+ res = SWIG_TypeError;
+ }
+#endif
+ return res;
+}
+#endif
+
+
+SWIGINTERNINLINE int
+SWIG_AsVal_size_t (PyObject * obj, size_t *val)
+{
+ int res = SWIG_TypeError;
+#ifdef SWIG_LONG_LONG_AVAILABLE
+ if (sizeof(size_t) <= sizeof(unsigned long)) {
+#endif
+ unsigned long v;
+ res = SWIG_AsVal_unsigned_SS_long (obj, val ? &v : 0);
+ if (SWIG_IsOK(res) && val) *val = (size_t)(v);
+#ifdef SWIG_LONG_LONG_AVAILABLE
+ } else if (sizeof(size_t) <= sizeof(unsigned long long)) {
+ unsigned long long v;
+ res = SWIG_AsVal_unsigned_SS_long_SS_long (obj, val ? &v : 0);
+ if (SWIG_IsOK(res) && val) *val = (size_t)(v);
+ }
+#endif
+ return res;
+}
+
+
+#include "webp/decode.h"
+#include "webp/encode.h"
+
+
+static size_t ReturnedBufferSize(
+ const char* function, int* width, int* height) {
+ static const struct sizemap {
+ const char* function;
+ int size_multiplier;
+ } size_map[] = {
+#ifdef SWIGJAVA
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 },
+ { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 },
+ { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 },
+#endif
+#ifdef SWIGPYTHON
+ { "WebPDecodeRGB", 3 },
+ { "WebPDecodeRGBA", 4 },
+ { "WebPDecodeARGB", 4 },
+ { "WebPDecodeBGR", 3 },
+ { "WebPDecodeBGRA", 4 },
+ { "wrap_WebPEncodeRGB", 1 },
+ { "wrap_WebPEncodeBGR", 1 },
+ { "wrap_WebPEncodeRGBA", 1 },
+ { "wrap_WebPEncodeBGRA", 1 },
+ { "wrap_WebPEncodeLosslessRGB", 1 },
+ { "wrap_WebPEncodeLosslessBGR", 1 },
+ { "wrap_WebPEncodeLosslessRGBA", 1 },
+ { "wrap_WebPEncodeLosslessBGRA", 1 },
+#endif
+ { NULL, 0 }
+ };
+ const struct sizemap* p;
+ size_t size = 0;
+
+ for (p = size_map; p->function; ++p) {
+ if (!strcmp(function, p->function)) {
+ size = *width * *height * p->size_multiplier;
+ break;
+ }
+ }
+
+ return size;
+}
+
+
+typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb,
+ int width, int height, int stride,
+ uint8_t** output);
+
+static uint8_t* EncodeLossy(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor,
+ WebPEncodeFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size =
+ encfn(rgb, width, height, stride, quality_factor, &output);
+ // the values of following two will be interpreted by ReturnedBufferSize()
+ // as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+
+static uint8_t* EncodeLossless(const uint8_t* rgb,
+ int width, int height, int stride,
+ WebPEncodeLosslessFunction encfn,
+ int* output_size, int* unused) {
+ uint8_t* output = NULL;
+ const size_t image_size = encfn(rgb, width, height, stride, &output);
+ // the values of the following two will be interpreted by
+ // ReturnedBufferSize() as 'width' and 'height' in the size calculation.
+ *output_size = image_size;
+ *unused = 1;
+ return image_size ? output : NULL;
+}
+
+
+// Changes the return type of WebPEncode* to more closely match Decode*.
+// This also makes it easier to wrap the output buffer in a native type rather
+// than dealing with the return pointer.
+// The additional parameters are to allow reuse of ReturnedBufferSize(),
+// unused2 and output_size will be used in this case.
+#define LOSSY_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride, float quality_factor) { \
+ return EncodeLossy(rgb, width, height, stride, quality_factor, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSY_WRAPPER(WebPEncodeRGB)
+LOSSY_WRAPPER(WebPEncodeBGR)
+LOSSY_WRAPPER(WebPEncodeRGBA)
+LOSSY_WRAPPER(WebPEncodeBGRA)
+
+#undef LOSSY_WRAPPER
+
+#define LOSSLESS_WRAPPER(FUNC) \
+ static uint8_t* wrap_##FUNC( \
+ const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \
+ int width, int height, int stride) { \
+ return EncodeLossless(rgb, width, height, stride, \
+ FUNC, output_size, unused2); \
+ } \
+
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGB)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGR)
+LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA)
+LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA)
+
+#undef LOSSLESS_WRAPPER
+
+
+
+SWIGINTERN int
+SWIG_AsVal_long (PyObject *obj, long* val)
+{
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check(obj)) {
+ if (val) *val = PyInt_AsLong(obj);
+ return SWIG_OK;
+ } else
+#endif
+ if (PyLong_Check(obj)) {
+ long v = PyLong_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_OK;
+ } else {
+ PyErr_Clear();
+ return SWIG_OverflowError;
+ }
+ }
+#ifdef SWIG_PYTHON_CAST_MODE
+ {
+ int dispatch = 0;
+ long v = PyInt_AsLong(obj);
+ if (!PyErr_Occurred()) {
+ if (val) *val = v;
+ return SWIG_AddCast(SWIG_OK);
+ } else {
+ PyErr_Clear();
+ }
+ if (!dispatch) {
+ double d;
+ int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d));
+ if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+ if (val) *val = (long)(d);
+ return res;
+ }
+ }
+ }
+#endif
+ return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int (PyObject * obj, int *val)
+{
+ long v;
+ int res = SWIG_AsVal_long (obj, &v);
+ if (SWIG_IsOK(res)) {
+ if ((v < INT_MIN || v > INT_MAX)) {
+ return SWIG_OverflowError;
+ } else {
+ if (val) *val = (int)(v);
+ }
+ }
+ return res;
+}
+
+
+/* Getting isfinite working pre C99 across multiple platforms is non-trivial. Users can provide SWIG_isfinite on older platforms. */
+#ifndef SWIG_isfinite
+/* isfinite() is a macro for C99 */
+# if defined(isfinite)
+# define SWIG_isfinite(X) (isfinite(X))
+# elif defined __cplusplus && __cplusplus >= 201103L
+/* Use a template so that this works whether isfinite() is std::isfinite() or
+ * in the global namespace. The reality seems to vary between compiler
+ * versions.
+ *
+ * Make sure namespace std exists to avoid compiler warnings.
+ *
+ * extern "C++" is required as this fragment can end up inside an extern "C" { } block
+ */
+namespace std { }
+extern "C++" template<typename T>
+inline int SWIG_isfinite_func(T x) {
+ using namespace std;
+ return isfinite(x);
+}
+# define SWIG_isfinite(X) (SWIG_isfinite_func(X))
+# elif defined(_MSC_VER)
+# define SWIG_isfinite(X) (_finite(X))
+# elif defined(__sun) && defined(__SVR4)
+# include <ieeefp.h>
+# define SWIG_isfinite(X) (finite(X))
+# endif
+#endif
+
+
+/* Accept infinite as a valid float value unless we are unable to check if a value is finite */
+#ifdef SWIG_isfinite
+# define SWIG_Float_Overflow_Check(X) ((X < -FLT_MAX || X > FLT_MAX) && SWIG_isfinite(X))
+#else
+# define SWIG_Float_Overflow_Check(X) ((X < -FLT_MAX || X > FLT_MAX))
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_float (PyObject * obj, float *val)
+{
+ double v;
+ int res = SWIG_AsVal_double (obj, &v);
+ if (SWIG_IsOK(res)) {
+ if (SWIG_Float_Overflow_Check(v)) {
+ return SWIG_OverflowError;
+ } else {
+ if (val) *val = (float)(v);
+ }
+ }
+ return res;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+SWIGINTERN PyObject *_wrap_WebPGetDecoderVersion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ int result;
+
+ if (!PyArg_ParseTuple(args,(char *)":WebPGetDecoderVersion")) SWIG_fail;
+ result = (int)WebPGetDecoderVersion();
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPGetInfo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ int result;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPGetInfo",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPGetInfo" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4);
+ resultobj = SWIG_From_int((int)(result));
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPDecodeRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeRGB",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeRGB" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (uint8_t *)WebPDecodeRGB((uint8_t const *)arg1,arg2,arg3,arg4);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeRGB", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ free(result);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPDecodeRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeRGBA",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeRGBA" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (uint8_t *)WebPDecodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeRGBA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ free(result);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPDecodeARGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeARGB",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeARGB" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (uint8_t *)WebPDecodeARGB((uint8_t const *)arg1,arg2,arg3,arg4);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeARGB", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ free(result);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPDecodeBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeBGR",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeBGR" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (uint8_t *)WebPDecodeBGR((uint8_t const *)arg1,arg2,arg3,arg4);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeBGR", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ free(result);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPDecodeBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ size_t arg2 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int res1 ;
+ char *buf1 = 0 ;
+ size_t size1 = 0 ;
+ int alloc1 = 0 ;
+ int temp3 ;
+ int res3 = SWIG_TMPOBJ ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ PyObject * obj0 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg3 = &temp3;
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeBGRA",&obj0)) SWIG_fail;
+ res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1);
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeBGRA" "', argument " "1"" of type '" "uint8_t const *""'");
+ }
+ arg1 = (uint8_t *)(buf1);
+ arg2 = (size_t)(size1 - 1);
+ result = (uint8_t *)WebPDecodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeBGRA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res3)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ free(result);
+ return resultobj;
+fail:
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_WebPGetEncoderVersion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ int result;
+
+ if (!PyArg_ParseTuple(args,(char *)":WebPGetEncoderVersion")) SWIG_fail;
+ result = (int)WebPGetEncoderVersion();
+ resultobj = SWIG_From_int((int)(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ float val8 ;
+ int ecode8 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ PyObject * obj6 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeRGB",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeRGB', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeRGB', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGB" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGB" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeRGB" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeRGB" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeRGB" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ ecode8 = SWIG_AsVal_float(obj6, &val8);
+ if (!SWIG_IsOK(ecode8)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeRGB" "', argument " "8"" of type '" "float""'");
+ }
+ arg8 = (float)(val8);
+ result = (uint8_t *)wrap_WebPEncodeRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeRGB", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ float val8 ;
+ int ecode8 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ PyObject * obj6 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeBGR",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeBGR', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeBGR', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGR" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGR" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeBGR" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeBGR" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeBGR" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ ecode8 = SWIG_AsVal_float(obj6, &val8);
+ if (!SWIG_IsOK(ecode8)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeBGR" "', argument " "8"" of type '" "float""'");
+ }
+ arg8 = (float)(val8);
+ result = (uint8_t *)wrap_WebPEncodeBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeBGR", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ float val8 ;
+ int ecode8 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ PyObject * obj6 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeRGBA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeRGBA', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeRGBA', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGBA" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGBA" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeRGBA" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeRGBA" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeRGBA" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ ecode8 = SWIG_AsVal_float(obj6, &val8);
+ if (!SWIG_IsOK(ecode8)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeRGBA" "', argument " "8"" of type '" "float""'");
+ }
+ arg8 = (float)(val8);
+ result = (uint8_t *)wrap_WebPEncodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeRGBA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ float arg8 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ float val8 ;
+ int ecode8 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ PyObject * obj6 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeBGRA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeBGRA', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeBGRA', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGRA" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGRA" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeBGRA" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeBGRA" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeBGRA" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ ecode8 = SWIG_AsVal_float(obj6, &val8);
+ if (!SWIG_IsOK(ecode8)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeBGRA" "', argument " "8"" of type '" "float""'");
+ }
+ arg8 = (float)(val8);
+ result = (uint8_t *)wrap_WebPEncodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeBGRA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessRGB",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeLosslessRGB', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeLosslessRGB', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ result = (uint8_t *)wrap_WebPEncodeLosslessRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessRGB", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessBGR",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeLosslessBGR', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeLosslessBGR', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ result = (uint8_t *)wrap_WebPEncodeLosslessBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessBGR", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessRGBA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeLosslessRGBA', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeLosslessRGBA', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ result = (uint8_t *)wrap_WebPEncodeLosslessRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessRGBA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ uint8_t *arg1 = (uint8_t *) 0 ;
+ int *arg2 = (int *) 0 ;
+ int *arg3 = (int *) 0 ;
+ int *arg4 = (int *) 0 ;
+ int arg5 ;
+ int arg6 ;
+ int arg7 ;
+ Py_buffer rgb_buffer1 ;
+ int temp2 ;
+ int res2 = 0 ;
+ int temp3 ;
+ int res3 = 0 ;
+ int temp4 ;
+ int res4 = SWIG_TMPOBJ ;
+ int val5 ;
+ int ecode5 = 0 ;
+ int val6 ;
+ int ecode6 = 0 ;
+ int val7 ;
+ int ecode7 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ PyObject * obj4 = 0 ;
+ PyObject * obj5 = 0 ;
+ uint8_t *result = 0 ;
+
+ arg4 = &temp4;
+ if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessBGRA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+ {
+ // NB: with Python < 2.6 the old style buffer protocol may be used:
+ // Py_ssize_t unused;
+ // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused);
+ if (!PyObject_CheckBuffer(obj0)) {
+ SWIG_exception_fail(SWIG_TypeError,
+ "in method 'wrap_WebPEncodeLosslessBGRA', argument 1"
+ " does not support the buffer interface");
+ }
+ if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) {
+ SWIG_exception_fail(SWIG_RuntimeError,
+ "in method 'wrap_WebPEncodeLosslessBGRA', unable to get buffer view");
+ }
+ arg1 = (uint8_t *)rgb_buffer1.buf;
+ }
+ if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj1, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "2"" of type '" "int""'");
+ }
+ temp2 = (int)(val);
+ arg2 = &temp2;
+ res2 = SWIG_AddTmpMask(ecode);
+ }
+ if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) {
+ int val;
+ int ecode = SWIG_AsVal_int(obj2, &val);
+ if (!SWIG_IsOK(ecode)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "3"" of type '" "int""'");
+ }
+ temp3 = (int)(val);
+ arg3 = &temp3;
+ res3 = SWIG_AddTmpMask(ecode);
+ }
+ ecode5 = SWIG_AsVal_int(obj3, &val5);
+ if (!SWIG_IsOK(ecode5)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "5"" of type '" "int""'");
+ }
+ arg5 = (int)(val5);
+ ecode6 = SWIG_AsVal_int(obj4, &val6);
+ if (!SWIG_IsOK(ecode6)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "6"" of type '" "int""'");
+ }
+ arg6 = (int)(val6);
+ ecode7 = SWIG_AsVal_int(obj5, &val7);
+ if (!SWIG_IsOK(ecode7)) {
+ SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "7"" of type '" "int""'");
+ }
+ arg7 = (int)(val7);
+ result = (uint8_t *)wrap_WebPEncodeLosslessBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7);
+ {
+ resultobj = PyString_FromStringAndSize(
+ (const char*)result,
+ (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessBGRA", arg3, arg4));
+ }
+ if (SWIG_IsTmpObj(res4)) {
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+ } else {
+ int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ;
+ resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+ }
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ free(result);
+ return resultobj;
+fail:
+ {
+ PyBuffer_Release(&rgb_buffer1);
+ }
+ if (SWIG_IsNewObj(res2)) free((char*)arg2);
+ if (SWIG_IsNewObj(res3)) free((char*)arg3);
+ return NULL;
+}
+
+
+static PyMethodDef SwigMethods[] = {
+ { "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL},
+ { "WebPGetDecoderVersion", _wrap_WebPGetDecoderVersion, METH_VARARGS, (char *)"WebPGetDecoderVersion() -> int"},
+ { "WebPGetInfo", _wrap_WebPGetInfo, METH_VARARGS, (char *)"WebPGetInfo(uint8_t data) -> (width, height)"},
+ { "WebPDecodeRGB", _wrap_WebPDecodeRGB, METH_VARARGS, (char *)"WebPDecodeRGB(uint8_t data) -> (rgb, width, height)"},
+ { "WebPDecodeRGBA", _wrap_WebPDecodeRGBA, METH_VARARGS, (char *)"WebPDecodeRGBA(uint8_t data) -> (rgb, width, height)"},
+ { "WebPDecodeARGB", _wrap_WebPDecodeARGB, METH_VARARGS, (char *)"WebPDecodeARGB(uint8_t data) -> (rgb, width, height)"},
+ { "WebPDecodeBGR", _wrap_WebPDecodeBGR, METH_VARARGS, (char *)"WebPDecodeBGR(uint8_t data) -> (rgb, width, height)"},
+ { "WebPDecodeBGRA", _wrap_WebPDecodeBGRA, METH_VARARGS, (char *)"WebPDecodeBGRA(uint8_t data) -> (rgb, width, height)"},
+ { "WebPGetEncoderVersion", _wrap_WebPGetEncoderVersion, METH_VARARGS, (char *)"WebPGetEncoderVersion() -> int"},
+ { "wrap_WebPEncodeRGB", _wrap_wrap_WebPEncodeRGB, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeBGR", _wrap_wrap_WebPEncodeBGR, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeRGBA", _wrap_wrap_WebPEncodeRGBA, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeBGRA", _wrap_wrap_WebPEncodeBGRA, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeLosslessRGB", _wrap_wrap_WebPEncodeLosslessRGB, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeLosslessBGR", _wrap_wrap_WebPEncodeLosslessBGR, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeLosslessRGBA", _wrap_wrap_WebPEncodeLosslessRGBA, METH_VARARGS, (char *)"private, do not call directly."},
+ { "wrap_WebPEncodeLosslessBGRA", _wrap_wrap_WebPEncodeLosslessBGRA, METH_VARARGS, (char *)"private, do not call directly."},
+ { NULL, NULL, 0, NULL }
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_uint8_t = {"_p_uint8_t", "uint8_t *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+ &_swigt__p_char,
+ &_swigt__p_int,
+ &_swigt__p_uint8_t,
+};
+
+static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_uint8_t[] = { {&_swigt__p_uint8_t, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+ _swigc__p_char,
+ _swigc__p_int,
+ _swigc__p_uint8_t,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+{0, 0, 0, 0.0, 0, 0}};
+
+#ifdef __cplusplus
+}
+#endif
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic
+ * memory is used. Also, since swig_type_info structures store pointers to
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization.
+ * The idea is that swig generates all the structures that are needed.
+ * The runtime then collects these partially filled structures.
+ * The SWIG_InitializeModule function takes these initial arrays out of
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned statically to an initial
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded.
+ * There are three cases to handle:
+ * 1) If the cast->type has already been loaded AND the type we are adding
+ * casting info to has not been loaded (it is in this module), THEN we
+ * replace the cast->type pointer with the type pointer that has already
+ * been loaded.
+ * 2) If BOTH types (the one we are adding casting info to, and the
+ * cast->type) are loaded, THEN the cast info has already been loaded by
+ * the previous module so we just ignore it.
+ * 3) Finally, if cast->type has not already been loaded, then we add that
+ * swig_cast_info to the linked list (because the cast->type) pointer will
+ * be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+ size_t i;
+ swig_module_info *module_head, *iter;
+ int init;
+
+ /* check to see if the circular list has been setup, if not, set it up */
+ if (swig_module.next==0) {
+ /* Initialize the swig_module */
+ swig_module.type_initial = swig_type_initial;
+ swig_module.cast_initial = swig_cast_initial;
+ swig_module.next = &swig_module;
+ init = 1;
+ } else {
+ init = 0;
+ }
+
+ /* Try and load any already created modules */
+ module_head = SWIG_GetModule(clientdata);
+ if (!module_head) {
+ /* This is the first module loaded for this interpreter */
+ /* so set the swig module into the interpreter */
+ SWIG_SetModule(clientdata, &swig_module);
+ } else {
+ /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+ iter=module_head;
+ do {
+ if (iter==&swig_module) {
+ /* Our module is already in the list, so there's nothing more to do. */
+ return;
+ }
+ iter=iter->next;
+ } while (iter!= module_head);
+
+ /* otherwise we must add our module into the list */
+ swig_module.next = module_head->next;
+ module_head->next = &swig_module;
+ }
+
+ /* When multiple interpreters are used, a module could have already been initialized in
+ a different interpreter, but not yet have a pointer in this interpreter.
+ In this case, we do not want to continue adding types... everything should be
+ set up already */
+ if (init == 0) return;
+
+ /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+ for (i = 0; i < swig_module.size; ++i) {
+ swig_type_info *type = 0;
+ swig_type_info *ret;
+ swig_cast_info *cast;
+
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+
+ /* if there is another module already loaded */
+ if (swig_module.next != &swig_module) {
+ type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+ }
+ if (type) {
+ /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+ if (swig_module.type_initial[i]->clientdata) {
+ type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+ }
+ } else {
+ type = swig_module.type_initial[i];
+ }
+
+ /* Insert casting types */
+ cast = swig_module.cast_initial[i];
+ while (cast->type) {
+ /* Don't need to add information already in the list */
+ ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+ if (swig_module.next != &swig_module) {
+ ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+ if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+ }
+ if (ret) {
+ if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+ cast->type = ret;
+ ret = 0;
+ } else {
+ /* Check for casting already in the list */
+ swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+ if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+ if (!ocast) ret = 0;
+ }
+ }
+
+ if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+ printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+ if (type->cast) {
+ type->cast->prev = cast;
+ cast->next = type->cast;
+ }
+ type->cast = cast;
+ }
+ cast++;
+ }
+ /* Set entry in modules->types array equal to the type */
+ swig_module.types[i] = type;
+ }
+ swig_module.types[i] = 0;
+
+#ifdef SWIGRUNTIME_DEBUG
+ printf("**** SWIG_InitializeModule: Cast List ******\n");
+ for (i = 0; i < swig_module.size; ++i) {
+ int j = 0;
+ swig_cast_info *cast = swig_module.cast_initial[i];
+ printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+ while (cast->type) {
+ printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+ cast++;
+ ++j;
+ }
+ printf("---- Total casts: %d\n",j);
+ }
+ printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types. It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+ size_t i;
+ swig_cast_info *equiv;
+ static int init_run = 0;
+
+ if (init_run) return;
+ init_run = 1;
+
+ for (i = 0; i < swig_module.size; i++) {
+ if (swig_module.types[i]->clientdata) {
+ equiv = swig_module.types[i]->cast;
+ while (equiv) {
+ if (!equiv->converter) {
+ if (equiv->type && !equiv->type->clientdata)
+ SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+ }
+ equiv = equiv->next;
+ }
+ }
+ }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+ /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Python-specific SWIG API */
+#define SWIG_newvarlink() SWIG_Python_newvarlink()
+#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr)
+#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants)
+
+ /* -----------------------------------------------------------------------------
+ * global variable support code.
+ * ----------------------------------------------------------------------------- */
+
+ typedef struct swig_globalvar {
+ char *name; /* Name of global variable */
+ PyObject *(*get_attr)(void); /* Return the current value */
+ int (*set_attr)(PyObject *); /* Set the value */
+ struct swig_globalvar *next;
+ } swig_globalvar;
+
+ typedef struct swig_varlinkobject {
+ PyObject_HEAD
+ swig_globalvar *vars;
+ } swig_varlinkobject;
+
+ SWIGINTERN PyObject *
+ swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) {
+#if PY_VERSION_HEX >= 0x03000000
+ return PyUnicode_InternFromString("<Swig global variables>");
+#else
+ return PyString_FromString("<Swig global variables>");
+#endif
+ }
+
+ SWIGINTERN PyObject *
+ swig_varlink_str(swig_varlinkobject *v) {
+#if PY_VERSION_HEX >= 0x03000000
+ PyObject *str = PyUnicode_InternFromString("(");
+ PyObject *tail;
+ PyObject *joined;
+ swig_globalvar *var;
+ for (var = v->vars; var; var=var->next) {
+ tail = PyUnicode_FromString(var->name);
+ joined = PyUnicode_Concat(str, tail);
+ Py_DecRef(str);
+ Py_DecRef(tail);
+ str = joined;
+ if (var->next) {
+ tail = PyUnicode_InternFromString(", ");
+ joined = PyUnicode_Concat(str, tail);
+ Py_DecRef(str);
+ Py_DecRef(tail);
+ str = joined;
+ }
+ }
+ tail = PyUnicode_InternFromString(")");
+ joined = PyUnicode_Concat(str, tail);
+ Py_DecRef(str);
+ Py_DecRef(tail);
+ str = joined;
+#else
+ PyObject *str = PyString_FromString("(");
+ swig_globalvar *var;
+ for (var = v->vars; var; var=var->next) {
+ PyString_ConcatAndDel(&str,PyString_FromString(var->name));
+ if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", "));
+ }
+ PyString_ConcatAndDel(&str,PyString_FromString(")"));
+#endif
+ return str;
+ }
+
+ SWIGINTERN int
+ swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) {
+ char *tmp;
+ PyObject *str = swig_varlink_str(v);
+ fprintf(fp,"Swig global variables ");
+ fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str));
+ SWIG_Python_str_DelForPy3(tmp);
+ Py_DECREF(str);
+ return 0;
+ }
+
+ SWIGINTERN void
+ swig_varlink_dealloc(swig_varlinkobject *v) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ swig_globalvar *n = var->next;
+ free(var->name);
+ free(var);
+ var = n;
+ }
+ }
+
+ SWIGINTERN PyObject *
+ swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+ PyObject *res = NULL;
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ res = (*var->get_attr)();
+ break;
+ }
+ var = var->next;
+ }
+ if (res == NULL && !PyErr_Occurred()) {
+ PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n);
+ }
+ return res;
+ }
+
+ SWIGINTERN int
+ swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+ int res = 1;
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ res = (*var->set_attr)(p);
+ break;
+ }
+ var = var->next;
+ }
+ if (res == 1 && !PyErr_Occurred()) {
+ PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n);
+ }
+ return res;
+ }
+
+ SWIGINTERN PyTypeObject*
+ swig_varlink_type(void) {
+ static char varlink__doc__[] = "Swig var link object";
+ static PyTypeObject varlink_type;
+ static int type_init = 0;
+ if (!type_init) {
+ const PyTypeObject tmp = {
+#if PY_VERSION_HEX >= 0x03000000
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+#endif
+ (char *)"swigvarlink", /* tp_name */
+ sizeof(swig_varlinkobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) swig_varlink_dealloc, /* tp_dealloc */
+ (printfunc) swig_varlink_print, /* tp_print */
+ (getattrfunc) swig_varlink_getattr, /* tp_getattr */
+ (setattrfunc) swig_varlink_setattr, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc) swig_varlink_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc) swig_varlink_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ 0, /* tp_flags */
+ varlink__doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+ 0, /* tp_del */
+#endif
+#if PY_VERSION_HEX >= 0x02060000
+ 0, /* tp_version_tag */
+#endif
+#if PY_VERSION_HEX >= 0x03040000
+ 0, /* tp_finalize */
+#endif
+#ifdef COUNT_ALLOCS
+ 0, /* tp_allocs */
+ 0, /* tp_frees */
+ 0, /* tp_maxalloc */
+#if PY_VERSION_HEX >= 0x02050000
+ 0, /* tp_prev */
+#endif
+ 0 /* tp_next */
+#endif
+ };
+ varlink_type = tmp;
+ type_init = 1;
+#if PY_VERSION_HEX < 0x02020000
+ varlink_type.ob_type = &PyType_Type;
+#else
+ if (PyType_Ready(&varlink_type) < 0)
+ return NULL;
+#endif
+ }
+ return &varlink_type;
+ }
+
+ /* Create a variable linking object for use later */
+ SWIGINTERN PyObject *
+ SWIG_Python_newvarlink(void) {
+ swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type());
+ if (result) {
+ result->vars = 0;
+ }
+ return ((PyObject*) result);
+ }
+
+ SWIGINTERN void
+ SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+ swig_varlinkobject *v = (swig_varlinkobject *) p;
+ swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+ if (gv) {
+ size_t size = strlen(name)+1;
+ gv->name = (char *)malloc(size);
+ if (gv->name) {
+ strncpy(gv->name,name,size);
+ gv->get_attr = get_attr;
+ gv->set_attr = set_attr;
+ gv->next = v->vars;
+ }
+ }
+ v->vars = gv;
+ }
+
+ SWIGINTERN PyObject *
+ SWIG_globals(void) {
+ static PyObject *_SWIG_globals = 0;
+ if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink();
+ return _SWIG_globals;
+ }
+
+ /* -----------------------------------------------------------------------------
+ * constants/methods manipulation
+ * ----------------------------------------------------------------------------- */
+
+ /* Install Constants */
+ SWIGINTERN void
+ SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) {
+ PyObject *obj = 0;
+ size_t i;
+ for (i = 0; constants[i].type; ++i) {
+ switch(constants[i].type) {
+ case SWIG_PY_POINTER:
+ obj = SWIG_InternalNewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0);
+ break;
+ case SWIG_PY_BINARY:
+ obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype));
+ break;
+ default:
+ obj = 0;
+ break;
+ }
+ if (obj) {
+ PyDict_SetItemString(d, constants[i].name, obj);
+ Py_DECREF(obj);
+ }
+ }
+ }
+
+ /* -----------------------------------------------------------------------------*/
+ /* Fix SwigMethods to carry the callback ptrs when needed */
+ /* -----------------------------------------------------------------------------*/
+
+ SWIGINTERN void
+ SWIG_Python_FixMethods(PyMethodDef *methods,
+ swig_const_info *const_table,
+ swig_type_info **types,
+ swig_type_info **types_initial) {
+ size_t i;
+ for (i = 0; methods[i].ml_name; ++i) {
+ const char *c = methods[i].ml_doc;
+ if (!c) continue;
+ c = strstr(c, "swig_ptr: ");
+ if (c) {
+ int j;
+ swig_const_info *ci = 0;
+ const char *name = c + 10;
+ for (j = 0; const_table[j].type; ++j) {
+ if (strncmp(const_table[j].name, name,
+ strlen(const_table[j].name)) == 0) {
+ ci = &(const_table[j]);
+ break;
+ }
+ }
+ if (ci) {
+ void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0;
+ if (ptr) {
+ size_t shift = (ci->ptype) - types;
+ swig_type_info *ty = types_initial[shift];
+ size_t ldoc = (c - methods[i].ml_doc);
+ size_t lptr = strlen(ty->name)+2*sizeof(void*)+2;
+ char *ndoc = (char*)malloc(ldoc + lptr + 10);
+ if (ndoc) {
+ char *buff = ndoc;
+ memcpy(buff, methods[i].ml_doc, ldoc);
+ buff += ldoc;
+ memcpy(buff, "swig_ptr: ", 10);
+ buff += 10;
+ SWIG_PackVoidPtr(buff, ptr, ty->name, lptr);
+ methods[i].ml_doc = ndoc;
+ }
+ }
+ }
+ }
+ }
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------*
+ * Partial Init method
+ * -----------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+SWIGEXPORT
+#if PY_VERSION_HEX >= 0x03000000
+PyObject*
+#else
+void
+#endif
+SWIG_init(void) {
+ PyObject *m, *d, *md;
+#if PY_VERSION_HEX >= 0x03000000
+ static struct PyModuleDef SWIG_module = {
+# if PY_VERSION_HEX >= 0x03020000
+ PyModuleDef_HEAD_INIT,
+# else
+ {
+ PyObject_HEAD_INIT(NULL)
+ NULL, /* m_init */
+ 0, /* m_index */
+ NULL, /* m_copy */
+ },
+# endif
+ (char *) SWIG_name,
+ NULL,
+ -1,
+ SwigMethods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+#endif
+
+#if defined(SWIGPYTHON_BUILTIN)
+ static SwigPyClientData SwigPyObject_clientdata = {
+ 0, 0, 0, 0, 0, 0, 0
+ };
+ static PyGetSetDef this_getset_def = {
+ (char *)"this", &SwigPyBuiltin_ThisClosure, NULL, NULL, NULL
+ };
+ static SwigPyGetSet thisown_getset_closure = {
+ SwigPyObject_own,
+ SwigPyObject_own
+ };
+ static PyGetSetDef thisown_getset_def = {
+ (char *)"thisown", SwigPyBuiltin_GetterClosure, SwigPyBuiltin_SetterClosure, NULL, &thisown_getset_closure
+ };
+ PyTypeObject *builtin_pytype;
+ int builtin_base_count;
+ swig_type_info *builtin_basetype;
+ PyObject *tuple;
+ PyGetSetDescrObject *static_getset;
+ PyTypeObject *metatype;
+ PyTypeObject *swigpyobject;
+ SwigPyClientData *cd;
+ PyObject *public_interface, *public_symbol;
+ PyObject *this_descr;
+ PyObject *thisown_descr;
+ PyObject *self = 0;
+ int i;
+
+ (void)builtin_pytype;
+ (void)builtin_base_count;
+ (void)builtin_basetype;
+ (void)tuple;
+ (void)static_getset;
+ (void)self;
+
+ /* Metaclass is used to implement static member variables */
+ metatype = SwigPyObjectType();
+ assert(metatype);
+#endif
+
+ /* Fix SwigMethods to carry the callback ptrs when needed */
+ SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial);
+
+#if PY_VERSION_HEX >= 0x03000000
+ m = PyModule_Create(&SWIG_module);
+#else
+ m = Py_InitModule((char *) SWIG_name, SwigMethods);
+#endif
+
+ md = d = PyModule_GetDict(m);
+ (void)md;
+
+ SWIG_InitializeModule(0);
+
+#ifdef SWIGPYTHON_BUILTIN
+ swigpyobject = SwigPyObject_TypeOnce();
+
+ SwigPyObject_stype = SWIG_MangledTypeQuery("_p_SwigPyObject");
+ assert(SwigPyObject_stype);
+ cd = (SwigPyClientData*) SwigPyObject_stype->clientdata;
+ if (!cd) {
+ SwigPyObject_stype->clientdata = &SwigPyObject_clientdata;
+ SwigPyObject_clientdata.pytype = swigpyobject;
+ } else if (swigpyobject->tp_basicsize != cd->pytype->tp_basicsize) {
+ PyErr_SetString(PyExc_RuntimeError, "Import error: attempted to load two incompatible swig-generated modules.");
+# if PY_VERSION_HEX >= 0x03000000
+ return NULL;
+# else
+ return;
+# endif
+ }
+
+ /* All objects have a 'this' attribute */
+ this_descr = PyDescr_NewGetSet(SwigPyObject_type(), &this_getset_def);
+ (void)this_descr;
+
+ /* All objects have a 'thisown' attribute */
+ thisown_descr = PyDescr_NewGetSet(SwigPyObject_type(), &thisown_getset_def);
+ (void)thisown_descr;
+
+ public_interface = PyList_New(0);
+ public_symbol = 0;
+ (void)public_symbol;
+
+ PyDict_SetItemString(md, "__all__", public_interface);
+ Py_DECREF(public_interface);
+ for (i = 0; SwigMethods[i].ml_name != NULL; ++i)
+ SwigPyBuiltin_AddPublicSymbol(public_interface, SwigMethods[i].ml_name);
+ for (i = 0; swig_const_table[i].name != 0; ++i)
+ SwigPyBuiltin_AddPublicSymbol(public_interface, swig_const_table[i].name);
+#endif
+
+ SWIG_InstallConstants(d,swig_const_table);
+
+#if PY_VERSION_HEX >= 0x03000000
+ return m;
+#else
+ return;
+#endif
+}
+
diff --git a/swig/setup.py b/swig/setup.py
new file mode 100644
index 0000000..3a3bfe1
--- /dev/null
+++ b/swig/setup.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+"""distutils script for libwebp python module."""
+
+from distutils.core import setup
+from distutils.extension import Extension
+import os
+import shutil
+import tempfile
+
+tmpdir = tempfile.mkdtemp()
+package = "com.google.webp"
+package_path = os.path.join(tmpdir, *package.split("."))
+os.makedirs(package_path)
+
+# Create __init_.py files along the package path.
+initpy_path = tmpdir
+for d in package.split("."):
+ initpy_path = os.path.join(initpy_path, d)
+ open(os.path.join(initpy_path, "__init__.py"), "w").close()
+
+shutil.copy2("libwebp.py", package_path)
+setup(name="libwebp",
+ version="0.0",
+ description="libwebp python wrapper",
+ long_description="Provides access to 'simple' libwebp decode interface",
+ license="BSD",
+ url="http://developers.google.com/speed/webp",
+ ext_package=package,
+ ext_modules=[Extension("_libwebp",
+ ["libwebp_python_wrap.c"],
+ libraries=["webp"],
+ ),
+ ],
+ package_dir={"": tmpdir},
+ packages=["com", "com.google", "com.google.webp"],
+ py_modules=[package + ".libwebp"],
+ )
+
+shutil.rmtree(tmpdir)
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..91daba2
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,18 @@
+# Tests
+
+This is a collection of tests for the libwebp libraries, currently covering
+fuzzing through the APIs. Additional test vector coverage can be found at:
+https://chromium.googlesource.com/webm/libwebp-test-data
+
+## Building
+
+### Fuzzers
+
+Follow the [build instructions](../doc/building.md) for libwebp, optionally
+adding build flags for various sanitizers (e.g., -fsanitize=address).
+
+`fuzzer/makefile.unix` can then be used to compile the fuzzer targets:
+
+```shell
+$ make -C fuzzer -f makefile.unix
+```
diff --git a/tests/fuzzer/advanced_api_fuzzer.c b/tests/fuzzer/advanced_api_fuzzer.c
index da4613b..1378d0b 100644
--- a/tests/fuzzer/advanced_api_fuzzer.c
+++ b/tests/fuzzer/advanced_api_fuzzer.c
@@ -14,8 +14,12 @@
//
////////////////////////////////////////////////////////////////////////////////
+#include <stdint.h>
+#include <string.h>
+
#include "./fuzz_utils.h"
-#include "webp/decode.h"
+#include "src/utils/rescaler_utils.h"
+#include "src/webp/decode.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPDecoderConfig config;
@@ -59,39 +63,74 @@
config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST);
#endif // WEBP_REDUCE_CSP
- if (size % 3) {
- // Decodes incrementally in chunks of increasing size.
- WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
- if (!idec) return 0;
- VP8StatusCode status;
- if (size & 8) {
- size_t available_size = value + 1;
- while (1) {
- if (available_size > size) available_size = size;
- status = WebPIUpdate(idec, data, available_size);
- if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
- available_size *= 2;
- }
- } else {
- // WebPIAppend expects new data and its size with each call.
- // Implemented here by simply advancing the pointer into data.
- const uint8_t* new_data = data;
- size_t new_size = value + 1;
- while (1) {
- if (new_data + new_size > data + size) {
- new_size = data + size - new_data;
+ for (int i = 0; i < 2; ++i) {
+ if (i == 1) {
+ // Use the bitstream data to generate extreme ranges for the options. An
+ // alternative approach would be to use a custom corpus containing webp
+ // files prepended with sizeof(config.options) zeroes to allow the fuzzer
+ // to modify these independently.
+ const int data_offset = 50;
+ if (data_offset + sizeof(config.options) >= size) break;
+ memcpy(&config.options, data + data_offset, sizeof(config.options));
+
+ // Skip easily avoidable out-of-memory fuzzing errors.
+ if (config.options.use_scaling) {
+ int scaled_width = config.options.scaled_width;
+ int scaled_height = config.options.scaled_height;
+ if (WebPRescalerGetScaledDimensions(config.input.width,
+ config.input.height, &scaled_width,
+ &scaled_height)) {
+ size_t fuzz_px_limit = kFuzzPxLimit;
+ if (scaled_width != config.input.width ||
+ scaled_height != config.input.height) {
+ // Using the WebPRescalerImport internally can significantly slow
+ // down the execution. Avoid timeouts due to that.
+ fuzz_px_limit /= 2;
+ }
+ // A big output canvas can lead to out-of-memory and timeout issues,
+ // but a big internal working buffer can too.
+ if ((uint64_t)scaled_width * scaled_height > fuzz_px_limit ||
+ (uint64_t)config.input.width * config.input.height >
+ fuzz_px_limit) {
+ break;
+ }
}
- status = WebPIAppend(idec, new_data, new_size);
- if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
- new_data += new_size;
- new_size *= 2;
}
}
- WebPIDelete(idec);
- } else {
- WebPDecode(data, size, &config);
- }
+ if (size % 3) {
+ // Decodes incrementally in chunks of increasing size.
+ WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
+ if (!idec) return 0;
+ VP8StatusCode status;
+ if (size & 8) {
+ size_t available_size = value + 1;
+ while (1) {
+ if (available_size > size) available_size = size;
+ status = WebPIUpdate(idec, data, available_size);
+ if (status != VP8_STATUS_SUSPENDED || available_size == size) break;
+ available_size *= 2;
+ }
+ } else {
+ // WebPIAppend expects new data and its size with each call.
+ // Implemented here by simply advancing the pointer into data.
+ const uint8_t* new_data = data;
+ size_t new_size = value + 1;
+ while (1) {
+ if (new_data + new_size > data + size) {
+ new_size = data + size - new_data;
+ }
+ status = WebPIAppend(idec, new_data, new_size);
+ if (status != VP8_STATUS_SUSPENDED || new_size == 0) break;
+ new_data += new_size;
+ new_size *= 2;
+ }
+ }
+ WebPIDelete(idec);
+ } else {
+ WebPDecode(data, size, &config);
+ }
- WebPFreeDecBuffer(&config.output);
+ WebPFreeDecBuffer(&config.output);
+ }
return 0;
}
diff --git a/tests/fuzzer/animation_api_fuzzer.c b/tests/fuzzer/animation_api_fuzzer.c
index 30d6074..187ed24 100644
--- a/tests/fuzzer/animation_api_fuzzer.c
+++ b/tests/fuzzer/animation_api_fuzzer.c
@@ -15,9 +15,9 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
-#include "webp/decode.h"
-#include "webp/demux.h"
-#include "webp/mux_types.h"
+#include "src/webp/decode.h"
+#include "src/webp/demux.h"
+#include "src/webp/mux_types.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPData webp_data;
diff --git a/tests/fuzzer/animdecoder_fuzzer.cc b/tests/fuzzer/animdecoder_fuzzer.cc
index 2d9e2d5..a79712d 100644
--- a/tests/fuzzer/animdecoder_fuzzer.cc
+++ b/tests/fuzzer/animdecoder_fuzzer.cc
@@ -16,7 +16,7 @@
#include "examples/anim_util.h"
#include "imageio/imageio_util.h"
-#include "webp/demux.h"
+#include "src/webp/demux.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// WebPAnimDecoderGetInfo() is too late to check the canvas size as
@@ -35,13 +35,18 @@
if (dec == NULL) return 0;
WebPAnimInfo info;
- if (!WebPAnimDecoderGetInfo(dec, &info)) return 0;
+ if (!WebPAnimDecoderGetInfo(dec, &info)) goto End;
+ if (!ImgIoUtilCheckSizeArgumentsOverflow(info.canvas_width * 4,
+ info.canvas_height)) {
+ goto End;
+ }
while (WebPAnimDecoderHasMoreFrames(dec)) {
uint8_t* buf;
int timestamp;
if (!WebPAnimDecoderGetNext(dec, &buf, ×tamp)) break;
}
+ End:
WebPAnimDecoderDelete(dec);
return 0;
}
diff --git a/tests/fuzzer/animencoder_fuzzer.cc b/tests/fuzzer/animencoder_fuzzer.cc
index 58a266f..1bd7871 100644
--- a/tests/fuzzer/animencoder_fuzzer.cc
+++ b/tests/fuzzer/animencoder_fuzzer.cc
@@ -18,8 +18,8 @@
#include <stdlib.h>
#include "./fuzz_utils.h"
-#include "webp/encode.h"
-#include "webp/mux.h"
+#include "src/webp/encode.h"
+#include "src/webp/mux.h"
namespace {
@@ -46,24 +46,32 @@
// Read the source picture.
if (!ExtractSourcePicture(&pic, data, size, bit_pos)) {
- fprintf(stderr, "Can't read input image.\n");
+ const WebPEncodingError error_code = pic.error_code;
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
abort();
}
// Crop and scale.
if (*enc == nullptr) { // First frame will set canvas width and height.
if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) {
- fprintf(stderr, "ExtractAndCropOrScale failed.");
+ const WebPEncodingError error_code = pic.error_code;
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
+ error_code);
abort();
}
} else { // Other frames will be resized to the first frame's dimensions.
if (!WebPPictureRescale(&pic, *width, *height)) {
- fprintf(stderr, "WebPPictureRescale failed. Size: %d,%d\n", *width,
- *height);
+ const WebPEncodingError error_code = pic.error_code;
WebPAnimEncoderDelete(*enc);
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr,
+ "WebPPictureRescale failed. Size: %d,%d. Error code: %d\n",
+ *width, *height, error_code);
abort();
}
}
@@ -74,9 +82,8 @@
*height = pic.height;
*enc = WebPAnimEncoderNew(*width, *height, &anim_config);
if (*enc == nullptr) {
- fprintf(stderr, "WebPAnimEncoderNew failed.\n");
WebPPictureFree(&pic);
- abort();
+ return 0;
}
}
@@ -98,9 +105,11 @@
// Encode.
if (!WebPAnimEncoderAdd(*enc, &pic, timestamp_ms, &config)) {
- fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code);
+ const WebPEncodingError error_code = pic.error_code;
WebPAnimEncoderDelete(*enc);
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
abort();
}
@@ -147,14 +156,16 @@
// Assemble.
if (!WebPAnimEncoderAdd(enc, nullptr, timestamp_ms, nullptr)) {
- fprintf(stderr, "Last WebPAnimEncoderAdd failed.");
+ fprintf(stderr, "Last WebPAnimEncoderAdd failed: %s.\n",
+ WebPAnimEncoderGetError(enc));
WebPAnimEncoderDelete(enc);
abort();
}
WebPData webp_data;
WebPDataInit(&webp_data);
if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
- fprintf(stderr, "WebPAnimEncoderAssemble failed.");
+ fprintf(stderr, "WebPAnimEncoderAssemble failed: %s.\n",
+ WebPAnimEncoderGetError(enc));
WebPAnimEncoderDelete(enc);
WebPDataClear(&webp_data);
abort();
diff --git a/tests/fuzzer/enc_dec_fuzzer.cc b/tests/fuzzer/enc_dec_fuzzer.cc
index d4e59a8..187b516 100644
--- a/tests/fuzzer/enc_dec_fuzzer.cc
+++ b/tests/fuzzer/enc_dec_fuzzer.cc
@@ -18,8 +18,8 @@
#include <stdlib.h>
#include "./fuzz_utils.h"
-#include "webp/decode.h"
-#include "webp/encode.h"
+#include "src/webp/decode.h"
+#include "src/webp/encode.h"
namespace {
@@ -42,15 +42,20 @@
// Read the source picture.
if (!ExtractSourcePicture(&pic, data, size, &bit_pos)) {
- fprintf(stderr, "Can't read input image.\n");
+ const WebPEncodingError error_code = pic.error_code;
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
abort();
}
// Crop and scale.
if (!ExtractAndCropOrScale(&pic, data, size, &bit_pos)) {
- fprintf(stderr, "ExtractAndCropOrScale failed.");
+ const WebPEncodingError error_code = pic.error_code;
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
+ error_code);
abort();
}
@@ -83,9 +88,11 @@
pic.writer = WebPMemoryWrite;
pic.custom_ptr = &memory_writer;
if (!WebPEncode(&config, &pic)) {
- fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code);
+ const WebPEncodingError error_code = pic.error_code;
WebPMemoryWriterClear(&memory_writer);
WebPPictureFree(&pic);
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
abort();
}
diff --git a/tests/fuzzer/fuzz_utils.h b/tests/fuzzer/fuzz_utils.h
index 1d74611..713a5f4 100644
--- a/tests/fuzzer/fuzz_utils.h
+++ b/tests/fuzzer/fuzz_utils.h
@@ -23,8 +23,8 @@
#include "./img_alpha.h"
#include "./img_grid.h"
#include "./img_peak.h"
-#include "dsp/dsp.h"
-#include "webp/encode.h"
+#include "src/dsp/dsp.h"
+#include "src/webp/encode.h"
//------------------------------------------------------------------------------
// Arbitrary limits to prevent OOM, timeout, or slow execution.
diff --git a/tests/fuzzer/makefile.unix b/tests/fuzzer/makefile.unix
index e242563..4a9bff3 100644
--- a/tests/fuzzer/makefile.unix
+++ b/tests/fuzzer/makefile.unix
@@ -9,6 +9,7 @@
LDFLAGS = -fsanitize=fuzzer
LDLIBS = ../../src/mux/libwebpmux.a ../../src/demux/libwebpdemux.a
LDLIBS += ../../src/libwebp.a ../../imageio/libimageio_util.a
+LDLIBS += ../../sharpyuv/libsharpyuv.a
FUZZERS = advanced_api_fuzzer animation_api_fuzzer animencoder_fuzzer
FUZZERS += animdecoder_fuzzer mux_demux_api_fuzzer enc_dec_fuzzer
diff --git a/tests/fuzzer/mux_demux_api_fuzzer.c b/tests/fuzzer/mux_demux_api_fuzzer.c
index a8f81bf..4ed0142 100644
--- a/tests/fuzzer/mux_demux_api_fuzzer.c
+++ b/tests/fuzzer/mux_demux_api_fuzzer.c
@@ -15,8 +15,8 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
-#include "webp/demux.h"
-#include "webp/mux.h"
+#include "src/webp/demux.h"
+#include "src/webp/mux.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPData webp_data;
diff --git a/tests/fuzzer/simple_api_fuzzer.c b/tests/fuzzer/simple_api_fuzzer.c
index fbc9310..7d2b7f8 100644
--- a/tests/fuzzer/simple_api_fuzzer.c
+++ b/tests/fuzzer/simple_api_fuzzer.c
@@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "./fuzz_utils.h"
-#include "webp/decode.h"
+#include "src/webp/decode.h"
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
int w, h;
diff --git a/webp_js/README.md b/webp_js/README.md
new file mode 100644
index 0000000..824afa0
--- /dev/null
+++ b/webp_js/README.md
@@ -0,0 +1,81 @@
+# WebP JavaScript decoder
+
+```
+ __ __ ____ ____ ____ __ ____
+/ \\/ \ _ \ _ \ _ \ (__)/ __\
+\ / __/ _ \ __/ _) \_ \
+ \__\__/_____/____/_/ /____/____/
+```
+
+This file describes the compilation of libwebp into a JavaScript decoder using
+Emscripten and CMake.
+
+- install the Emscripten SDK following the procedure described at:
+ https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended
+ After installation, you should have some global variable positioned to the
+ location of the SDK. In particular, $EMSDK should point to the top-level
+ directory containing Emscripten tools.
+
+- configure the project 'WEBP_JS' with CMake using:
+
+ ```shell
+ cd webp_js && \
+ emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \
+ ../
+ ```
+
+- compile webp.js using 'emmake make'.
+
+- that's it! Upon completion, you should have the 'webp.js', 'webp.js.mem',
+ 'webp_wasm.js' and 'webp_wasm.wasm' files generated.
+
+The callable JavaScript function is WebPToSDL(), which decodes a raw WebP
+bitstream into a canvas. See webp_js/index.html for a simple usage sample (see
+below for instructions).
+
+## Demo HTML page
+
+The HTML page webp_js/index.html requires the built files 'webp.js' and
+'webp.js.mem' to be copied to webp_js/. An HTTP server to serve the WebP image
+example is also needed. With Python, just run:
+
+```shell
+cd webp_js && python3 -m http.server 8080
+```
+
+and then navigate to http://localhost:8080 in your favorite browser.
+
+## Web-Assembly (WASM) version:
+
+CMakeLists.txt is configured to build the WASM version when using the option
+WEBP_BUILD_WEBP_JS=ON. The compilation step will assemble the files
+'webp_wasm.js' and 'webp_wasm.wasm' that you then need to copy to the webp_js/
+directory.
+
+See webp_js/index_wasm.html for a simple demo page using the WASM version of the
+library.
+
+You will need a fairly recent version of Emscripten (at least 2.0.18,
+latest-upstream is recommended) and of your WASM-enabled browser to run this
+version.
+
+## Caveats
+
+- First decoding using the library is usually slower, due to just-in-time
+ compilation.
+
+- Some versions of llvm produce the following compile error when SSE2 is
+ enabled.
+
+ ```
+ "Unsupported: %516 = bitcast <8 x i16> %481 to i128
+ LLVM ERROR: BitCast Instruction not yet supported for integer types larger than 64 bits"
+ ```
+
+ The corresponding Emscripten bug is at:
+ https://github.com/kripken/emscripten/issues/3788
+
+ Therefore, SSE2 optimization is currently disabled in CMakeLists.txt.
+
+- If WEBP_ENABLE_SIMD is set to 1 the JavaScript version (webp.js) will be
+ disabled as wasm2js does not support SIMD.
diff --git a/webp_js/index.html b/webp_js/index.html
new file mode 100644
index 0000000..33cacb4
--- /dev/null
+++ b/webp_js/index.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <title>simple Javascript WebP decoding demo</title>
+ <script type="text/javascript">
+ var Module = {
+ noInitialRun : true
+ };
+ </script>
+ <script type="text/javascript" src="./webp.js"></script>
+ <script type="text/javascript">
+
+'use strict';
+
+// main wrapper for the function decoding a WebP into a canvas object
+var WebpToCanvas;
+
+function init() {
+ WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
+}
+window.onload = init;
+
+function decode(webp_data, canvas_id) {
+ // get the canvas to decode into
+ var canvas = document.getElementById(canvas_id);
+ if (canvas == null) return;
+ // clear previous picture (if any)
+ Module.canvas = canvas;
+ canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ // decode and measure timing
+ var start = new Date();
+ var ret = WebpToCanvas(webp_data, webp_data.length);
+ var end = new Date();
+ var speed_result = document.getElementById('timing');
+ // display timing result
+ if (speed_result != null) {
+ var decode_time = end - start;
+ speed_result.innerHTML = '<p>decoding time: ' + decode_time +' ms.</p>';
+ }
+}
+
+function loadfile(filename, canvas_id) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', filename);
+ xhr.responseType = 'arraybuffer';
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ var webp_data = new Uint8Array(xhr.response);
+ decode(webp_data, canvas_id);
+ }
+ };
+ xhr.send();
+}
+ </script>
+</head>
+
+<body>
+ <p>
+ <strong>WebP in JavaScript demo</strong> -
+ </p>
+ <p>
+ WebP decoder in JavaScript, using libwebp compiled with
+ <a href="https://github.com/kripken/emscripten/wiki">Emscripten</a>.
+ </p>
+ <p id="image_buttons">
+ <input type="button" value="test image!" name="./test_webp_js.webp"
+ onclick="loadfile(this.name, 'output_canvas')">
+ </p>
+ <p id="timing">Timing: N/A</p>
+ <canvas id="output_canvas">Your browser does not support canvas</canvas>
+
+</body>
+</html>
diff --git a/webp_js/index_wasm.html b/webp_js/index_wasm.html
new file mode 100644
index 0000000..5d7c17e
--- /dev/null
+++ b/webp_js/index_wasm.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <title>simple Javascript WebP decoding demo, using Web-Assembly (WASM)</title>
+ <script type="text/javascript">
+ var Module = {
+ noInitialRun : true
+ };
+ </script>
+ <script type="text/javascript">
+
+'use strict';
+
+// main wrapper for the function decoding a WebP into a canvas object
+var WebpToCanvas;
+
+function init() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'webp_wasm.wasm', true);
+ xhr.responseType = 'arraybuffer';
+ xhr.onload = function() {
+ Module.wasmBinary = xhr.response;
+ var script = document.createElement('script');
+ script.src = "webp_wasm.js";
+ document.body.appendChild(script);
+ };
+ xhr.send(null);
+}
+window.onload = init;
+
+function decode(webp_data, canvas_id) {
+ var result;
+ if (Module["asm"] != undefined) {
+ // wrapper for the function decoding a WebP into a canvas object
+ WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
+ // get the canvas to decode into
+ var canvas = document.getElementById(canvas_id);
+ if (canvas == null) return;
+ // clear previous picture (if any)
+ Module.canvas = canvas;
+ canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ // decode and measure timing
+ var start = new Date();
+ var ret = WebpToCanvas(webp_data, webp_data.length);
+ var end = new Date();
+ var decode_time = end - start;
+ result = 'decoding time: ' + decode_time +' ms.';
+ } else {
+ result = "WASM module not finished loading! Please retry";
+ }
+ // display timing result
+ var speed_result = document.getElementById('timing');
+ if (speed_result != null) {
+ speed_result.innerHTML = '<p>'+ result + '</p>';
+ }
+}
+
+function loadfile(filename, canvas_id) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', filename);
+ xhr.responseType = 'arraybuffer';
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ var webp_data = new Uint8Array(xhr.response);
+ decode(webp_data, canvas_id);
+ }
+ };
+ xhr.send();
+}
+ </script>
+</head>
+
+<body>
+ <p>
+ <strong>WebP demo using Web-Assembly</strong> -
+ </p>
+ <p>
+ WASM version of the WebP decoder, using libwebp compiled with
+ <a href="https://github.com/kripken/emscripten/wiki">Emscripten</a>.
+ </p>
+ <p id="image_buttons">
+ <input type="button" value="test image!"
+ onclick="loadfile('./test_webp_wasm.webp', 'output_canvas')">
+ </p>
+ <p id="timing">Timing: N/A</p>
+ <canvas id="output_canvas">Your browser does not support canvas</canvas>
+</body>
+</html>
diff --git a/webp_js/test_webp_js.webp b/webp_js/test_webp_js.webp
new file mode 100644
index 0000000..f798f55
--- /dev/null
+++ b/webp_js/test_webp_js.webp
Binary files differ
diff --git a/webp_js/test_webp_wasm.webp b/webp_js/test_webp_wasm.webp
new file mode 100644
index 0000000..f798f55
--- /dev/null
+++ b/webp_js/test_webp_wasm.webp
Binary files differ
diff --git a/xcframeworkbuild.sh b/xcframeworkbuild.sh
new file mode 100755
index 0000000..8d484c2
--- /dev/null
+++ b/xcframeworkbuild.sh
@@ -0,0 +1,255 @@
+#!/bin/bash
+#
+# This script generates 'WebP.xcframework', 'WebPDecoder.xcframework',
+# 'WebPDemux.xcframework' and 'WebPMux.xcframework'.
+# An iOS, Mac or Mac Catalyst app can decode WebP images by including
+# 'WebPDecoder.xcframework' and both encode and decode WebP images by including
+# 'WebP.xcframework'.
+#
+# Run ./xcframeworkbuild.sh to generate the frameworks under the current
+# directory (the previous build will be erased if it exists).
+#
+
+set -e
+
+# Set these variables based on the desired minimum deployment target.
+readonly IOS_MIN_VERSION=6.0
+readonly MACOSX_MIN_VERSION=10.15
+readonly MACOSX_CATALYST_MIN_VERSION=14.0
+
+# Extract Xcode version.
+readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
+if [[ -z "${XCODE}" ]] || [[ "${XCODE%%.*}" -lt 11 ]]; then
+ echo "Xcode 11.0 or higher is required!"
+ exit 1
+fi
+
+# Extract the latest SDK version from the final field of the form: iphoneosX.Y
+# / macosxX.Y
+readonly SDK=($(
+ xcodebuild -showsdks \
+ | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
+ xcodebuild -showsdks \
+ | grep macosx | sort | tail -n 1 | awk '{print substr($NF, 7)}'
+))
+readonly IOS=0
+readonly MACOS=1
+readonly IOS_SIMULATOR=2
+readonly MACOS_CATALYST=3
+readonly NUM_PLATFORMS=4
+
+readonly OLDPATH=${PATH}
+
+# Names should be of the form '<platform>-[<variant>-]<architecture>'.
+PLATFORMS[$IOS]="iPhoneOS-armv7 iPhoneOS-armv7s iPhoneOS-arm64"
+PLATFORMS[$IOS_SIMULATOR]="iPhoneSimulator-i386 iPhoneSimulator-x86_64"
+PLATFORMS[$MACOS]="MacOSX-x86_64"
+PLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64"
+if [[ "${XCODE%%.*}" -ge 12 ]]; then
+ PLATFORMS[$MACOS]+=" MacOSX-arm64"
+ PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64"
+ PLATFORMS[$IOS_SIMULATOR]+=" iPhoneSimulator-arm64"
+elif [[ "${XCODE%%.*}" -eq 11 ]]; then
+ cat << EOF
+WARNING: Xcode 12.0 or higher is required to build targets for
+WARNING: Apple Silicon (arm64). The XCFrameworks generated with Xcode 11 will
+WARNING: contain libraries for MacOS & Catalyst supporting x86_64 only.
+WARNING: The build will continue in 5 seconds...
+EOF
+ sleep 5
+else
+ echo "Xcode 11.0 or higher is required!"
+ exit 1
+fi
+readonly PLATFORMS
+readonly SRCDIR=$(dirname $0)
+readonly TOPDIR=$(pwd)
+readonly BUILDDIR="${TOPDIR}/xcframeworkbuild"
+readonly TARGETDIR="${TOPDIR}/WebP.xcframework"
+readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework"
+readonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework"
+readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework"
+readonly DEVELOPER=$(xcode-select --print-path)
+readonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
+readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
+readonly LIPO=$(xcrun -sdk iphoneos${SDK[$IOS]} -find lipo)
+
+if [[ -z "${SDK[$IOS]}" ]] || [[ ${SDK[$IOS]%%.*} -lt 8 ]]; then
+ echo "iOS SDK version 8.0 or higher is required!"
+ exit 1
+fi
+
+#######################################
+# Moves Headers/*.h to Headers/<framework>/
+#
+# Places framework headers in a subdirectory to avoid Xcode errors when using
+# multiple frameworks:
+# error: Multiple commands produce
+# '.../Build/Products/Debug-iphoneos/include/types.h'
+# Arguments:
+# $1 - path to framework
+#######################################
+update_headers_path() {
+ local framework_name="$(basename ${1%.xcframework})"
+ local subdir
+ for d in $(find "$1" -path "*/Headers"); do
+ subdir="$d/$framework_name"
+ mkdir "$subdir"
+ mv "$d/"*.h "$subdir"
+ done
+}
+
+echo "Xcode Version: ${XCODE}"
+echo "iOS SDK Version: ${SDK[$IOS]}"
+echo "MacOS SDK Version: ${SDK[$MACOS]}"
+
+if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
+ || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then
+ cat << EOF
+WARNING: The following directories will be deleted:
+WARNING: ${BUILDDIR}
+WARNING: ${TARGETDIR}
+WARNING: ${DECTARGETDIR}
+WARNING: ${MUXTARGETDIR}
+WARNING: ${DEMUXTARGETDIR}
+WARNING: The build will continue in 5 seconds...
+EOF
+ sleep 5
+fi
+rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
+ ${MUXTARGETDIR} ${DEMUXTARGETDIR}
+
+if [[ ! -e ${SRCDIR}/configure ]]; then
+ if ! (cd ${SRCDIR} && sh autogen.sh); then
+ cat << EOF
+Error creating configure script!
+This script requires the autoconf/automake and libtool to build. MacPorts or
+Homebrew can be used to obtain these:
+https://www.macports.org/install.php
+https://brew.sh/
+EOF
+ exit 1
+ fi
+fi
+
+for (( i = 0; i < $NUM_PLATFORMS; ++i )); do
+ LIBLIST=()
+ DECLIBLIST=()
+ MUXLIBLIST=()
+ DEMUXLIBLIST=()
+
+ for PLATFORM in ${PLATFORMS[$i]}; do
+ ROOTDIR="${BUILDDIR}/${PLATFORM}"
+ mkdir -p "${ROOTDIR}"
+
+ ARCH="${PLATFORM##*-}"
+ case "${PLATFORM}" in
+ iPhone*)
+ sdk="${SDK[$IOS]}"
+ ;;
+ MacOS*)
+ sdk="${SDK[$MACOS]}"
+ ;;
+ *)
+ echo "Unrecognized platform: ${PLATFORM}!"
+ exit 1
+ ;;
+ esac
+
+ SDKROOT="${PLATFORMSROOT}/${PLATFORM%%-*}.platform/"
+ SDKROOT+="Developer/SDKs/${PLATFORM%%-*}${sdk}.sdk/"
+ CFLAGS="-pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
+ case "${PLATFORM}" in
+ iPhone*)
+ CFLAGS+=" -fembed-bitcode"
+ CFLAGS+=" -target ${ARCH}-apple-ios${IOS_MIN_VERSION}"
+ [[ "${PLATFORM}" == *Simulator* ]] && CFLAGS+="-simulator"
+ ;;
+ MacOSX-Catalyst*)
+ CFLAGS+=" -target"
+ CFLAGS+=" ${ARCH}-apple-ios${MACOSX_CATALYST_MIN_VERSION}-macabi"
+ ;;
+ MacOSX*)
+ CFLAGS+=" -mmacosx-version-min=${MACOSX_MIN_VERSION}"
+ ;;
+ esac
+
+ set -x
+ export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
+ ${SRCDIR}/configure --host=${ARCH/arm64/aarch64}-apple-darwin \
+ --build=$(${SRCDIR}/config.guess) \
+ --prefix=${ROOTDIR} \
+ --disable-shared --enable-static \
+ --enable-libwebpdecoder --enable-swap-16bit-csp \
+ --enable-libwebpmux \
+ CC="clang -arch ${ARCH}" \
+ CFLAGS="${CFLAGS}"
+ set +x
+
+ # Build only the libraries, skip the examples.
+ make V=0 -C sharpyuv
+ make V=0 -C src install
+
+ LIBLIST+=("${ROOTDIR}/lib/libwebp.a")
+ DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a")
+ MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a")
+ DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a")
+ # xcodebuild requires a directory for the -headers option, these will match
+ # for all builds.
+ make -C src install-data DESTDIR="${ROOTDIR}/lib-headers"
+ make -C src install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers"
+ make -C src/demux install-data DESTDIR="${ROOTDIR}/demux-headers"
+ make -C src/mux install-data DESTDIR="${ROOTDIR}/mux-headers"
+ LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp"
+ DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp"
+ DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp"
+ MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp"
+
+ make distclean
+
+ export PATH=${OLDPATH}
+ done
+
+ [[ -z "${LIBLIST[@]}" ]] && continue
+
+ # Create a temporary target directory for each <platform>[-<variant>].
+ target_dir="${BUILDDIR}/${PLATFORMS[$i]}"
+ target_dir="${target_dir%% *}"
+ target_dir="${target_dir%-*}"
+ target_lib="${target_dir}/$(basename ${LIBLIST[0]})"
+ target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})"
+ target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})"
+ target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})"
+
+ mkdir -p "${target_dir}"
+ ${LIPO} -create ${LIBLIST[@]} -output "${target_lib}"
+ ${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}"
+ ${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}"
+ ${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}"
+ FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}")
+ FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}")
+ FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}")
+ FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}")
+done
+
+# lipo will not put archives with the same architecture (e.g., x86_64
+# iPhoneSimulator & MacOS) in the same fat output file. xcodebuild
+# -create-xcframework requires universal archives to avoid e.g.:
+# Both ios-x86_64-maccatalyst and ios-arm64-maccatalyst represent two
+# equivalent library definitions
+set -x
+xcodebuild -create-xcframework "${FAT_LIBLIST[@]}" \
+ -output ${TARGETDIR}
+xcodebuild -create-xcframework "${FAT_DECLIBLIST[@]}" \
+ -output ${DECTARGETDIR}
+xcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \
+ -output ${DEMUXTARGETDIR}
+xcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \
+ -output ${MUXTARGETDIR}
+update_headers_path "${TARGETDIR}"
+update_headers_path "${DECTARGETDIR}"
+update_headers_path "${DEMUXTARGETDIR}"
+update_headers_path "${MUXTARGETDIR}"
+set +x
+
+echo "SUCCESS"