mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-16 05:49:51 +02:00
Compare commits
273 Commits
v1.2.0-rc3
...
chrome-m10
Author | SHA1 | Date | |
---|---|---|---|
a36ce6e442 | |||
7366f7f394 | |||
84163d9d02 | |||
d01c1eb309 | |||
8813ca8e69 | |||
3c4a0fbfbc | |||
56a480e80c | |||
62b45bddcd | |||
8764ec7a07 | |||
bcb872c31f | |||
67c44ac5db | |||
8278825aac | |||
14a49e018d | |||
34b1dc336d | |||
0b397fda9d | |||
c16488ac4a | |||
5a2d929cd8 | |||
169f867f3c | |||
a94b855c54 | |||
f83bdb5251 | |||
bef0d79764 | |||
404c1622f8 | |||
8895f8a345 | |||
92a673d258 | |||
67c1d72239 | |||
1124ff662d | |||
e15b356014 | |||
ec9e782a35 | |||
7bd07f3b5d | |||
5ecee06f7a | |||
f81dd7d63e | |||
2d607ee646 | |||
266cbbc511 | |||
9fc12274ce | |||
7d18f40ac1 | |||
11309aa54c | |||
4bc762f729 | |||
0d1b9bc433 | |||
20ef48f05a | |||
93c5437115 | |||
53cf2b4997 | |||
d3006f4b96 | |||
ea967098a4 | |||
11bc8410bd | |||
30453ea4e6 | |||
6c43219a5f | |||
4f59fa7390 | |||
e74f8a62b2 | |||
5a709ec0d7 | |||
a2093acc4b | |||
86c669303a | |||
232f22da5a | |||
44dd765def | |||
7a7e33e977 | |||
86f94ee010 | |||
a3927cc800 | |||
6c45cef7ff | |||
0c8b0e67a4 | |||
dc3841e077 | |||
a19a25bb03 | |||
42888f6c7c | |||
7efcf3cc26 | |||
8f4b5c62b7 | |||
90084d84f9 | |||
ed643f619d | |||
8fa053d134 | |||
99a8756201 | |||
deb426becc | |||
779597d443 | |||
40e8aa57f8 | |||
01a05de1a7 | |||
2de4b05a56 | |||
b8bca81fb6 | |||
e8e77b9c47 | |||
7e7d5d503a | |||
10c5084842 | |||
89f774e61d | |||
2d3293ad76 | |||
ec34fd7023 | |||
e471728754 | |||
e3cfafaf71 | |||
a828a59b49 | |||
fe153fae98 | |||
919acc0ef5 | |||
efa0731b9d | |||
0957fd69ee | |||
e685feef0c | |||
841960b670 | |||
617cf03656 | |||
7a68afaac5 | |||
34bb332ca1 | |||
f0e9351cce | |||
5ccbd6ed8c | |||
c3d0c2d7d8 | |||
d0d2292e1a | |||
03d1219055 | |||
d55d447c9a | |||
e4cbcdd2b5 | |||
924e7ca654 | |||
0fa0ea5488 | |||
29cc95ce4c | |||
a30f219016 | |||
66b3ce239e | |||
54e61a3864 | |||
b4533debd9 | |||
b9d2f9cd3b | |||
ec178f2c7f | |||
26139c7398 | |||
13b8281609 | |||
88b6a396f1 | |||
6f49654024 | |||
4074acf873 | |||
b0a860891d | |||
6db8248c01 | |||
827a307fec | |||
db25f1b4ed | |||
286e7fceaa | |||
6e8a4126f2 | |||
faf219684c | |||
480cd51de6 | |||
9195ea0538 | |||
4acae017bd | |||
883f063397 | |||
567e1f442b | |||
1b0c15db02 | |||
17bade381a | |||
a80954a1d9 | |||
f084244d9f | |||
b217b4fff7 | |||
ec497b7532 | |||
e4886716d3 | |||
e3cb052ca5 | |||
a510fedb9a | |||
f035d2e40d | |||
7031946ad8 | |||
973390b618 | |||
abd6664fee | |||
5b7e79303a | |||
02ca04c348 | |||
e94716e27c | |||
c846efd888 | |||
b6f756e82b | |||
8f5cb4c18e | |||
8ea81561d2 | |||
6b1d18c362 | |||
3368d8768a | |||
f213abf620 | |||
50c97c301d | |||
2c206aaf96 | |||
96e3dfef26 | |||
0e0f74b7e3 | |||
35b7436a21 | |||
21d24b4c08 | |||
cdcf89020e | |||
dc683cdef5 | |||
0858494e96 | |||
c2cf6a93b0 | |||
df0e808fed | |||
676c57dba4 | |||
7bb7f7474e | |||
abcd1797a1 | |||
edaf08952d | |||
b96220636b | |||
e23cd5481c | |||
3875c7de07 | |||
1a8f0d45d3 | |||
934801604e | |||
45eaacc939 | |||
42592af875 | |||
e298e05f66 | |||
29148919e0 | |||
9ce5843dba | |||
d9191588ab | |||
c5bc36243a | |||
53b6f76209 | |||
d2caaba435 | |||
731246ba3b | |||
d250f01d95 | |||
1fe3162541 | |||
3a4d3ecd40 | |||
b2bc809346 | |||
e542fc7a8a | |||
e024115490 | |||
edea64442c | |||
ece18e5520 | |||
a89a3230c9 | |||
26f4aa0115 | |||
8f5946634e | |||
46d844e6cf | |||
298d26eac2 | |||
a1e5dae0f0 | |||
327ef24fbd | |||
f70819de51 | |||
dc7e2b42e7 | |||
9df23dddc2 | |||
a2e18f10eb | |||
e1a8d4f3fe | |||
4de35f4383 | |||
0f13eec7bf | |||
277d30749f | |||
97adbba513 | |||
b60d460318 | |||
72fe52f623 | |||
116d235c30 | |||
6f445b3e3d | |||
b1cf887f86 | |||
3e26513656 | |||
f6d2924757 | |||
de3b4ba813 | |||
7f09d3d132 | |||
4edea4a695 | |||
c9e26bdb35 | |||
28d488e6f1 | |||
695bdaa2f6 | |||
685d073ee1 | |||
d38bd0dda0 | |||
109ff0f100 | |||
a2fce86744 | |||
776983d427 | |||
315abbd60b | |||
eae815d0d1 | |||
afbca5a152 | |||
3320416b2e | |||
29145ed692 | |||
1f5791398c | |||
29b6129c78 | |||
b60869a18e | |||
6fb4cddc93 | |||
05b72d4205 | |||
b6513fbaa8 | |||
98bbe35b51 | |||
b1674240f9 | |||
88c90c4528 | |||
6a9916d734 | |||
b6cf52d5b8 | |||
3b12b7f4b4 | |||
595fa13f83 | |||
8fdaecb09d | |||
8933bac212 | |||
7d416ff085 | |||
ec6cfeb51e | |||
7e58a1a260 | |||
5651a6b2ed | |||
25ae67b3de | |||
5d4ee4c3c0 | |||
01b38ee19a | |||
652aa34424 | |||
0320e1e36f | |||
8886f620c0 | |||
fae416179e | |||
5bd2704e30 | |||
fee642870e | |||
33ddb894b1 | |||
b27ea8525a | |||
b78494a933 | |||
e79974cd6a | |||
a885339448 | |||
a09a647241 | |||
401da22bd6 | |||
2690782292 | |||
06c1e72e71 | |||
8f0d41aac0 | |||
373eb170f1 | |||
759b9d5a06 | |||
926ce921f3 | |||
9c367bc602 | |||
47f64f6edd | |||
cc3577e9b9 | |||
004d77ffab | |||
ceddb5fc8d | |||
289757fe1e | |||
8696147da4 | |||
8df77fb1b1 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,7 +3,9 @@
|
|||||||
*.pc
|
*.pc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.deps
|
.deps
|
||||||
|
.idea
|
||||||
.libs
|
.libs
|
||||||
|
.vscode
|
||||||
/aclocal.m4
|
/aclocal.m4
|
||||||
/ar-lib
|
/ar-lib
|
||||||
/autom4te.cache
|
/autom4te.cache
|
||||||
|
5
.mailmap
5
.mailmap
@ -8,6 +8,11 @@ Vikas Arora <vikasa@google.com>
|
|||||||
<vikasa@google.com> <vikaas.arora@gmail.com>
|
<vikasa@google.com> <vikaas.arora@gmail.com>
|
||||||
<slobodan.prijic@imgtec.com> <Slobodan.Prijic@imgtec.com>
|
<slobodan.prijic@imgtec.com> <Slobodan.Prijic@imgtec.com>
|
||||||
<vrabaud@google.com> <vincent.rabaud@gmail.com>
|
<vrabaud@google.com> <vincent.rabaud@gmail.com>
|
||||||
|
Vincent Rabaud <vrabaud@google.com>
|
||||||
Tamar Levy <tamar.levy@intel.com>
|
Tamar Levy <tamar.levy@intel.com>
|
||||||
<qrczak@google.com> <qrczak>
|
<qrczak@google.com> <qrczak>
|
||||||
Hui Su <huisu@google.com>
|
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>
|
||||||
|
441
.pylintrc
Normal file
441
.pylintrc
Normal file
@ -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
|
2
.style.yapf
Normal file
2
.style.yapf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[style]
|
||||||
|
based_on_style = chromium
|
9
AUTHORS
9
AUTHORS
@ -1,11 +1,17 @@
|
|||||||
Contributors:
|
Contributors:
|
||||||
- Aidan O'Loan (aidanol at gmail dot com)
|
- Aidan O'Loan (aidanol at gmail dot com)
|
||||||
- Alan Browning (browning at google 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)
|
- Charles Munger (clm at google dot com)
|
||||||
- Cheng Yi (cyi at google dot com)
|
- Cheng Yi (cyi at google dot com)
|
||||||
- Christian Duvivier (cduvivier 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)
|
- Djordje Pesut (djordje dot pesut at imgtec dot com)
|
||||||
|
- Frank Barchard (fbarchard at google dot com)
|
||||||
- Hui Su (huisu at google dot com)
|
- Hui Su (huisu at google dot com)
|
||||||
|
- Ilya Kurdyukov (jpegqs at gmail dot com)
|
||||||
- Ingvar Stepanyan (rreverser at google dot com)
|
- Ingvar Stepanyan (rreverser at google dot com)
|
||||||
- James Zern (jzern at google dot com)
|
- James Zern (jzern at google dot com)
|
||||||
- Jan Engelhardt (jengelh at medozas dot de)
|
- Jan Engelhardt (jengelh at medozas dot de)
|
||||||
@ -19,6 +25,7 @@ Contributors:
|
|||||||
- Mans Rullgard (mans at mansr dot com)
|
- Mans Rullgard (mans at mansr dot com)
|
||||||
- Marcin Kowalczyk (qrczak at google dot com)
|
- Marcin Kowalczyk (qrczak at google dot com)
|
||||||
- Martin Olsson (mnemo at minimum dot se)
|
- Martin Olsson (mnemo at minimum dot se)
|
||||||
|
- Maryla Ustarroz-Calonge (maryla at google dot com)
|
||||||
- Mikołaj Zalewski (mikolajz at google dot com)
|
- Mikołaj Zalewski (mikolajz at google dot com)
|
||||||
- Mislav Bradac (mislavm at google dot com)
|
- Mislav Bradac (mislavm at google dot com)
|
||||||
- Nico Weber (thakis at chromium dot org)
|
- Nico Weber (thakis at chromium dot org)
|
||||||
@ -29,6 +36,7 @@ Contributors:
|
|||||||
- Pascal Massimino (pascal dot massimino at gmail dot com)
|
- Pascal Massimino (pascal dot massimino at gmail dot com)
|
||||||
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
|
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
|
||||||
- Pierre Joye (pierre dot php at gmail dot com)
|
- Pierre Joye (pierre dot php at gmail dot com)
|
||||||
|
- Roberto Alanis (alanisbaez at google dot com)
|
||||||
- Sam Clegg (sbc at chromium dot org)
|
- Sam Clegg (sbc at chromium dot org)
|
||||||
- Scott Hancher (seh at google dot com)
|
- Scott Hancher (seh at google dot com)
|
||||||
- Scott LaVarnway (slavarnway at google dot com)
|
- Scott LaVarnway (slavarnway at google dot com)
|
||||||
@ -45,3 +53,4 @@ Contributors:
|
|||||||
- Wan-Teh Chang (wtc at google dot com)
|
- Wan-Teh Chang (wtc at google dot com)
|
||||||
- Yang Zhang (yang dot zhang at arm dot com)
|
- Yang Zhang (yang dot zhang at arm dot com)
|
||||||
- Yannis Guyon (yguyon at google dot com)
|
- Yannis Guyon (yguyon at google dot com)
|
||||||
|
- Zhi An Ng (zhin at chromium dot org)
|
||||||
|
10
Android.mk
10
Android.mk
@ -33,6 +33,14 @@ else
|
|||||||
NEON := c
|
NEON := c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
sharpyuv_srcs := \
|
||||||
|
sharpyuv/sharpyuv.c \
|
||||||
|
sharpyuv/sharpyuv_csp.c \
|
||||||
|
sharpyuv/sharpyuv_dsp.c \
|
||||||
|
sharpyuv/sharpyuv_gamma.c \
|
||||||
|
sharpyuv/sharpyuv_neon.$(NEON) \
|
||||||
|
sharpyuv/sharpyuv_sse2.c \
|
||||||
|
|
||||||
dec_srcs := \
|
dec_srcs := \
|
||||||
src/dec/alpha_dec.c \
|
src/dec/alpha_dec.c \
|
||||||
src/dec/buffer_dec.c \
|
src/dec/buffer_dec.c \
|
||||||
@ -74,6 +82,7 @@ dsp_dec_srcs := \
|
|||||||
src/dsp/lossless_msa.c \
|
src/dsp/lossless_msa.c \
|
||||||
src/dsp/lossless_neon.$(NEON) \
|
src/dsp/lossless_neon.$(NEON) \
|
||||||
src/dsp/lossless_sse2.c \
|
src/dsp/lossless_sse2.c \
|
||||||
|
src/dsp/lossless_sse41.c \
|
||||||
src/dsp/rescaler.c \
|
src/dsp/rescaler.c \
|
||||||
src/dsp/rescaler_mips32.c \
|
src/dsp/rescaler_mips32.c \
|
||||||
src/dsp/rescaler_mips_dsp_r2.c \
|
src/dsp/rescaler_mips_dsp_r2.c \
|
||||||
@ -203,6 +212,7 @@ endif # ENABLE_SHARED=1
|
|||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
$(sharpyuv_srcs) \
|
||||||
$(dsp_enc_srcs) \
|
$(dsp_enc_srcs) \
|
||||||
$(enc_srcs) \
|
$(enc_srcs) \
|
||||||
$(utils_enc_srcs) \
|
$(utils_enc_srcs) \
|
||||||
|
200
CMakeLists.txt
200
CMakeLists.txt
@ -1,17 +1,28 @@
|
|||||||
##
|
# Copyright (c) 2020 Google LLC.
|
||||||
## Copyright (c) 2020 Google LLC.
|
#
|
||||||
##
|
# Use of this source code is governed by a BSD-style license
|
||||||
## 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
|
||||||
## that can be found in the LICENSE file in the root of the source
|
# tree. An additional intellectual property rights grant can be found
|
||||||
## tree. An additional intellectual property rights grant can be found
|
# in the file PATENTS. All contributing project authors may
|
||||||
## in the file PATENTS. All contributing project authors may
|
# be found in the AUTHORS file in the root of the source tree.
|
||||||
## be found in the AUTHORS file in the root of the source tree.
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
|
||||||
|
if(POLICY CMP0072)
|
||||||
|
cmake_policy(SET CMP0072 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(WebP C)
|
project(WebP C)
|
||||||
|
|
||||||
# Options for coder / decoder executables.
|
# 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)
|
if(NOT EMSCRIPTEN)
|
||||||
# Disable SIMD on Emscripten by default, as it's a new unstable Wasm feature.
|
# 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.
|
# Users can still explicitly opt-in to make a SIMD-enabled build.
|
||||||
@ -26,15 +37,29 @@ option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
|
|||||||
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation 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_VWEBP "Build the vwebp viewer tool." ON)
|
||||||
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line 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_WEBPMUX "Build the webpmux command line tool." ON)
|
||||||
option(WEBP_BUILD_EXTRAS "Build extras." ON)
|
option(WEBP_BUILD_EXTRAS "Build extras." ON)
|
||||||
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
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_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
||||||
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
||||||
OFF)
|
OFF)
|
||||||
set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
|
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)
|
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.
|
# Option needed for handling Unicode file names on Windows.
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
option(WEBP_UNICODE "Build Unicode executables." ON)
|
option(WEBP_UNICODE "Build Unicode executables." ON)
|
||||||
@ -50,6 +75,7 @@ if(WEBP_BUILD_WEBP_JS)
|
|||||||
set(WEBP_BUILD_WEBPINFO OFF)
|
set(WEBP_BUILD_WEBPINFO OFF)
|
||||||
set(WEBP_BUILD_WEBPMUX OFF)
|
set(WEBP_BUILD_WEBPMUX OFF)
|
||||||
set(WEBP_BUILD_EXTRAS OFF)
|
set(WEBP_BUILD_EXTRAS OFF)
|
||||||
|
set(WEBP_USE_THREAD OFF)
|
||||||
|
|
||||||
if(WEBP_ENABLE_SIMD)
|
if(WEBP_ENABLE_SIMD)
|
||||||
message("wasm2js does not support SIMD, disabling webp.js generation.")
|
message("wasm2js does not support SIMD, disabling webp.js generation.")
|
||||||
@ -91,6 +117,8 @@ set(includedir "\$\{prefix\}/include")
|
|||||||
set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
||||||
set(INSTALLED_LIBRARIES)
|
set(INSTALLED_LIBRARIES)
|
||||||
|
|
||||||
|
set(CMAKE_C_VISIBILITY_PRESET hidden)
|
||||||
|
|
||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
# Android only.
|
# Android only.
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
@ -205,6 +233,18 @@ function(libwebp_add_stub_file TARGET)
|
|||||||
target_sources(${TARGET} PRIVATE ${stub_source_file})
|
target_sources(${TARGET} PRIVATE ${stub_source_file})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS"
|
||||||
|
"")
|
||||||
|
add_library(sharpyuv OBJECT ${WEBP_SHARPYUV_SRCS})
|
||||||
|
target_include_directories(sharpyuv
|
||||||
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set_target_properties(
|
||||||
|
sharpyuv
|
||||||
|
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h;\
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# avoid security warnings for e.g., fopen() used in the examples.
|
# avoid security warnings for e.g., fopen() used in the examples.
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
@ -269,6 +309,7 @@ target_include_directories(webputils
|
|||||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR})
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
add_library(webp
|
add_library(webp
|
||||||
|
$<TARGET_OBJECTS:sharpyuv>
|
||||||
$<TARGET_OBJECTS:webpdecode>
|
$<TARGET_OBJECTS:webpdecode>
|
||||||
$<TARGET_OBJECTS:webpdsp>
|
$<TARGET_OBJECTS:webpdsp>
|
||||||
$<TARGET_OBJECTS:webpencode>
|
$<TARGET_OBJECTS:webpencode>
|
||||||
@ -277,10 +318,12 @@ if(XCODE)
|
|||||||
libwebp_add_stub_file(webp)
|
libwebp_add_stub_file(webp)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
|
target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
|
||||||
target_include_directories(webp
|
target_include_directories(
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
webp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
PUBLIC $<INSTALL_INTERFACE:include>)
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||||
|
$<INSTALL_INTERFACE:include>)
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
webp
|
webp
|
||||||
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
|
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
|
||||||
@ -289,7 +332,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
|
|||||||
|
|
||||||
# Make sure the OBJECT libraries are built with position independent code (it is
|
# Make sure the OBJECT libraries are built with position independent code (it is
|
||||||
# not ON by default).
|
# not ON by default).
|
||||||
set_target_properties(webpdecode
|
set_target_properties(sharpyuv
|
||||||
|
webpdecode
|
||||||
webpdspdecode
|
webpdspdecode
|
||||||
webputilsdecode
|
webputilsdecode
|
||||||
webpencode
|
webpencode
|
||||||
@ -315,10 +359,10 @@ ${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
|
|||||||
configure_pkg_config("src/demux/libwebpdemux.pc")
|
configure_pkg_config("src/demux/libwebpdemux.pc")
|
||||||
|
|
||||||
# Set the version numbers.
|
# Set the version numbers.
|
||||||
function(parse_version FILE NAME VAR)
|
macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
|
||||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
|
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
|
||||||
string(REGEX MATCH
|
string(REGEX MATCH
|
||||||
"${NAME}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
|
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+"
|
||||||
TMP
|
TMP
|
||||||
${SOURCE_FILE})
|
${SOURCE_FILE})
|
||||||
string(REGEX MATCH
|
string(REGEX MATCH
|
||||||
@ -327,29 +371,35 @@ function(parse_version FILE NAME VAR)
|
|||||||
${TMP})
|
${TMP})
|
||||||
string(REGEX
|
string(REGEX
|
||||||
REPLACE ":"
|
REPLACE ":"
|
||||||
"."
|
" "
|
||||||
VERSION
|
LT_VERSION
|
||||||
${TMP})
|
${TMP})
|
||||||
set(${VAR} "${VERSION}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
# See the libtool docs for more information:
|
||||||
parse_version(Makefile.am webp WEBP_WEBP_SOVERSION)
|
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
|
||||||
set_target_properties(webp
|
#
|
||||||
PROPERTIES VERSION
|
# c=<current>, a=<age>, r=<revision>
|
||||||
${PACKAGE_VERSION}
|
#
|
||||||
SOVERSION
|
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
|
||||||
${WEBP_WEBP_SOVERSION})
|
# passed to libtool.
|
||||||
parse_version(Makefile.am webpdecoder WEBP_DECODER_SOVERSION)
|
#
|
||||||
set_target_properties(webpdecoder
|
# We set FULL = [c-a].a.r and MAJOR = [c-a].
|
||||||
PROPERTIES VERSION
|
separate_arguments(LT_VERSION)
|
||||||
${PACKAGE_VERSION}
|
list(GET LT_VERSION 0 LT_CURRENT)
|
||||||
SOVERSION
|
list(GET LT_VERSION 1 LT_REVISION)
|
||||||
${WEBP_DECODER_SOVERSION})
|
list(GET LT_VERSION 2 LT_AGE)
|
||||||
parse_version(demux/Makefile.am webpdemux WEBP_DEMUX_SOVERSION)
|
math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}")
|
||||||
set_target_properties(webpdemux
|
|
||||||
PROPERTIES VERSION
|
set_target_properties(
|
||||||
${PACKAGE_VERSION}
|
${TARGET_NAME}
|
||||||
SOVERSION
|
PROPERTIES VERSION
|
||||||
${WEBP_DEMUX_SOVERSION})
|
${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
|
||||||
|
SOVERSION
|
||||||
|
${LT_CURRENT_MINUS_AGE})
|
||||||
|
endmacro()
|
||||||
|
set_version(Makefile.am webp webp)
|
||||||
|
set_version(Makefile.am webpdecoder webpdecoder)
|
||||||
|
set_version(demux/Makefile.am webpdemux webpdemux)
|
||||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
|
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
|
||||||
string(REGEX MATCH
|
string(REGEX MATCH
|
||||||
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
|
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
|
||||||
@ -377,6 +427,12 @@ foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
|
|||||||
${SIMD_COMPILE_FLAG})
|
${SIMD_COMPILE_FLAG})
|
||||||
endforeach()
|
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)
|
if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
|
||||||
set(WEBP_BUILD_GIF2WEBP OFF)
|
set(WEBP_BUILD_GIF2WEBP OFF)
|
||||||
endif()
|
endif()
|
||||||
@ -391,13 +447,14 @@ if(WEBP_BUILD_ANIM_UTILS
|
|||||||
OR WEBP_BUILD_DWEBP
|
OR WEBP_BUILD_DWEBP
|
||||||
OR WEBP_BUILD_GIF2WEBP
|
OR WEBP_BUILD_GIF2WEBP
|
||||||
OR WEBP_BUILD_IMG2WEBP
|
OR WEBP_BUILD_IMG2WEBP
|
||||||
OR WEBP_BUILD_VWEBP)
|
OR WEBP_BUILD_VWEBP
|
||||||
|
OR WEBP_BUILD_WEBPMUX
|
||||||
|
OR WEBP_BUILD_WEBPINFO)
|
||||||
# Example utility library.
|
# Example utility library.
|
||||||
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS"
|
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS"
|
||||||
"example_util_[^ ]*")
|
"example_util_[^ ]*")
|
||||||
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
|
||||||
add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS})
|
add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS})
|
||||||
target_link_libraries(exampleutil imageioutil)
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
exampleutil
|
exampleutil
|
||||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
|
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
|
||||||
@ -406,6 +463,7 @@ if(WEBP_BUILD_ANIM_UTILS
|
|||||||
"imageio_util_[^ ]*")
|
"imageio_util_[^ ]*")
|
||||||
add_library(imageioutil STATIC ${IMAGEIOUTILS_SRCS})
|
add_library(imageioutil STATIC ${IMAGEIOUTILS_SRCS})
|
||||||
target_link_libraries(imageioutil webp)
|
target_link_libraries(imageioutil webp)
|
||||||
|
target_link_libraries(exampleutil imageioutil)
|
||||||
|
|
||||||
# Image-decoding utility library.
|
# Image-decoding utility library.
|
||||||
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS"
|
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS"
|
||||||
@ -449,26 +507,20 @@ if(WEBP_BUILD_CWEBP)
|
|||||||
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
|
if(WEBP_BUILD_LIBWEBPMUX)
|
||||||
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
|
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
|
||||||
add_library(libwebpmux ${WEBP_MUX_SRCS})
|
add_library(webpmux ${WEBP_MUX_SRCS})
|
||||||
target_link_libraries(libwebpmux webp)
|
target_link_libraries(webpmux webp)
|
||||||
target_include_directories(libwebpmux
|
target_include_directories(webpmux
|
||||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR})
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
parse_version(mux/Makefile.am webpmux WEBP_MUX_SOVERSION)
|
set_version(mux/Makefile.am webpmux webpmux)
|
||||||
set_target_properties(libwebpmux
|
set_target_properties(webpmux
|
||||||
PROPERTIES VERSION
|
|
||||||
${PACKAGE_VERSION}
|
|
||||||
SOVERSION
|
|
||||||
${WEBP_MUX_SOVERSION})
|
|
||||||
set_target_properties(libwebpmux
|
|
||||||
PROPERTIES PUBLIC_HEADER
|
PROPERTIES PUBLIC_HEADER
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
|
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
|
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
|
||||||
set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux)
|
list(APPEND INSTALLED_LIBRARIES webpmux)
|
||||||
list(APPEND INSTALLED_LIBRARIES libwebpmux)
|
|
||||||
configure_pkg_config("src/mux/libwebpmux.pc")
|
configure_pkg_config("src/mux/libwebpmux.pc")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -482,7 +534,7 @@ if(WEBP_BUILD_GIF2WEBP)
|
|||||||
exampleutil
|
exampleutil
|
||||||
imageioutil
|
imageioutil
|
||||||
webp
|
webp
|
||||||
libwebpmux
|
webpmux
|
||||||
${WEBP_DEP_GIF_LIBRARIES})
|
${WEBP_DEP_GIF_LIBRARIES})
|
||||||
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
@ -499,7 +551,7 @@ if(WEBP_BUILD_IMG2WEBP)
|
|||||||
imagedec
|
imagedec
|
||||||
imageioutil
|
imageioutil
|
||||||
webp
|
webp
|
||||||
libwebpmux)
|
webpmux)
|
||||||
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
@ -539,7 +591,9 @@ if(WEBP_BUILD_WEBPINFO)
|
|||||||
"webpinfo")
|
"webpinfo")
|
||||||
add_executable(webpinfo ${WEBPINFO_SRCS})
|
add_executable(webpinfo ${WEBPINFO_SRCS})
|
||||||
target_link_libraries(webpinfo exampleutil imageioutil)
|
target_link_libraries(webpinfo exampleutil imageioutil)
|
||||||
target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(webpinfo
|
||||||
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -547,10 +601,12 @@ if(WEBP_BUILD_WEBPMUX)
|
|||||||
# webpmux
|
# webpmux
|
||||||
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS"
|
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS"
|
||||||
"webpmux")
|
"webpmux")
|
||||||
add_executable(webpmux ${WEBPMUX_SRCS})
|
add_executable(webpmux_app ${WEBPMUX_SRCS})
|
||||||
target_link_libraries(webpmux exampleutil imageioutil libwebpmux webp)
|
set_target_properties(webpmux_app PROPERTIES OUTPUT_NAME webpmux)
|
||||||
target_include_directories(webpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_link_libraries(webpmux_app exampleutil imageioutil webpmux webp)
|
||||||
install(TARGETS webpmux RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
target_include_directories(webpmux_app
|
||||||
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
|
install(TARGETS webpmux_app RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WEBP_BUILD_EXTRAS)
|
if(WEBP_BUILD_EXTRAS)
|
||||||
@ -560,37 +616,39 @@ if(WEBP_BUILD_EXTRAS)
|
|||||||
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality")
|
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality")
|
||||||
parse_makefile_am(${EXTRAS_MAKEFILE} "VWEBP_SDL_SRCS" "vwebp_sdl")
|
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
|
# get_disto
|
||||||
add_executable(get_disto ${GET_DISTO_SRCS})
|
add_executable(get_disto ${GET_DISTO_SRCS})
|
||||||
target_link_libraries(get_disto imagedec)
|
target_link_libraries(get_disto imagedec)
|
||||||
target_include_directories(get_disto
|
target_include_directories(get_disto
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/src)
|
${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
install(TARGETS get_disto RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
|
|
||||||
# webp_quality
|
# webp_quality
|
||||||
add_executable(webp_quality ${WEBP_QUALITY_SRCS} ${WEBP_EXTRAS_SRCS})
|
add_executable(webp_quality ${WEBP_QUALITY_SRCS})
|
||||||
target_link_libraries(webp_quality exampleutil imagedec)
|
target_link_libraries(webp_quality exampleutil imagedec extras)
|
||||||
target_include_directories(webp_quality
|
target_include_directories(webp_quality
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR})
|
${CMAKE_CURRENT_BINARY_DIR})
|
||||||
install(TARGETS webp_quality RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
|
|
||||||
# vwebp_sdl
|
# vwebp_sdl
|
||||||
find_package(SDL)
|
find_package(SDL)
|
||||||
if(SDL_FOUND)
|
if(WEBP_BUILD_VWEBP AND SDL_FOUND)
|
||||||
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
|
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
|
||||||
target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
|
target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
|
||||||
target_include_directories(vwebp_sdl
|
target_include_directories(vwebp_sdl
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/src
|
${CMAKE_CURRENT_BINARY_DIR}/src
|
||||||
${SDL_INCLUDE_DIR})
|
${SDL_INCLUDE_DIR})
|
||||||
set(WEBP_HAVE_SDL 1)
|
set(WEBP_HAVE_SDL 1)
|
||||||
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
|
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
|
||||||
install(TARGETS vwebp_sdl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -606,7 +664,7 @@ if(WEBP_BUILD_WEBP_JS)
|
|||||||
webp_js
|
webp_js
|
||||||
PROPERTIES LINK_FLAGS "-s WASM=0 \
|
PROPERTIES LINK_FLAGS "-s WASM=0 \
|
||||||
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
||||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||||
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
|
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
|
||||||
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||||
endif()
|
endif()
|
||||||
@ -619,7 +677,7 @@ if(WEBP_BUILD_WEBP_JS)
|
|||||||
webp_wasm
|
webp_wasm
|
||||||
PROPERTIES LINK_FLAGS "-s WASM=1 \
|
PROPERTIES LINK_FLAGS "-s WASM=1 \
|
||||||
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
||||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
-s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||||
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||||
|
|
||||||
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
|
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
|
||||||
@ -637,7 +695,6 @@ if(WEBP_BUILD_ANIM_UTILS)
|
|||||||
imageenc
|
imageenc
|
||||||
imageioutil
|
imageioutil
|
||||||
webp
|
webp
|
||||||
libwebpmux
|
|
||||||
webpdemux
|
webpdemux
|
||||||
${WEBP_DEP_GIF_LIBRARIES})
|
${WEBP_DEP_GIF_LIBRARIES})
|
||||||
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
@ -653,7 +710,6 @@ if(WEBP_BUILD_ANIM_UTILS)
|
|||||||
imageenc
|
imageenc
|
||||||
imageioutil
|
imageioutil
|
||||||
webp
|
webp
|
||||||
libwebpmux
|
|
||||||
webpdemux
|
webpdemux
|
||||||
${WEBP_DEP_GIF_LIBRARIES})
|
${WEBP_DEP_GIF_LIBRARIES})
|
||||||
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
|
29
CONTRIBUTING.md
Normal file
29
CONTRIBUTING.md
Normal file
@ -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/).
|
270
ChangeLog
270
ChangeLog
@ -1,10 +1,278 @@
|
|||||||
|
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.
|
170a8712 Fix check_c_source_compiles with pthread.
|
||||||
|
ceddb5fc Fix check_c_source_compiles with pthread.
|
||||||
85995719 disable CombinedShannonEntropy_SSE2 on x86
|
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
|
8af7436f Merge "{ios,xcframework}build.sh: make min version(s) more visible" into 1.2.0
|
||||||
e56c3c5b pngdec: raise memory limit if needed
|
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
|
13b8e9fe {ios,xcframework}build.sh: make min version(s) more visible
|
||||||
a9225410 animdecoder_fuzzer: fix memory leak
|
a9225410 animdecoder_fuzzer: fix memory leak
|
||||||
d6c2285d update gradle to 6.1.1
|
d6c2285d update gradle to 6.1.1
|
||||||
|
8df77fb1 animdecoder_fuzzer: fix memory leak
|
||||||
52ce6333 update NEWS
|
52ce6333 update NEWS
|
||||||
28c49820 bump version to 1.2.0
|
28c49820 bump version to 1.2.0
|
||||||
7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0
|
7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0
|
||||||
@ -74,7 +342,7 @@ a99078c1 remove call to MBAnalyzeBestIntra4Mode for method >= 5
|
|||||||
6a0ff358 Enc: add a qmin / qmax range for quality factor
|
6a0ff358 Enc: add a qmin / qmax range for quality factor
|
||||||
0fa56f30 Merge tag 'v1.1.0'
|
0fa56f30 Merge tag 'v1.1.0'
|
||||||
6cf504d0 PNM decoding: handle max_value != 255
|
6cf504d0 PNM decoding: handle max_value != 255
|
||||||
d7844e97 update ChangeLog (tag: v1.1.0-rc2, tag: v1.1.0, origin/1.1.0)
|
d7844e97 update ChangeLog (tag: v1.1.0-rc2, tag: v1.1.0)
|
||||||
7f006436 Makefile.vc: fix webp_quality.exe link
|
7f006436 Makefile.vc: fix webp_quality.exe link
|
||||||
cf047e83 Makefile.vc: fix webp_quality.exe link
|
cf047e83 Makefile.vc: fix webp_quality.exe link
|
||||||
c074c653 update NEWS
|
c074c653 update NEWS
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = src imageio man
|
SUBDIRS = sharpyuv src imageio man
|
||||||
EXTRA_DIST = COPYING autogen.sh
|
EXTRA_DIST = COPYING autogen.sh
|
||||||
|
|
||||||
if BUILD_EXTRAS
|
if BUILD_EXTRAS
|
||||||
|
23
Makefile.vc
23
Makefile.vc
@ -31,12 +31,11 @@ CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
|
|||||||
CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1
|
CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1
|
||||||
CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c
|
CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c
|
||||||
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
|
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
|
||||||
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE
|
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE
|
||||||
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
|
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
|
||||||
LNKDLL = link.exe /DLL $(NOLOGO)
|
LNKDLL = link.exe /DLL $(NOLOGO)
|
||||||
LNKEXE = link.exe $(NOLOGO)
|
LNKEXE = link.exe $(NOLOGO)
|
||||||
LNKLIB = lib.exe $(NOLOGO)
|
LNKLIB = lib.exe $(NOLOGO)
|
||||||
MT = mt.exe $(NOLOGO)
|
|
||||||
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
|
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
|
||||||
RCDEBUG = $(RCNODBG) /D_DEBUG
|
RCDEBUG = $(RCNODBG) /D_DEBUG
|
||||||
|
|
||||||
@ -82,6 +81,7 @@ OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
|
|||||||
$(DIROBJ)\extras \
|
$(DIROBJ)\extras \
|
||||||
$(DIROBJ)\imageio \
|
$(DIROBJ)\imageio \
|
||||||
$(DIROBJ)\mux \
|
$(DIROBJ)\mux \
|
||||||
|
$(DIROBJ)\sharpyuv \
|
||||||
$(DIROBJ)\utils \
|
$(DIROBJ)\utils \
|
||||||
|
|
||||||
# Target configuration
|
# Target configuration
|
||||||
@ -174,6 +174,14 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
|
|||||||
# A config was provided, so the library can be built.
|
# A config was provided, so the library can be built.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
SHARPYUV_OBJS = \
|
||||||
|
$(DIROBJ)\sharpyuv\sharpyuv.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 = \
|
DEC_OBJS = \
|
||||||
$(DIROBJ)\dec\alpha_dec.obj \
|
$(DIROBJ)\dec\alpha_dec.obj \
|
||||||
$(DIROBJ)\dec\buffer_dec.obj \
|
$(DIROBJ)\dec\buffer_dec.obj \
|
||||||
@ -215,6 +223,7 @@ DSP_DEC_OBJS = \
|
|||||||
$(DIROBJ)\dsp\lossless_msa.obj \
|
$(DIROBJ)\dsp\lossless_msa.obj \
|
||||||
$(DIROBJ)\dsp\lossless_neon.obj \
|
$(DIROBJ)\dsp\lossless_neon.obj \
|
||||||
$(DIROBJ)\dsp\lossless_sse2.obj \
|
$(DIROBJ)\dsp\lossless_sse2.obj \
|
||||||
|
$(DIROBJ)\dsp\lossless_sse41.obj \
|
||||||
$(DIROBJ)\dsp\rescaler.obj \
|
$(DIROBJ)\dsp\rescaler.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
||||||
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
||||||
@ -334,8 +343,8 @@ UTILS_ENC_OBJS = \
|
|||||||
$(DIROBJ)\utils\quant_levels_utils.obj \
|
$(DIROBJ)\utils\quant_levels_utils.obj \
|
||||||
|
|
||||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(SHARPYUV_OBJS) $(ENC_OBJS) \
|
||||||
$(UTILS_ENC_OBJS) $(DLL_OBJS)
|
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_OBJS)
|
||||||
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
|
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
|
||||||
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
|
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
|
||||||
|
|
||||||
@ -481,6 +490,8 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
|||||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
|
$(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
|
||||||
{imageio}.c{$(DIROBJ)\imageio}.obj::
|
{imageio}.c{$(DIROBJ)\imageio}.obj::
|
||||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $<
|
$(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::
|
{src\dec}.c{$(DIROBJ)\dec}.obj::
|
||||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
|
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
|
||||||
{src\demux}.c{$(DIROBJ)\demux}.obj::
|
{src\demux}.c{$(DIROBJ)\demux}.obj::
|
||||||
@ -501,13 +512,9 @@ LNKLIBS = $(LNKLIBS) Shell32.lib
|
|||||||
|
|
||||||
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
|
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
|
||||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
||||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
|
||||||
del $@.manifest
|
|
||||||
|
|
||||||
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
|
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
|
||||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
||||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
|
||||||
del $@.manifest
|
|
||||||
|
|
||||||
clean::
|
clean::
|
||||||
@-erase /s $(DIROBJ)\*.dll 2> NUL
|
@-erase /s $(DIROBJ)\*.dll 2> NUL
|
||||||
|
28
NEWS
28
NEWS
@ -1,3 +1,31 @@
|
|||||||
|
- 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
|
- 12/23/2020: version 1.2.0
|
||||||
* API changes:
|
* API changes:
|
||||||
- libwebp:
|
- libwebp:
|
||||||
|
245
PRESUBMIT.py
Normal file
245
PRESUBMIT.py
Normal file
@ -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
|
795
README
795
README
@ -1,795 +0,0 @@
|
|||||||
__ __ ____ ____ ____
|
|
||||||
/ \\/ \/ _ \/ _ )/ _ \
|
|
||||||
\ / __/ _ \ __/
|
|
||||||
\__\__/\____/\_____/__/ ____ ___
|
|
||||||
/ _/ / \ \ / _ \/ _/
|
|
||||||
/ \_/ / / \ \ __/ \__
|
|
||||||
\____/____/\_____/_____/____/v1.2.0
|
|
||||||
|
|
||||||
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 http://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 http://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:
|
|
||||||
http://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms
|
|
||||||
http://src.chromium.org/viewvc/chrome/trunk/src/third_party/qcms
|
|
||||||
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-level options] [image files...] [per-frame options...]
|
|
||||||
|
|
||||||
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 (!WebPPictureAllocate(&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:
|
|
||||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
|
||||||
|
|
||||||
Discuss:
|
|
||||||
========
|
|
||||||
|
|
||||||
Email: webp-discuss@webmproject.org
|
|
||||||
Web: http://groups.google.com/a/webmproject.org/group/webp-discuss
|
|
53
README.md
Normal file
53
README.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# WebP Codec
|
||||||
|
|
||||||
|
```
|
||||||
|
__ __ ____ ____ ____
|
||||||
|
/ \\/ \/ _ \/ _ )/ _ \
|
||||||
|
\ / __/ _ \ __/
|
||||||
|
\__\__/\____/\_____/__/ ____ ___
|
||||||
|
/ _/ / \ \ / _ \/ _/
|
||||||
|
/ \_/ / / \ \ __/ \__
|
||||||
|
\____/____/\_____/_____/____/v1.2.3
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
257
README.mux
257
README.mux
@ -1,257 +0,0 @@
|
|||||||
__ __ ____ ____ ____ __ __ _ __ __
|
|
||||||
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
|
||||||
\ / __/ _ \ __/ / / (_/ /__
|
|
||||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.2.0
|
|
||||||
|
|
||||||
|
|
||||||
Description:
|
|
||||||
============
|
|
||||||
|
|
||||||
WebPMux: 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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
> 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:
|
|
||||||
loop LOOP_COUNT set the loop count
|
|
||||||
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 each 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 '-'.
|
|
||||||
|
|
||||||
Visualization tool:
|
|
||||||
===================
|
|
||||||
|
|
||||||
The examples/ directory also contains a tool (vwebp) for viewing WebP files.
|
|
||||||
It decodes the image and visualizes it using OpenGL. See the libwebp README
|
|
||||||
for details on building and running this program.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
|
|
||||||
Bugs:
|
|
||||||
=====
|
|
||||||
|
|
||||||
Please report all bugs to the issue tracker:
|
|
||||||
https://bugs.chromium.org/p/webp
|
|
||||||
Patches welcome! See this page to get started:
|
|
||||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
|
||||||
|
|
||||||
Discuss:
|
|
||||||
========
|
|
||||||
|
|
||||||
Email: webp-discuss@webmproject.org
|
|
||||||
Web: http://groups.google.com/a/webmproject.org/group/webp-discuss
|
|
@ -1,83 +0,0 @@
|
|||||||
__ __ ____ ____ ____ __ ____
|
|
||||||
/ \\/ \ _ \ _ \ _ \ (__)/ __\
|
|
||||||
\ / __/ _ \ __/ _) \_ \
|
|
||||||
\__\__/_____/____/_/ /____/____/
|
|
||||||
|
|
||||||
Description:
|
|
||||||
============
|
|
||||||
|
|
||||||
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://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
|
|
||||||
After installation, you should have some global variable positioned to the
|
|
||||||
location of the SDK. In particular, $EMSCRIPTEN should point to the
|
|
||||||
top-level directory containing Emscripten tools.
|
|
||||||
|
|
||||||
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
|
|
||||||
accessible. This is the toolchain file used by CMake to invoke Emscripten.
|
|
||||||
If $EMSCRIPTEN is unset search for Emscripten.cmake under $EMSDK and set
|
|
||||||
$EMSCRIPTEN accordingly, for example:
|
|
||||||
unix-like environments: export EMSCRIPTEN=$EMSDK/upstream/emscripten
|
|
||||||
windows: set EMSCRIPTEN=%EMSDK%\upstream\emscripten
|
|
||||||
|
|
||||||
- configure the project 'WEBP_JS' with CMake using:
|
|
||||||
|
|
||||||
cd webp_js && \
|
|
||||||
cmake -DWEBP_BUILD_WEBP_JS=ON \
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
|
|
||||||
../
|
|
||||||
|
|
||||||
- compile webp.js using 'make'.
|
|
||||||
|
|
||||||
- that's it! Upon completion, you should have the webp.js and
|
|
||||||
webp.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 an HTTP server to serve the WebP
|
|
||||||
image example. It's easy to just use Python for that.
|
|
||||||
|
|
||||||
cd webp_js && python -m SimpleHTTPServer 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', 'webp_wasm.wasm' in 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 1.37.8,
|
|
||||||
latest-upstream is recommended) and of your WASM-enabled browser to run this
|
|
||||||
version.
|
|
||||||
|
|
||||||
Caveat:
|
|
||||||
=======
|
|
||||||
|
|
||||||
- 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.
|
|
@ -105,6 +105,13 @@ model {
|
|||||||
sources {
|
sources {
|
||||||
c {
|
c {
|
||||||
source {
|
source {
|
||||||
|
srcDir "sharpyuv"
|
||||||
|
include "sharpyuv.c"
|
||||||
|
include "sharpyuv_csp.c"
|
||||||
|
include "sharpyuv_dsp.c"
|
||||||
|
include "sharpyuv_gamma.c"
|
||||||
|
include "sharpyuv_neon.c"
|
||||||
|
include "sharpyuv_sse2.c"
|
||||||
srcDir "src/dec"
|
srcDir "src/dec"
|
||||||
include "alpha_dec.c"
|
include "alpha_dec.c"
|
||||||
include "buffer_dec.c"
|
include "buffer_dec.c"
|
||||||
@ -141,6 +148,7 @@ model {
|
|||||||
include "lossless_msa.c"
|
include "lossless_msa.c"
|
||||||
include "lossless_neon.$NEON"
|
include "lossless_neon.$NEON"
|
||||||
include "lossless_sse2.c"
|
include "lossless_sse2.c"
|
||||||
|
include "lossless_sse41.c"
|
||||||
include "rescaler.c"
|
include "rescaler.c"
|
||||||
include "rescaler_mips32.c"
|
include "rescaler_mips32.c"
|
||||||
include "rescaler_mips_dsp_r2.c"
|
include "rescaler_mips_dsp_r2.c"
|
||||||
|
@ -5,7 +5,7 @@ set(WEBP_VERSION ${WebP_VERSION})
|
|||||||
|
|
||||||
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||||
|
|
||||||
set(WebP_INCLUDE_DIRS "webp")
|
set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||||
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
|
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
|
||||||
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
|
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
|
||||||
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
|
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
# 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.
|
# Check for SIMD extensions.
|
||||||
include(CMakePushCheckState)
|
include(CMakePushCheckState)
|
||||||
|
|
||||||
@ -117,6 +125,12 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
|||||||
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||||
include(CheckCCompilerFlag)
|
include(CheckCCompilerFlag)
|
||||||
if(SIMD_COMPILE_FLAG)
|
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)
|
unset(HAS_COMPILE_FLAG CACHE)
|
||||||
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
||||||
if(HAS_COMPILE_FLAG)
|
if(HAS_COMPILE_FLAG)
|
||||||
@ -134,6 +148,7 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
|||||||
"warning: argument unused during compilation:"
|
"warning: argument unused during compilation:"
|
||||||
${COMMON_PATTERNS})
|
${COMMON_PATTERNS})
|
||||||
if(NOT FLAG_${SIMD_COMPILE_FLAG})
|
if(NOT FLAG_${SIMD_COMPILE_FLAG})
|
||||||
|
unset(HAS_COMPILE_FLAG)
|
||||||
unset(HAS_COMPILE_FLAG CACHE)
|
unset(HAS_COMPILE_FLAG CACHE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
# 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.
|
# Generate the config.h to compile with specific intrinsics / libs.
|
||||||
|
|
||||||
# Check for compiler options.
|
# Check for compiler options.
|
||||||
@ -22,26 +30,25 @@ check_c_source_compiles("
|
|||||||
" HAVE_BUILTIN_BSWAP64)
|
" HAVE_BUILTIN_BSWAP64)
|
||||||
|
|
||||||
# Check for libraries.
|
# Check for libraries.
|
||||||
if(NOT WEBP_BUILD_WEBP_JS)
|
if(WEBP_USE_THREAD)
|
||||||
# Disable pThreads for WASM.
|
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
endif()
|
if(Threads_FOUND)
|
||||||
if(Threads_FOUND)
|
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
|
||||||
# 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")
|
||||||
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||||
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()
|
endif()
|
||||||
check_c_source_compiles("
|
set(WEBP_USE_THREAD ${Threads_FOUND})
|
||||||
#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 ${CMAKE_THREAD_LIBS_INIT})
|
|
||||||
endif()
|
endif()
|
||||||
set(WEBP_USE_THREAD ${Threads_FOUND})
|
|
||||||
|
|
||||||
# TODO: this seems unused, check with autotools.
|
# TODO: this seems unused, check with autotools.
|
||||||
set(LT_OBJDIR ".libs/")
|
set(LT_OBJDIR ".libs/")
|
||||||
@ -67,6 +74,11 @@ endif()
|
|||||||
set(WEBP_DEP_IMG_LIBRARIES)
|
set(WEBP_DEP_IMG_LIBRARIES)
|
||||||
set(WEBP_DEP_IMG_INCLUDE_DIRS)
|
set(WEBP_DEP_IMG_INCLUDE_DIRS)
|
||||||
foreach(I_LIB PNG JPEG TIFF)
|
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})
|
find_package(${I_LIB})
|
||||||
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
|
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
|
||||||
if(${I_LIB}_FOUND)
|
if(${I_LIB}_FOUND)
|
||||||
|
99
configure.ac
99
configure.ac
@ -1,6 +1,6 @@
|
|||||||
AC_INIT([libwebp], [1.2.0],
|
AC_INIT([libwebp], [1.2.3],
|
||||||
[https://bugs.chromium.org/p/webp],,
|
[https://bugs.chromium.org/p/webp],,
|
||||||
[http://developers.google.com/speed/webp])
|
[https://developers.google.com/speed/webp])
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
||||||
@ -9,7 +9,8 @@ dnl === automake >= 1.12 requires this for 'unusual archivers' support.
|
|||||||
dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
|
dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
|
||||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||||
|
|
||||||
AC_PROG_LIBTOOL
|
dnl === AC_PROG_LIBTOOL is deprecated.
|
||||||
|
m4_ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL])
|
||||||
AC_PROG_SED
|
AC_PROG_SED
|
||||||
AM_PROG_CC_C_O
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
@ -27,11 +28,46 @@ AC_ARG_ENABLE([everything],
|
|||||||
AS_HELP_STRING([--enable-everything],
|
AS_HELP_STRING([--enable-everything],
|
||||||
[Enable all optional targets. These can still be
|
[Enable all optional targets. These can still be
|
||||||
disabled with --disable-target]),
|
disabled with --disable-target]),
|
||||||
[SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
|
[SET_IF_UNSET([enable_libsharpyuv], [$enableval])
|
||||||
|
SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
|
||||||
SET_IF_UNSET([enable_libwebpdemux], [$enableval])
|
SET_IF_UNSET([enable_libwebpdemux], [$enableval])
|
||||||
SET_IF_UNSET([enable_libwebpextras], [$enableval])
|
SET_IF_UNSET([enable_libwebpextras], [$enableval])
|
||||||
SET_IF_UNSET([enable_libwebpmux], [$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
|
dnl === If --enable-asserts is not defined, define NDEBUG
|
||||||
|
|
||||||
AC_MSG_CHECKING(whether asserts are enabled)
|
AC_MSG_CHECKING(whether asserts are enabled)
|
||||||
@ -225,6 +261,9 @@ AS_IF([test "x$enable_neon" != "xno"], [
|
|||||||
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
|
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
aarch64*|arm64*)
|
||||||
|
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
AC_SUBST([NEON_FLAGS])])
|
AC_SUBST([NEON_FLAGS])])
|
||||||
|
|
||||||
@ -409,6 +448,10 @@ AS_IF([test "x$enable_gl" != "xno"], [
|
|||||||
|
|
||||||
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
|
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
|
||||||
build_vwebp=yes
|
build_vwebp=yes
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE(
|
||||||
|
m4_normalize([Not building vwebp.
|
||||||
|
OpenGL libraries and --enable-libwebpdemux are required.]))
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
|
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
|
||||||
@ -468,7 +511,7 @@ AS_IF([test "x$enable_sdl" != "xno"], [
|
|||||||
if test x"$sdl_support" = "xyes"; then
|
if test x"$sdl_support" = "xyes"; then
|
||||||
build_vwebp_sdl=yes
|
build_vwebp_sdl=yes
|
||||||
else
|
else
|
||||||
AC_MSG_WARN(Optional SDL library not found)
|
AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -592,11 +635,17 @@ AS_IF([test "x$enable_gif" != "xno"], [
|
|||||||
if test "$gif_support" = "yes" -a \
|
if test "$gif_support" = "yes" -a \
|
||||||
"$enable_libwebpdemux" = "yes"; then
|
"$enable_libwebpdemux" = "yes"; then
|
||||||
build_anim_diff=yes
|
build_anim_diff=yes
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE(
|
||||||
|
[Not building anim_diff. libgif and --enable-libwebpdemux are required.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$gif_support" = "yes" -a \
|
if test "$gif_support" = "yes" -a \
|
||||||
"$enable_libwebpmux" = "yes"; then
|
"$enable_libwebpmux" = "yes"; then
|
||||||
build_gif2webp=yes
|
build_gif2webp=yes
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE(
|
||||||
|
[Not building gif2webp. libgif and --enable-libwebpmux are required.])
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
|
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
|
||||||
@ -604,11 +653,17 @@ AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
|
|||||||
|
|
||||||
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
|
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
|
||||||
build_img2webp=yes
|
build_img2webp=yes
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE(
|
||||||
|
m4_normalize([Not building img2webp.
|
||||||
|
--enable-libwebpdemux & --enable-libwebpmux are required.]))
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
|
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
|
||||||
|
|
||||||
if test "$enable_libwebpmux" = "yes"; then
|
if test "$enable_libwebpmux" = "yes"; then
|
||||||
build_webpinfo=yes
|
build_webpinfo=yes
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
|
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
|
||||||
|
|
||||||
@ -692,45 +747,13 @@ else
|
|||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl === Check whether libwebpmux should be built
|
|
||||||
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
|
||||||
AC_ARG_ENABLE([libwebpmux],
|
|
||||||
AS_HELP_STRING([--enable-libwebpmux],
|
|
||||||
[Build libwebpmux @<:@default=no@:>@]))
|
|
||||||
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 =========================
|
dnl =========================
|
||||||
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS([src/webp/config.h])
|
AC_CONFIG_HEADERS([src/webp/config.h])
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
|
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
|
||||||
examples/Makefile extras/Makefile imageio/Makefile \
|
examples/Makefile extras/Makefile imageio/Makefile \
|
||||||
|
sharpyuv/Makefile \
|
||||||
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
|
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
|
||||||
src/demux/Makefile src/mux/Makefile \
|
src/demux/Makefile src/mux/Makefile \
|
||||||
src/utils/Makefile \
|
src/utils/Makefile \
|
||||||
|
29
doc/README
29
doc/README
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
Generate libwebp Container Spec Docs from Text Source
|
|
||||||
=====================================================
|
|
||||||
|
|
||||||
HTML generation requires kramdown [1], easily installed as a
|
|
||||||
rubygem [2]. Rubygems installation should satisfy dependencies
|
|
||||||
automatically.
|
|
||||||
|
|
||||||
[1]: http://kramdown.rubyforge.org/
|
|
||||||
[2]: http://rubygems.org/
|
|
||||||
|
|
||||||
HTML generation can then be done from the project root:
|
|
||||||
|
|
||||||
$ 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 [3],
|
|
||||||
a dependency of kramdown that rubygems will install automatically. The
|
|
||||||
following will apply inline CSS styling; an external stylesheet is not
|
|
||||||
needed.
|
|
||||||
|
|
||||||
$ 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.
|
|
||||||
|
|
||||||
[3]: http://coderay.rubychan.de/
|
|
385
doc/api.md
Normal file
385
doc/api.md
Normal file
@ -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).
|
213
doc/building.md
Normal file
213
doc/building.md
Normal file
@ -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)
|
26
doc/specs_generation.md
Normal file
26
doc/specs_generation.md
Normal file
@ -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.
|
512
doc/tools.md
Normal file
512
doc/tools.md
Normal file
@ -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 '-'.
|
||||||
|
```
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
Although you may be viewing an alternate representation, this document
|
Although you may be viewing an alternate representation, this document
|
||||||
is sourced in Markdown, a light-duty markup scheme, and is optimized for
|
is sourced in Markdown, a light-duty markup scheme, and is optimized for
|
||||||
the [kramdown](http://kramdown.rubyforge.org/) transformer.
|
the [kramdown](https://kramdown.gettalong.org/) transformer.
|
||||||
|
|
||||||
See the accompanying README. External link targets are referenced at the
|
See the accompanying specs_generation.md. External link targets are referenced
|
||||||
end of this file.
|
at the end of this file.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ for:
|
|||||||
* **Lossless compression.** An image can be losslessly compressed, using the
|
* **Lossless compression.** An image can be losslessly compressed, using the
|
||||||
WebP Lossless Format.
|
WebP Lossless Format.
|
||||||
|
|
||||||
* **Metadata.** An image may have metadata stored in EXIF or XMP formats.
|
* **Metadata.** An image may have metadata stored in Exif or XMP formats.
|
||||||
|
|
||||||
* **Transparency.** An image may have transparency, i.e., an alpha channel.
|
* **Transparency.** An image may have transparency, i.e., an alpha channel.
|
||||||
|
|
||||||
@ -53,10 +53,6 @@ document are to be interpreted as described in [RFC 2119][].
|
|||||||
Bit numbering in chunk diagrams starts at `0` for the most significant bit
|
Bit numbering in chunk diagrams starts at `0` for the most significant bit
|
||||||
('MSB 0') as described in [RFC 1166][].
|
('MSB 0') as described in [RFC 1166][].
|
||||||
|
|
||||||
**Note:** Out of the features mentioned above, lossy compression, lossless
|
|
||||||
compression, transparency, metadata, color profile and animation are finalized
|
|
||||||
and are to be considered stable.
|
|
||||||
|
|
||||||
Terminology & Basics
|
Terminology & Basics
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@ -98,7 +94,7 @@ _1-based_
|
|||||||
RIFF File Format
|
RIFF File Format
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
The WebP file format is based on the RIFF (resource interchange file format)
|
The WebP file format is based on the RIFF (Resource Interchange File Format)
|
||||||
document format.
|
document format.
|
||||||
|
|
||||||
The basic element of a RIFF file is a _chunk_. It consists of:
|
The basic element of a RIFF file is a _chunk_. It consists of:
|
||||||
@ -265,11 +261,11 @@ An extended format file consists of:
|
|||||||
|
|
||||||
* Image data.
|
* Image data.
|
||||||
|
|
||||||
* An optional 'EXIF' chunk with EXIF metadata.
|
* An optional 'EXIF' chunk with Exif metadata.
|
||||||
|
|
||||||
* An optional 'XMP ' chunk with XMP metadata.
|
* An optional 'XMP ' chunk with XMP metadata.
|
||||||
|
|
||||||
* An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_
|
* An optional list of [unknown chunks](#unknown-chunks).
|
||||||
|
|
||||||
For a _still image_, the _image data_ consists of a single frame, which is made
|
For a _still image_, the _image data_ consists of a single frame, which is made
|
||||||
up of:
|
up of:
|
||||||
@ -321,9 +317,9 @@ Alpha (L): 1 bit
|
|||||||
: Set if any of the frames of the image contain transparency information
|
: Set if any of the frames of the image contain transparency information
|
||||||
("alpha").
|
("alpha").
|
||||||
|
|
||||||
EXIF metadata (E): 1 bit
|
Exif metadata (E): 1 bit
|
||||||
|
|
||||||
: Set if the file contains EXIF metadata.
|
: Set if the file contains Exif metadata.
|
||||||
|
|
||||||
XMP metadata (X): 1 bit
|
XMP metadata (X): 1 bit
|
||||||
|
|
||||||
@ -345,12 +341,12 @@ Reserved: 24 bits
|
|||||||
Canvas Width Minus One: 24 bits
|
Canvas Width Minus One: 24 bits
|
||||||
|
|
||||||
: _1-based_ width of the canvas in pixels.
|
: _1-based_ width of the canvas in pixels.
|
||||||
The actual canvas width is '1 + Canvas Width Minus One'
|
The actual canvas width is `1 + Canvas Width Minus One`.
|
||||||
|
|
||||||
Canvas Height Minus One: 24 bits
|
Canvas Height Minus One: 24 bits
|
||||||
|
|
||||||
: _1-based_ height of the canvas in pixels.
|
: _1-based_ height of the canvas in pixels.
|
||||||
The actual canvas height is '1 + Canvas Height Minus One'
|
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`.
|
The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`.
|
||||||
|
|
||||||
@ -427,21 +423,21 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
|
|||||||
|
|
||||||
Frame X: 24 bits (_uint24_)
|
Frame X: 24 bits (_uint24_)
|
||||||
|
|
||||||
: The X coordinate of the upper left corner of the frame is `Frame X * 2`
|
: The X coordinate of the upper left corner of the frame is `Frame X * 2`.
|
||||||
|
|
||||||
Frame Y: 24 bits (_uint24_)
|
Frame Y: 24 bits (_uint24_)
|
||||||
|
|
||||||
: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`
|
: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`.
|
||||||
|
|
||||||
Frame Width Minus One: 24 bits (_uint24_)
|
Frame Width Minus One: 24 bits (_uint24_)
|
||||||
|
|
||||||
: The _1-based_ width of the frame.
|
: The _1-based_ width of the frame.
|
||||||
The frame width is `1 + Frame Width Minus One`
|
The frame width is `1 + Frame Width Minus One`.
|
||||||
|
|
||||||
Frame Height Minus One: 24 bits (_uint24_)
|
Frame Height Minus One: 24 bits (_uint24_)
|
||||||
|
|
||||||
: The _1-based_ height of the frame.
|
: The _1-based_ height of the frame.
|
||||||
The frame height is `1 + Frame Height Minus One`
|
The frame height is `1 + Frame Height Minus One`.
|
||||||
|
|
||||||
Frame Duration: 24 bits (_uint24_)
|
Frame Duration: 24 bits (_uint24_)
|
||||||
|
|
||||||
@ -681,12 +677,12 @@ EXIF chunk:
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| ChunkHeader('EXIF') |
|
| ChunkHeader('EXIF') |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| EXIF Metadata |
|
| Exif Metadata |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
EXIF Metadata: _Chunk Size_ bytes
|
Exif Metadata: _Chunk Size_ bytes
|
||||||
|
|
||||||
: image metadata in EXIF format.
|
: image metadata in Exif format.
|
||||||
|
|
||||||
XMP chunk:
|
XMP chunk:
|
||||||
|
|
||||||
@ -705,7 +701,7 @@ XMP Metadata: _Chunk Size_ bytes
|
|||||||
Additional guidance about handling metadata can be found in the
|
Additional guidance about handling metadata can be found in the
|
||||||
Metadata Working Group's [Guidelines for Handling Metadata][metadata].
|
Metadata Working Group's [Guidelines for Handling Metadata][metadata].
|
||||||
|
|
||||||
#### Unknown Chunks _\[status: experimental\]_
|
#### Unknown Chunks
|
||||||
|
|
||||||
A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
|
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
|
tag_ is different from any of the chunks described in this document, is
|
||||||
@ -802,7 +798,7 @@ RIFF/WEBP
|
|||||||
+- XMP (metadata)
|
+- XMP (metadata)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
An animated image with EXIF metadata may look as follows:
|
An animated image with Exif metadata may look as follows:
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
RIFF/WEBP
|
RIFF/WEBP
|
||||||
@ -815,9 +811,9 @@ RIFF/WEBP
|
|||||||
+- EXIF (metadata)
|
+- EXIF (metadata)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[vp8spec]: http://tools.ietf.org/html/rfc6386
|
[vp8spec]: https://datatracker.ietf.org/doc/html/rfc6386
|
||||||
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
|
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
|
||||||
[iccspec]: http://www.color.org/icc_specs2.xalter
|
[iccspec]: https://www.color.org/icc_specs2.xalter
|
||||||
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
||||||
[rfc 1166]: http://tools.ietf.org/html/rfc1166
|
[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166
|
||||||
[rfc 2119]: http://tools.ietf.org/html/rfc2119
|
[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
Although you may be viewing an alternate representation, this document
|
Although you may be viewing an alternate representation, this document
|
||||||
is sourced in Markdown, a light-duty markup scheme, and is optimized for
|
is sourced in Markdown, a light-duty markup scheme, and is optimized for
|
||||||
the [kramdown](http://kramdown.rubyforge.org/) transformer.
|
the [kramdown](https://kramdown.gettalong.org/) transformer.
|
||||||
|
|
||||||
See the accompanying README. External link targets are referenced at the
|
See the accompanying specs_generation.md. External link targets are referenced
|
||||||
end of this file.
|
at the end of this file.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -16,6 +16,8 @@ _Jyrki Alakuijala, Ph.D., Google, Inc., 2012-06-19_
|
|||||||
|
|
||||||
Paragraphs marked as \[AMENDED\] were amended on 2014-09-16.
|
Paragraphs marked as \[AMENDED\] were amended on 2014-09-16.
|
||||||
|
|
||||||
|
Paragraphs marked as \[AMENDED2\] were amended on 2022-05-13.
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
--------
|
--------
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ exactly, including the color values for zero alpha pixels. The
|
|||||||
format uses subresolution images, recursively embedded into the format
|
format uses subresolution images, recursively embedded into the format
|
||||||
itself, for storing statistical data about the images, such as the used
|
itself, for storing statistical data about the images, such as the used
|
||||||
entropy codes, spatial predictors, color space conversion, and color
|
entropy codes, spatial predictors, color space conversion, and color
|
||||||
table. LZ77, Huffman coding, and a color cache are used for compression
|
table. LZ77, prefix coding, and a color cache are used for compression
|
||||||
of the bulk data. Decoding speeds faster than PNG have been
|
of the bulk data. Decoding speeds faster than PNG have been
|
||||||
demonstrated, as well as 25% denser compression than can be achieved
|
demonstrated, as well as 25% denser compression than can be achieved
|
||||||
using today's PNG format.
|
using today's PNG format.
|
||||||
@ -63,9 +65,9 @@ distance mapping
|
|||||||
entropy image
|
entropy image
|
||||||
: A two-dimensional subresolution image indicating which entropy coding
|
: A two-dimensional subresolution image indicating which entropy coding
|
||||||
should be used in a respective square in the image, i.e., each pixel
|
should be used in a respective square in the image, i.e., each pixel
|
||||||
is a meta Huffman code.
|
is a meta prefix code.
|
||||||
|
|
||||||
Huffman code
|
prefix code
|
||||||
: A classic way to do entropy coding where a smaller number of bits are
|
: A classic way to do entropy coding where a smaller number of bits are
|
||||||
used for more frequent codes.
|
used for more frequent codes.
|
||||||
|
|
||||||
@ -73,9 +75,9 @@ LZ77
|
|||||||
: Dictionary-based sliding window compression algorithm that either
|
: Dictionary-based sliding window compression algorithm that either
|
||||||
emits symbols or describes them as sequences of past symbols.
|
emits symbols or describes them as sequences of past symbols.
|
||||||
|
|
||||||
meta Huffman code
|
meta prefix code
|
||||||
: A small integer (up to 16 bits) that indexes an element in the meta
|
: A small integer (up to 16 bits) that indexes an element in the meta
|
||||||
Huffman table.
|
prefix table.
|
||||||
|
|
||||||
predictor image
|
predictor image
|
||||||
: A two-dimensional subresolution image indicating which spatial
|
: A two-dimensional subresolution image indicating which spatial
|
||||||
@ -235,7 +237,7 @@ transform, the current pixel value is predicted from the pixels already
|
|||||||
decoded (in scan-line order) and only the residual value (actual -
|
decoded (in scan-line order) and only the residual value (actual -
|
||||||
predicted) is encoded. The _prediction mode_ determines the type of
|
predicted) is encoded. The _prediction mode_ determines the type of
|
||||||
prediction to use. We divide the image into squares and all the pixels
|
prediction to use. We divide the image into squares and all the pixels
|
||||||
in a square use same prediction mode.
|
in a square use the same prediction mode.
|
||||||
|
|
||||||
The first 3 bits of prediction data define the block width and height in
|
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
|
number of bits. The number of block columns, `block_xsize`, is used in
|
||||||
@ -367,15 +369,17 @@ 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
|
0xff000000, L-pixel for all pixels on the top row, and T-pixel for all
|
||||||
pixels on the leftmost column.
|
pixels on the leftmost column.
|
||||||
|
|
||||||
|
\[AMENDED2\]
|
||||||
Addressing the TR-pixel for pixels on the rightmost column is
|
Addressing the TR-pixel for pixels on the rightmost column is
|
||||||
exceptional. The pixels on the rightmost column are predicted by using
|
exceptional. The pixels on the rightmost column are predicted by using
|
||||||
the modes \[0..13\] just like pixels not on border, but by using the
|
the modes \[0..13\] just like pixels not on the border, but the leftmost pixel
|
||||||
leftmost pixel on the same row as the current TR-pixel. The TR-pixel
|
on the same row as the current pixel is instead used as the TR-pixel.
|
||||||
offset in memory is the same for border and non-border pixels.
|
|
||||||
|
|
||||||
|
|
||||||
### Color Transform
|
### Color Transform
|
||||||
|
|
||||||
|
\[AMENDED2\]
|
||||||
|
|
||||||
The goal of the color transform is to decorrelate the R, G and B values
|
The goal of the color transform is to decorrelate the R, G and B values
|
||||||
of each pixel. Color transform keeps the green (G) value as it is,
|
of each pixel. Color transform keeps the green (G) value as it is,
|
||||||
transforms red (R) based on green and transforms blue (B) based on green
|
transforms red (R) based on green and transforms blue (B) based on green
|
||||||
@ -396,8 +400,8 @@ typedef struct {
|
|||||||
The actual color transformation is done by defining a color transform
|
The actual color transformation is done by defining a color transform
|
||||||
delta. The color transform delta depends on the `ColorTransformElement`,
|
delta. The color transform delta depends on the `ColorTransformElement`,
|
||||||
which is the same for all the pixels in a particular block. The delta is
|
which is the same for all the pixels in a particular block. The delta is
|
||||||
added during color transform. The inverse color transform then is just
|
subtracted during color transform. The inverse color transform then is just
|
||||||
subtracting those deltas.
|
adding those deltas.
|
||||||
|
|
||||||
The color transform function is defined as follows:
|
The color transform function is defined as follows:
|
||||||
|
|
||||||
@ -406,13 +410,13 @@ void ColorTransform(uint8 red, uint8 blue, uint8 green,
|
|||||||
ColorTransformElement *trans,
|
ColorTransformElement *trans,
|
||||||
uint8 *new_red, uint8 *new_blue) {
|
uint8 *new_red, uint8 *new_blue) {
|
||||||
// Transformed values of red and blue components
|
// Transformed values of red and blue components
|
||||||
uint32 tmp_red = red;
|
int tmp_red = red;
|
||||||
uint32 tmp_blue = blue;
|
int tmp_blue = blue;
|
||||||
|
|
||||||
// Applying transform is just adding the transform deltas
|
// Applying the transform is just subtracting the transform deltas
|
||||||
tmp_red += ColorTransformDelta(trans->green_to_red, green);
|
tmp_red -= ColorTransformDelta(p->green_to_red_, green);
|
||||||
tmp_blue += ColorTransformDelta(trans->green_to_blue, green);
|
tmp_blue -= ColorTransformDelta(p->green_to_blue_, green);
|
||||||
tmp_blue += ColorTransformDelta(trans->red_to_blue, red);
|
tmp_blue -= ColorTransformDelta(p->red_to_blue_, red);
|
||||||
|
|
||||||
*new_red = tmp_red & 0xff;
|
*new_red = tmp_red & 0xff;
|
||||||
*new_blue = tmp_blue & 0xff;
|
*new_blue = tmp_blue & 0xff;
|
||||||
@ -430,7 +434,7 @@ int8 ColorTransformDelta(int8 t, int8 c) {
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
A conversion from the 8-bit unsigned representation (uint8) to the 8-bit
|
A conversion from the 8-bit unsigned representation (uint8) to the 8-bit
|
||||||
signed one (int8) is required before calling ColorTransformDelta().
|
signed one (int8) is required before calling `ColorTransformDelta()`.
|
||||||
It should be performed using 8-bit two's complement (that is: uint8 range
|
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).
|
\[128-255\] is mapped to the \[-128, -1\] range of its converted int8 value).
|
||||||
|
|
||||||
@ -468,14 +472,18 @@ channels.
|
|||||||
void InverseTransform(uint8 red, uint8 green, uint8 blue,
|
void InverseTransform(uint8 red, uint8 green, uint8 blue,
|
||||||
ColorTransformElement *p,
|
ColorTransformElement *p,
|
||||||
uint8 *new_red, uint8 *new_blue) {
|
uint8 *new_red, uint8 *new_blue) {
|
||||||
// Applying inverse transform is just subtracting the
|
// Transformed values of red and blue components
|
||||||
// color transform deltas
|
int tmp_red = red;
|
||||||
red -= ColorTransformDelta(p->green_to_red_, green);
|
int tmp_blue = blue;
|
||||||
blue -= ColorTransformDelta(p->green_to_blue_, green);
|
|
||||||
blue -= ColorTransformDelta(p->red_to_blue_, red & 0xff);
|
|
||||||
|
|
||||||
*new_red = red & 0xff;
|
// Applying inverse transform is just adding the
|
||||||
*new_blue = blue & 0xff;
|
// 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;
|
||||||
}
|
}
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -590,12 +598,12 @@ The values are packed into the green component as follows:
|
|||||||
4 most-significant bits of the green value at x / 2.
|
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
|
* `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
|
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 in order to the
|
green value at x / 4, green values at x + 1 to x + 3 are positioned in order
|
||||||
more significant bits of the green value at x / 4.
|
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
|
* `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 is positioned into the least-significant bit of the green
|
||||||
value at x / 8, green values at x + 1 to x + 7 in order to the more
|
value at x / 8, green values at x + 1 to x + 7 are positioned in order to
|
||||||
significant bits of the green value at x / 8.
|
the more significant bits of the green value at x / 8.
|
||||||
|
|
||||||
|
|
||||||
4 Image Data
|
4 Image Data
|
||||||
@ -609,8 +617,8 @@ We use image data in five different roles:
|
|||||||
|
|
||||||
1. ARGB image: Stores the actual pixels of the image.
|
1. ARGB image: Stores the actual pixels of the image.
|
||||||
1. Entropy image: Stores the
|
1. Entropy image: Stores the
|
||||||
[meta Huffman codes](#decoding-of-meta-huffman-codes). The red and green
|
[meta prefix codes](#decoding-of-meta-prefix-codes). The red and green
|
||||||
components of a pixel define the meta Huffman code used in a particular
|
components of a pixel define the meta prefix code used in a particular
|
||||||
block of the ARGB image.
|
block of the ARGB image.
|
||||||
1. Predictor image: Stores the metadata for [Predictor
|
1. Predictor image: Stores the metadata for [Predictor
|
||||||
Transform](#predictor-transform). The green component of a pixel defines
|
Transform](#predictor-transform). The green component of a pixel defines
|
||||||
@ -621,12 +629,12 @@ We use image data in five different roles:
|
|||||||
the image. Each `ColorTransformElement` `'cte'` is treated as a pixel whose
|
the image. Each `ColorTransformElement` `'cte'` is treated as a pixel whose
|
||||||
alpha component is `255`, red component is `cte.red_to_blue`, green
|
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`.
|
component is `cte.green_to_blue` and blue component is `cte.green_to_red`.
|
||||||
1. Color indexing image: An array of of size `color_table_size` (up to 256
|
1. Color indexing image: An array of size `color_table_size` (up to 256
|
||||||
ARGB values) storing the metadata for the
|
ARGB values) storing the metadata for the
|
||||||
[Color Indexing Transform](#color-indexing-transform). This is stored as an
|
[Color Indexing Transform](#color-indexing-transform). This is stored as an
|
||||||
image of width `color_table_size` and height `1`.
|
image of width `color_table_size` and height `1`.
|
||||||
|
|
||||||
### 4.2 Encoding of Image data
|
### 4.2 Encoding of Image Data
|
||||||
|
|
||||||
The encoding of image data is independent of its role.
|
The encoding of image data is independent of its role.
|
||||||
|
|
||||||
@ -643,7 +651,7 @@ the image.
|
|||||||
|
|
||||||
Each pixel is encoded using one of the three possible methods:
|
Each pixel is encoded using one of the three possible methods:
|
||||||
|
|
||||||
1. Huffman coded literal: each channel (green, red, blue and alpha) is
|
1. prefix coded literal: each channel (green, red, blue and alpha) is
|
||||||
entropy-coded independently;
|
entropy-coded independently;
|
||||||
2. LZ77 backward reference: a sequence of pixels are copied from elsewhere
|
2. LZ77 backward reference: a sequence of pixels are copied from elsewhere
|
||||||
in the image; or
|
in the image; or
|
||||||
@ -652,9 +660,9 @@ Each pixel is encoded using one of the three possible methods:
|
|||||||
|
|
||||||
The following sub-sections describe each of these in detail.
|
The following sub-sections describe each of these in detail.
|
||||||
|
|
||||||
#### 4.2.1 Huffman Coded Literals
|
#### 4.2.1 Prefix Coded Literals
|
||||||
|
|
||||||
The pixel is stored as Huffman coded values of green, red, blue and alpha (in
|
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.
|
that order). See [this section](#decoding-entropy-coded-image-data) for details.
|
||||||
|
|
||||||
#### 4.2.2 LZ77 Backward Reference
|
#### 4.2.2 LZ77 Backward Reference
|
||||||
@ -678,7 +686,7 @@ very few values in the image. Thus, this approach results in a better
|
|||||||
compression overall.
|
compression overall.
|
||||||
|
|
||||||
The following table denotes the prefix codes and extra bits used for storing
|
The following table denotes the prefix codes and extra bits used for storing
|
||||||
different range of values.
|
different ranges of values.
|
||||||
|
|
||||||
Note: The maximum backward reference length is limited to 4096. Hence, only the
|
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
|
first 24 prefix codes (with the respective extra bits) are meaningful for length
|
||||||
@ -753,13 +761,13 @@ The mapping between distance code `i` and the neighboring pixel offset
|
|||||||
(-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6), (8, 7)
|
(-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6), (8, 7)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
For example, distance code `1` indicates offset of `(0, 1)` for the neighboring
|
For example, distance code `1` indicates an offset of `(0, 1)` for the
|
||||||
pixel, that is, the pixel above the current pixel (0-pixel difference in
|
neighboring pixel, that is, the pixel above the current pixel (0 pixel
|
||||||
X-direction and 1 pixel difference in Y-direction). Similarly, distance code
|
difference in X-direction and 1 pixel difference in Y-direction). Similarly,
|
||||||
`3` indicates left-top pixel.
|
distance code `3` indicates left-top pixel.
|
||||||
|
|
||||||
The decoder can convert a distances code 'i' to a scan-line order distance
|
The decoder can convert a distance code `i` to a scan-line order distance
|
||||||
'dist' as follows:
|
`dist` as follows:
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
(xi, yi) = distance_map[i]
|
(xi, yi) = distance_map[i]
|
||||||
@ -769,21 +777,22 @@ if (dist < 1) {
|
|||||||
}
|
}
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
where 'distance_map' is the mapping noted above and `xsize` is the width of the
|
where `distance_map` is the mapping noted above and `xsize` is the width of the
|
||||||
image in pixels.
|
image in pixels.
|
||||||
|
|
||||||
|
|
||||||
#### 4.2.3 Color Cache Coding
|
#### 4.2.3 Color Cache Coding
|
||||||
|
{:#color-cache-code}
|
||||||
|
|
||||||
Color cache stores a set of colors that have been recently used in the image.
|
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
|
**Rationale:** This way, the recently used colors can sometimes be referred to
|
||||||
more efficiently than emitting them using other two methods (described in
|
more efficiently than emitting them using the other two methods (described in
|
||||||
[4.2.1](#huffman-coded-literals) and [4.2.2](#lz77-backward-reference)).
|
[4.2.1](#prefix-coded-literals) and [4.2.2](#lz77-backward-reference)).
|
||||||
|
|
||||||
Color cache codes are stored as follows. First, there is a 1-bit value that
|
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
|
indicates if the color cache is used. If this bit is 0, no color cache codes
|
||||||
exist, and they are not transmitted in the Huffman code that decodes the green
|
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
|
symbols and the length prefix codes. However, if this bit is 1, the color cache
|
||||||
size is read next:
|
size is read next:
|
||||||
|
|
||||||
@ -814,130 +823,245 @@ literals, into the cache in the order they appear in the stream.
|
|||||||
|
|
||||||
### 5.1 Overview
|
### 5.1 Overview
|
||||||
|
|
||||||
Most of the data is coded using [canonical Huffman code][canonical_huff]. Hence,
|
Most of the data is coded using a [canonical prefix code][canonical_huff].
|
||||||
the codes are transmitted by sending the _Huffman code lengths_, as opposed to
|
Hence, the codes are transmitted by sending the _prefix code lengths_, as
|
||||||
the actual _Huffman codes_.
|
opposed to the actual _prefix codes_.
|
||||||
|
|
||||||
In particular, the format uses **spatially-variant Huffman coding**. In other
|
In particular, the format uses **spatially-variant prefix coding**. In other
|
||||||
words, different blocks of the image can potentially use different entropy
|
words, different blocks of the image can potentially use different entropy
|
||||||
codes.
|
codes.
|
||||||
|
|
||||||
**Rationale**: Different areas of the image may have different characteristics. So, allowing them to use different entropy codes provides more flexibility and
|
**Rationale**: Different areas of the image may have different characteristics.
|
||||||
potentially a better compression.
|
So, allowing them to use different entropy codes provides more flexibility and
|
||||||
|
potentially better compression.
|
||||||
|
|
||||||
### 5.2 Details
|
### 5.2 Details
|
||||||
|
|
||||||
The encoded image data consists of two parts:
|
The encoded image data consists of several parts:
|
||||||
|
|
||||||
1. Meta Huffman codes
|
1. Decoding and building the prefix codes \[AMENDED2\]
|
||||||
|
1. Meta prefix codes
|
||||||
1. Entropy-coded image data
|
1. Entropy-coded image data
|
||||||
|
|
||||||
#### 5.2.1 Decoding of Meta Huffman Codes
|
#### 5.2.1 Decoding and Building the Prefix Codes
|
||||||
|
|
||||||
As noted earlier, the format allows the use of different Huffman codes for
|
There are several steps in decoding the prefix codes.
|
||||||
different blocks of the image. _Meta Huffman codes_ are indexes identifying
|
|
||||||
which Huffman codes to use in different parts of the image.
|
|
||||||
|
|
||||||
Meta Huffman codes may be used _only_ when the image is being used in the
|
**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 a 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 > 18, the bitstream is invalid.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#### 5.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_.
|
[role](#roles-of-image-data) of an _ARGB image_.
|
||||||
|
|
||||||
There are two possibilities for the meta Huffman codes, indicated by a 1-bit
|
There are two possibilities for the meta prefix codes, indicated by a 1-bit
|
||||||
value:
|
value:
|
||||||
|
|
||||||
* If this bit is zero, there is only one meta Huffman code used everywhere in
|
* If this bit is zero, there is only one meta prefix code used everywhere in
|
||||||
the image. No more data is stored.
|
the image. No more data is stored.
|
||||||
* If this bit is one, the image uses multiple meta Huffman codes. These meta
|
* If this bit is one, the image uses multiple meta prefix codes. These meta
|
||||||
Huffman codes are stored as an _entropy image_ (described below).
|
prefix codes are stored as an _entropy image_ (described below).
|
||||||
|
|
||||||
**Entropy image:**
|
**Entropy image:**
|
||||||
|
|
||||||
The entropy image defines which Huffman codes are used in different parts of the
|
The entropy image defines which prefix codes are used in different parts of the
|
||||||
image, as described below.
|
image, as described below.
|
||||||
|
|
||||||
The first 3-bits contain the `huffman_bits` value. The dimensions of the entropy
|
The first 3-bits contain the `prefix_bits` value. The dimensions of the entropy
|
||||||
image are derived from 'huffman_bits'.
|
image are derived from 'prefix_bits'.
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
int huffman_bits = ReadBits(3) + 2;
|
int prefix_bits = ReadBits(3) + 2;
|
||||||
int huffman_xsize = DIV_ROUND_UP(xsize, 1 << huffman_bits);
|
int prefix_xsize = DIV_ROUND_UP(xsize, 1 << prefix_bits);
|
||||||
int huffman_ysize = DIV_ROUND_UP(ysize, 1 << huffman_bits);
|
int prefix_ysize = DIV_ROUND_UP(ysize, 1 << prefix_bits);
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
where `DIV_ROUND_UP` is as defined [earlier](#predictor-transform).
|
where `DIV_ROUND_UP` is as defined [earlier](#predictor-transform).
|
||||||
|
|
||||||
Next bits contain an entropy image of width `huffman_xsize` and height
|
The next bits contain an entropy image of width `prefix_xsize` and height
|
||||||
`huffman_ysize`.
|
`prefix_ysize`.
|
||||||
|
|
||||||
**Interpretation of Meta Huffman Codes:**
|
**Interpretation of Meta Prefix Codes:**
|
||||||
|
|
||||||
For any given pixel (x, y), there is a set of five Huffman codes associated with
|
For any given pixel (x, y), there is a set of five prefix codes associated with
|
||||||
it. These codes are (in bitstream order):
|
it. These codes are (in bitstream order):
|
||||||
|
|
||||||
* **Huffman code #1**: used for green channel, backward-reference length and
|
* **prefix code #1**: used for green channel, backward-reference length and
|
||||||
color cache
|
color cache
|
||||||
* **Huffman code #2, #3 and #4**: used for red, blue and alpha channels
|
* **prefix code #2, #3 and #4**: used for red, blue and alpha channels
|
||||||
respectively.
|
respectively.
|
||||||
* **Huffman code #5**: used for backward-reference distance.
|
* **prefix code #5**: used for backward-reference distance.
|
||||||
|
|
||||||
From here on, we refer to this set as a **Huffman code group**.
|
From here on, we refer to this set as a **prefix code group**.
|
||||||
|
|
||||||
The number of Huffman code groups in the ARGB image can be obtained by finding
|
The number of prefix code groups in the ARGB image can be obtained by finding
|
||||||
the _largest meta Huffman code_ from the entropy image:
|
the _largest meta prefix code_ from the entropy image:
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
int num_huff_groups = max(entropy image) + 1;
|
int num_prefix_groups = max(entropy image) + 1;
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
where `max(entropy image)` indicates the largest Huffman code stored in the
|
where `max(entropy image)` indicates the largest prefix code stored in the
|
||||||
entropy image.
|
entropy image.
|
||||||
|
|
||||||
As each Huffman code groups contains five Huffman codes, the total number of
|
As each prefix code group contains five prefix codes, the total number of
|
||||||
Huffman codes is:
|
prefix codes is:
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
int num_huff_codes = 5 * num_huff_groups;
|
int num_prefix_codes = 5 * num_prefix_groups;
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Given a pixel (x, y) in the ARGB image, we can obtain the corresponding Huffman
|
Given a pixel (x, y) in the ARGB image, we can obtain the corresponding prefix
|
||||||
codes to be used as follows:
|
codes to be used as follows:
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
int position = (y >> huffman_bits) * huffman_xsize + (x >> huffman_bits);
|
int position = (y >> prefix_bits) * prefix_xsize + (x >> prefix_bits);
|
||||||
int meta_huff_code = (entropy_image[pos] >> 8) & 0xffff;
|
int meta_prefix_code = (entropy_image[pos] >> 8) & 0xffff;
|
||||||
HuffmanCodeGroup huff_group = huffman_code_groups[meta_huff_code];
|
PrefixCodeGroup prefix_group = prefix_code_groups[meta_prefix_code];
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
where, we have assumed the existence of `HuffmanCodeGroup` structure, which
|
where, we have assumed the existence of `PrefixCodeGroup` structure, which
|
||||||
represents a set of five Huffman codes. Also, `huffman_code_groups` is an array
|
represents a set of five prefix codes. Also, `prefix_code_groups` is an array
|
||||||
of `HuffmanCodeGroup` (of size `num_huff_groups`).
|
of `PrefixCodeGroup` (of size `num_prefix_groups`).
|
||||||
|
|
||||||
The decoder then uses Huffman code group `huff_group` to decode the pixel
|
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).
|
(x, y) as explained in the [next section](#decoding-entropy-coded-image-data).
|
||||||
|
|
||||||
#### 5.2.2 Decoding Entropy-coded Image Data
|
#### 5.2.3 Decoding Entropy-coded Image Data
|
||||||
|
|
||||||
|
\[AMENDED2\]
|
||||||
|
|
||||||
For the current position (x, y) in the image, the decoder first identifies the
|
For the current position (x, y) in the image, the decoder first identifies the
|
||||||
corresponding Huffman code group (as explained in the last section). Given the
|
corresponding prefix code group (as explained in the last section). Given the
|
||||||
Huffman code group, the pixel is read and decoded as follows:
|
prefix code group, the pixel is read and decoded as follows:
|
||||||
|
|
||||||
Read next symbol S from the bitstream using Huffman code #1. \[See
|
Read next symbol S from the bitstream using prefix code #1. Note that S is any
|
||||||
[next section](#decoding-the-code-lengths) for details on decoding the Huffman
|
integer in the range `0` to
|
||||||
code lengths\]. Note that S is any integer in the range `0` to
|
`(256 + 24 + ` [`color_cache_size`](#color-cache-code)` - 1)`.
|
||||||
`(256 + 24 + ` [`color_cache_size`](#color-cache-code)`- 1)`.
|
|
||||||
|
|
||||||
The interpretation of S depends on its value:
|
The interpretation of S depends on its value:
|
||||||
|
|
||||||
1. if S < 256
|
1. if S < 256
|
||||||
1. Use S as the green component
|
1. Use S as the green component.
|
||||||
1. Read red from the bitstream using Huffman code #2
|
1. Read red from the bitstream using prefix code #2.
|
||||||
1. Read blue from the bitstream using Huffman code #3
|
1. Read blue from the bitstream using prefix code #3.
|
||||||
1. Read alpha from the bitstream using Huffman code #4
|
1. Read alpha from the bitstream using prefix code #4.
|
||||||
1. if S < 256 + 24
|
1. if S >= 256 && S < 256 + 24
|
||||||
1. Use S - 256 as a length prefix code
|
1. Use S - 256 as a length prefix code.
|
||||||
1. Read extra bits for length from the bitstream
|
1. Read extra bits for length from the bitstream.
|
||||||
1. Determine backward-reference length L from length prefix code and the
|
1. Determine backward-reference length L from length prefix code and the
|
||||||
extra bits read.
|
extra bits read.
|
||||||
1. Read distance prefix code from the bitstream using Huffman code #5
|
1. Read distance prefix code from the bitstream using prefix code #5.
|
||||||
1. Read extra bits for distance from the bitstream
|
1. Read extra bits for distance from the bitstream.
|
||||||
1. Determine backward-reference distance D from distance prefix code and
|
1. Determine backward-reference distance D from distance prefix code and
|
||||||
the extra bits read.
|
the extra bits read.
|
||||||
1. Copy the L pixels (in scan-line order) from the sequence of pixels
|
1. Copy the L pixels (in scan-line order) from the sequence of pixels
|
||||||
@ -947,80 +1071,6 @@ The interpretation of S depends on its value:
|
|||||||
1. Get ARGB color from the color cache at that index.
|
1. Get ARGB color from the color cache at that index.
|
||||||
|
|
||||||
|
|
||||||
**Decoding the Code Lengths:**
|
|
||||||
{:#decoding-the-code-lengths}
|
|
||||||
|
|
||||||
This section describes the details about reading a symbol from the bitstream by
|
|
||||||
decoding the Huffman code length.
|
|
||||||
|
|
||||||
The Huffman 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_.
|
|
||||||
|
|
||||||
**(i) Simple Code Length Code:**
|
|
||||||
|
|
||||||
This variant is used in the special case when only 1 or 2 Huffman code lengths
|
|
||||||
are non-zero, and are in the range of \[0, 255\]. All other Huffman code lengths
|
|
||||||
are implicitly zeros.
|
|
||||||
|
|
||||||
The first bit indicates the number of non-zero code lengths:
|
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
int num_code_lengths = ReadBits(1) + 1;
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The first code length is stored either using a 1-bit code for values of 0 and 1,
|
|
||||||
or using an 8-bit code for values in range \[0, 255\]. The second code length,
|
|
||||||
when present, is coded as an 8-bit code.
|
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
int is_first_8bits = ReadBits(1);
|
|
||||||
code_lengths[0] = ReadBits(1 + 7 * is_first_8bits);
|
|
||||||
if (num_code_lengths == 2) {
|
|
||||||
code_lengths[1] = ReadBits(8);
|
|
||||||
}
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**Note:** Another special case is when _all_ Huffman code lengths are _zeros_
|
|
||||||
(an empty Huffman code). For example, a Huffman code for distance can be empty
|
|
||||||
if there are no backward references. Similarly, Huffman codes for alpha, red,
|
|
||||||
and blue can be empty if all pixels within the same meta Huffman code are
|
|
||||||
produced using the color cache. However, this case doesn't need a special
|
|
||||||
handling, as empty Huffman codes can be coded as those containing a single
|
|
||||||
symbol `0`.
|
|
||||||
|
|
||||||
**(ii) Normal Code Length Code:**
|
|
||||||
|
|
||||||
The code lengths of a Huffman code are read as follows: `num_code_lengths`
|
|
||||||
specifies the number of code lengths; the rest of the 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_lengths[kCodeLengthCodes] = { 0 }; // All zeros.
|
|
||||||
int num_code_lengths = 4 + ReadBits(4);
|
|
||||||
for (i = 0; i < num_code_lengths; ++i) {
|
|
||||||
code_lengths[kCodeLengthCodeOrder[i]] = ReadBits(3);
|
|
||||||
}
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* Code length 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.
|
|
||||||
|
|
||||||
|
|
||||||
6 Overall Structure of the Format
|
6 Overall Structure of the Format
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
@ -1056,23 +1106,26 @@ of pixels (xsize * ysize).
|
|||||||
|
|
||||||
#### Structure of the Image Data
|
#### Structure of the Image Data
|
||||||
|
|
||||||
|
\[AMENDED2\]
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
<spatially-coded image> ::= <meta huffman><entropy-coded image>
|
<spatially-coded image> ::= <color cache info><meta prefix><data>
|
||||||
<entropy-coded image> ::= <color cache info><huffman codes><lz77-coded image>
|
<entropy-coded image> ::= <color cache info><data>
|
||||||
<meta huffman> ::= 1-bit value 0 |
|
|
||||||
(1-bit value 1; <entropy image>)
|
|
||||||
<entropy image> ::= 3-bit subsample value; <entropy-coded image>
|
|
||||||
<color cache info> ::= 1 bit value 0 |
|
<color cache info> ::= 1 bit value 0 |
|
||||||
(1-bit value 1; 4-bit value for color cache size)
|
(1-bit value 1; 4-bit value for color cache size)
|
||||||
<huffman codes> ::= <huffman code group> | <huffman code group><huffman codes>
|
<meta prefix> ::= 1-bit value 0 |
|
||||||
<huffman code group> ::= <huffman code><huffman code><huffman code>
|
(1-bit value 1; <entropy image>)
|
||||||
<huffman code><huffman code>
|
<data> ::= <prefix codes><lz77-coded image>
|
||||||
See "Interpretation of Meta Huffman codes" to
|
<entropy image> ::= 3-bit subsample value; <entropy-coded image>
|
||||||
understand what each of these five Huffman codes are
|
<prefix codes> ::= <prefix code group> | <prefix code group><prefix codes>
|
||||||
for.
|
<prefix code group> ::= <prefix code><prefix code><prefix code>
|
||||||
<huffman code> ::= <simple huffman code> | <normal huffman code>
|
<prefix code><prefix code>
|
||||||
<simple huffman code> ::= see "Simple code length code" for details
|
See "Interpretation of Meta Prefix Codes" to
|
||||||
<normal huffman code> ::= <code length code>; encoded code lengths
|
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"
|
<code length code> ::= see section "Normal code length code"
|
||||||
<lz77-coded image> ::= ((<argb-pixel> | <lz77-copy> | <color-cache-code>)
|
<lz77-coded image> ::= ((<argb-pixel> | <lz77-copy> | <color-cache-code>)
|
||||||
<lz77-coded image>) | ""
|
<lz77-coded image>) | ""
|
||||||
@ -1082,9 +1135,8 @@ A possible example sequence:
|
|||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
<RIFF header><image size>1-bit value 1<subtract-green-tx>
|
<RIFF header><image size>1-bit value 1<subtract-green-tx>
|
||||||
1-bit value 1<predictor-tx>1-bit value 0<meta huffman>
|
1-bit value 1<predictor-tx>1-bit value 0<color cache info>1-bit value 0
|
||||||
<color cache info><huffman codes>
|
<prefix codes><lz77-coded image>
|
||||||
<lz77-coded image>
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[canonical_huff]: http://en.wikipedia.org/wiki/Canonical_Huffman_code
|
[canonical_huff]: https://en.wikipedia.org/wiki/Canonical_Huffman_code
|
||||||
|
@ -241,7 +241,7 @@ static int ReadAnimatedWebP(const char filename[],
|
|||||||
image->bgcolor = anim_info.bgcolor;
|
image->bgcolor = anim_info.bgcolor;
|
||||||
|
|
||||||
// Allocate frames.
|
// Allocate frames.
|
||||||
if (!AllocateFrames(image, anim_info.frame_count)) return 0;
|
if (!AllocateFrames(image, anim_info.frame_count)) goto End;
|
||||||
|
|
||||||
// Decode frames.
|
// Decode frames.
|
||||||
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
||||||
@ -558,7 +558,10 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Allocate frames.
|
// Allocate frames.
|
||||||
AllocateFrames(image, frame_count);
|
if (!AllocateFrames(image, frame_count)) {
|
||||||
|
DGifCloseFile(gif, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
canvas_width = image->canvas_width;
|
canvas_width = image->canvas_width;
|
||||||
canvas_height = image->canvas_height;
|
canvas_height = image->canvas_height;
|
||||||
|
@ -571,7 +571,7 @@ static void HelpLong(void) {
|
|||||||
printf(" -qrange <min> <max> .... specifies the permissible quality range\n"
|
printf(" -qrange <min> <max> .... specifies the permissible quality range\n"
|
||||||
" (default: 0 100)\n");
|
" (default: 0 100)\n");
|
||||||
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\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(" -resize <w> <h> ........ resize picture (*after* any cropping)\n");
|
||||||
printf(" -mt .................... use multi-threading if available\n");
|
printf(" -mt .................... use multi-threading if available\n");
|
||||||
printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
|
printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
|
||||||
printf(" -map <int> ............. print map of extra info\n");
|
printf(" -map <int> ............. print map of extra info\n");
|
||||||
@ -620,6 +620,7 @@ static void HelpLong(void) {
|
|||||||
printf(" -af .................... auto-adjust filter strength\n");
|
printf(" -af .................... auto-adjust filter strength\n");
|
||||||
printf(" -pre <int> ............. pre-processing filter\n");
|
printf(" -pre <int> ............. pre-processing filter\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
printf("Supported input formats:\n %s\n", WebPGetEnabledInputFileFormats());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -96,7 +96,7 @@ static void Help(void) {
|
|||||||
" -alpha_dither use alpha-plane dithering if needed\n"
|
" -alpha_dither use alpha-plane dithering if needed\n"
|
||||||
" -mt .......... use multi-threading\n"
|
" -mt .......... use multi-threading\n"
|
||||||
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
|
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
|
||||||
" -resize <w> <h> ......... scale the output (*after* any cropping)\n"
|
" -resize <w> <h> ......... resize output (*after* any cropping)\n"
|
||||||
" -flip ........ flip the output vertically\n"
|
" -flip ........ flip the output vertically\n"
|
||||||
" -alpha ....... only save the alpha plane\n"
|
" -alpha ....... only save the alpha plane\n"
|
||||||
" -incremental . use incremental decoding (useful for tests)\n"
|
" -incremental . use incremental decoding (useful for tests)\n"
|
||||||
|
@ -103,7 +103,10 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[],
|
|||||||
}
|
}
|
||||||
args->own_argv_ = 1;
|
args->own_argv_ = 1;
|
||||||
args->argv_ = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_));
|
args->argv_ = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_));
|
||||||
if (args->argv_ == NULL) return 0;
|
if (args->argv_ == NULL) {
|
||||||
|
ExUtilDeleteCommandLineArguments(args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
argc = 0;
|
argc = 0;
|
||||||
for (cur = strtok((char*)args->argv_data_.bytes, sep);
|
for (cur = strtok((char*)args->argv_data_.bytes, sep);
|
||||||
@ -111,6 +114,7 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[],
|
|||||||
cur = strtok(NULL, sep)) {
|
cur = strtok(NULL, sep)) {
|
||||||
if (argc == MAX_ARGC) {
|
if (argc == MAX_ARGC) {
|
||||||
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC);
|
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC);
|
||||||
|
ExUtilDeleteCommandLineArguments(args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
assert(strlen(cur) != 0);
|
assert(strlen(cur) != 0);
|
||||||
|
@ -314,8 +314,11 @@ int main(int argc, const char* argv[]) {
|
|||||||
frame.use_argb = 1;
|
frame.use_argb = 1;
|
||||||
if (!WebPPictureAlloc(&frame)) goto End;
|
if (!WebPPictureAlloc(&frame)) goto End;
|
||||||
GIFClearPic(&frame, NULL);
|
GIFClearPic(&frame, NULL);
|
||||||
WebPPictureCopy(&frame, &curr_canvas);
|
if (!(WebPPictureCopy(&frame, &curr_canvas) &&
|
||||||
WebPPictureCopy(&frame, &prev_canvas);
|
WebPPictureCopy(&frame, &prev_canvas))) {
|
||||||
|
fprintf(stderr, "Error allocating canvas.\n");
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
|
|
||||||
// Background color.
|
// Background color.
|
||||||
GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
|
GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
|
||||||
@ -465,8 +468,10 @@ int main(int argc, const char* argv[]) {
|
|||||||
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
|
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
// If there's only one frame, we don't need to handle loop count.
|
||||||
if (!loop_compatibility) {
|
if (frame_number == 1) {
|
||||||
|
loop_count = 0;
|
||||||
|
} else if (!loop_compatibility) {
|
||||||
if (!stored_loop_count) {
|
if (!stored_loop_count) {
|
||||||
// if no loop-count element is seen, the default is '1' (loop-once)
|
// 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
|
// and we need to signal it explicitly in WebP. Note however that
|
||||||
|
@ -35,8 +35,7 @@
|
|||||||
|
|
||||||
static void Help(void) {
|
static void Help(void) {
|
||||||
printf("Usage:\n\n");
|
printf("Usage:\n\n");
|
||||||
printf(" img2webp [file-level options] [image files...] "
|
printf(" img2webp [file_options] [[frame_options] frame_file]...\n");
|
||||||
"[per-frame options...]\n");
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
printf("File-level options (only used at the start of compression):\n");
|
printf("File-level options (only used at the start of compression):\n");
|
||||||
@ -66,6 +65,8 @@ static void Help(void) {
|
|||||||
"arguments will be\n");
|
"arguments will be\n");
|
||||||
printf("tokenized from this file. The file name must not start with "
|
printf("tokenized from this file. The file name must not start with "
|
||||||
"the character '-'.\n");
|
"the character '-'.\n");
|
||||||
|
printf("\nSupported input formats:\n %s\n",
|
||||||
|
WebPGetEnabledInputFileFormats());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -187,7 +188,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
verbose = 1;
|
verbose = 1;
|
||||||
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
goto End;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-version")) {
|
} else if (!strcmp(argv[c], "-version")) {
|
||||||
const int enc_version = WebPGetEncoderVersion();
|
const int enc_version = WebPGetEncoderVersion();
|
||||||
const int mux_version = WebPGetMuxVersion();
|
const int mux_version = WebPGetMuxVersion();
|
||||||
|
@ -16,11 +16,15 @@
|
|||||||
#ifndef WEBP_EXAMPLES_UNICODE_H_
|
#ifndef WEBP_EXAMPLES_UNICODE_H_
|
||||||
#define WEBP_EXAMPLES_UNICODE_H_
|
#define WEBP_EXAMPLES_UNICODE_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_UNICODE)
|
#if defined(_WIN32) && defined(_UNICODE)
|
||||||
|
|
||||||
// wchar_t is used instead of TCHAR because we only perform additional work when
|
// 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.
|
// Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t.
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
@ -55,8 +59,16 @@
|
|||||||
|
|
||||||
#define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT))
|
#define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT))
|
||||||
|
|
||||||
#define WPRINTF(STR, ...) wprintf(TO_W_CHAR(STR), __VA_ARGS__)
|
#define WFPRINTF(STREAM, STR, ...) \
|
||||||
#define WFPRINTF(STDERR, STR, ...) fwprintf(STDERR, TO_W_CHAR(STR), __VA_ARGS__)
|
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 WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME)
|
||||||
#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
|
#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
|
||||||
@ -65,6 +77,8 @@
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// Unicode file paths work as is on Unix platforms, and no extra work is done on
|
// Unicode file paths work as is on Unix platforms, and no extra work is done on
|
||||||
// Windows either if Unicode is disabled.
|
// Windows either if Unicode is disabled.
|
||||||
|
|
||||||
@ -83,7 +97,7 @@
|
|||||||
#define WFOPEN(ARG, OPT) fopen(ARG, OPT)
|
#define WFOPEN(ARG, OPT) fopen(ARG, OPT)
|
||||||
|
|
||||||
#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__)
|
#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__)
|
||||||
#define WFPRINTF(STDERR, STR, ...) fprintf(STDERR, STR, __VA_ARGS__)
|
#define WFPRINTF(STREAM, STR, ...) fprintf(STREAM, STR, __VA_ARGS__)
|
||||||
|
|
||||||
#define WSTRLEN(FILENAME) strlen(FILENAME)
|
#define WSTRLEN(FILENAME) strlen(FILENAME)
|
||||||
#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR)
|
#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR)
|
||||||
|
@ -45,18 +45,19 @@ static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_UNICODE)
|
#if defined(_WIN32) && defined(_UNICODE)
|
||||||
|
{
|
||||||
int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY);
|
int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY);
|
||||||
if (file_handle == -1) {
|
if (file_handle == -1) {
|
||||||
if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED;
|
if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LOCAL_GIF_PREREQ(5, 0)
|
#if LOCAL_GIF_PREREQ(5, 0)
|
||||||
return DGifOpenFileHandle(file_handle, error);
|
return DGifOpenFileHandle(file_handle, error);
|
||||||
#else
|
#else
|
||||||
return DGifOpenFileHandle(file_handle);
|
return DGifOpenFileHandle(file_handle);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -292,6 +292,19 @@ static void PrintString(const char* const text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
static float GetColorf(uint32_t color, int shift) {
|
||||||
return ((color >> shift) & 0xff) / 255.f;
|
return ((color >> shift) & 0xff) / 255.f;
|
||||||
}
|
}
|
||||||
@ -396,7 +409,7 @@ static void HandleDisplay(void) {
|
|||||||
|
|
||||||
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
||||||
glRasterPos2f(-0.95f, 0.90f);
|
glRasterPos2f(-0.95f, 0.90f);
|
||||||
PrintString(kParams.file_name);
|
PrintStringW(kParams.file_name);
|
||||||
|
|
||||||
snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height);
|
snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height);
|
||||||
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
if (webp_info->show_diagnosis_) { \
|
if (webp_info->show_diagnosis_) { \
|
||||||
fprintf(stderr, "Warning: %s\n", MESSAGE); \
|
fprintf(stderr, "Warning: %s\n", MESSAGE); \
|
||||||
} \
|
} \
|
||||||
|
++webp_info->num_warnings_; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static const char* const kFormats[3] = {
|
static const char* const kFormats[3] = {
|
||||||
@ -116,6 +117,7 @@ typedef struct WebPInfo {
|
|||||||
int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_;
|
int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_;
|
||||||
// Print output control.
|
// Print output control.
|
||||||
int quiet_, show_diagnosis_, show_summary_;
|
int quiet_, show_diagnosis_, show_summary_;
|
||||||
|
int num_warnings_;
|
||||||
int parse_bitstream_;
|
int parse_bitstream_;
|
||||||
} WebPInfo;
|
} WebPInfo;
|
||||||
|
|
||||||
@ -123,16 +125,16 @@ static void WebPInfoInit(WebPInfo* const webp_info) {
|
|||||||
memset(webp_info, 0, sizeof(*webp_info));
|
memset(webp_info, 0, sizeof(*webp_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char kWebPChunkTags[CHUNK_TYPES][4] = {
|
static const uint32_t kWebPChunkTags[CHUNK_TYPES] = {
|
||||||
{ 'V', 'P', '8', ' ' },
|
MKFOURCC('V', 'P', '8', ' '),
|
||||||
{ 'V', 'P', '8', 'L' },
|
MKFOURCC('V', 'P', '8', 'L'),
|
||||||
{ 'V', 'P', '8', 'X' },
|
MKFOURCC('V', 'P', '8', 'X'),
|
||||||
{ 'A', 'L', 'P', 'H' },
|
MKFOURCC('A', 'L', 'P', 'H'),
|
||||||
{ 'A', 'N', 'I', 'M' },
|
MKFOURCC('A', 'N', 'I', 'M'),
|
||||||
{ 'A', 'N', 'M', 'F' },
|
MKFOURCC('A', 'N', 'M', 'F'),
|
||||||
{ 'I', 'C', 'C', 'P' },
|
MKFOURCC('I', 'C', 'C', 'P'),
|
||||||
{ 'E', 'X', 'I', 'F' },
|
MKFOURCC('E', 'X', 'I', 'F'),
|
||||||
{ 'X', 'M', 'P', ' ' },
|
MKFOURCC('X', 'M', 'P', ' '),
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -580,7 +582,7 @@ static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Chunk parsing.
|
// Chunk parsing.
|
||||||
|
|
||||||
static WebPInfoStatus ParseRIFFHeader(const WebPInfo* const webp_info,
|
static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info,
|
||||||
MemBuffer* const mem) {
|
MemBuffer* const mem) {
|
||||||
const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
|
const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
|
||||||
size_t riff_size;
|
size_t riff_size;
|
||||||
@ -642,7 +644,7 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
|
|||||||
return WEBP_INFO_TRUNCATED_DATA;
|
return WEBP_INFO_TRUNCATED_DATA;
|
||||||
}
|
}
|
||||||
for (i = 0; i < CHUNK_TYPES; ++i) {
|
for (i = 0; i < CHUNK_TYPES; ++i) {
|
||||||
if (!memcmp(kWebPChunkTags[i], &fourcc, TAG_SIZE)) break;
|
if (kWebPChunkTags[i] == fourcc) break;
|
||||||
}
|
}
|
||||||
chunk_data->offset_ = chunk_start_offset;
|
chunk_data->offset_ = chunk_start_offset;
|
||||||
chunk_data->size_ = chunk_size;
|
chunk_data->size_ = chunk_size;
|
||||||
@ -937,7 +939,13 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
|
|||||||
LOG_WARN(error_message);
|
LOG_WARN(error_message);
|
||||||
} else {
|
} else {
|
||||||
if (!webp_info->quiet_) {
|
if (!webp_info->quiet_) {
|
||||||
const char* tag = kWebPChunkTags[chunk_data->id_];
|
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",
|
printf("Chunk %c%c%c%c at offset %6d, length %6d\n",
|
||||||
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_,
|
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_,
|
||||||
(int)chunk_data->size_);
|
(int)chunk_data->size_);
|
||||||
@ -988,7 +996,7 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WebPInfoStatus Validate(const WebPInfo* const webp_info) {
|
static WebPInfoStatus Validate(WebPInfo* const webp_info) {
|
||||||
if (webp_info->num_frames_ < 1) {
|
if (webp_info->num_frames_ < 1) {
|
||||||
LOG_ERROR("No image/frame detected.");
|
LOG_ERROR("No image/frame detected.");
|
||||||
return WEBP_INFO_MISSING_DATA;
|
return WEBP_INFO_MISSING_DATA;
|
||||||
@ -1093,16 +1101,14 @@ static WebPInfoStatus AnalyzeWebP(WebPInfo* const webp_info,
|
|||||||
} else {
|
} else {
|
||||||
printf("Errors detected.\n");
|
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;
|
return webp_info_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HelpShort(void) {
|
static void Help(void) {
|
||||||
printf("Usage: webpinfo [options] in_files\n"
|
|
||||||
"Try -longhelp for an exhaustive list of options.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HelpLong(void) {
|
|
||||||
printf("Usage: webpinfo [options] in_files\n"
|
printf("Usage: webpinfo [options] in_files\n"
|
||||||
"Note: there could be multiple input files;\n"
|
"Note: there could be multiple input files;\n"
|
||||||
" options must come before input files.\n"
|
" options must come before input files.\n"
|
||||||
@ -1123,17 +1129,15 @@ int main(int argc, const char* argv[]) {
|
|||||||
INIT_WARGV(argc, argv);
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
HelpShort();
|
Help();
|
||||||
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse command-line input.
|
// Parse command-line input.
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help") ||
|
||||||
HelpShort();
|
!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||||
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
Help();
|
||||||
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
|
||||||
HelpLong();
|
|
||||||
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
||||||
} else if (!strcmp(argv[c], "-quiet")) {
|
} else if (!strcmp(argv[c], "-quiet")) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
@ -1154,7 +1158,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (c == argc) {
|
if (c == argc) {
|
||||||
HelpShort();
|
Help();
|
||||||
FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND);
|
FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ typedef enum {
|
|||||||
FEATURE_ANMF,
|
FEATURE_ANMF,
|
||||||
FEATURE_DURATION,
|
FEATURE_DURATION,
|
||||||
FEATURE_LOOP,
|
FEATURE_LOOP,
|
||||||
|
FEATURE_BGCOLOR,
|
||||||
LAST_FEATURE
|
LAST_FEATURE
|
||||||
} FeatureType;
|
} FeatureType;
|
||||||
|
|
||||||
@ -315,11 +316,12 @@ static void PrintHelp(void) {
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("SET_OPTIONS:\n");
|
printf("SET_OPTIONS:\n");
|
||||||
printf(" Set color profile/metadata:\n");
|
printf(" Set color profile/metadata/parameters:\n");
|
||||||
printf(" loop LOOP_COUNT set the loop count\n");
|
printf(" loop LOOP_COUNT set the loop count\n");
|
||||||
printf(" icc file.icc set ICC profile\n");
|
printf(" bgcolor BACKGROUND_COLOR set the animation background color\n");
|
||||||
printf(" exif file.exif set EXIF metadata\n");
|
printf(" icc file.icc set ICC profile\n");
|
||||||
printf(" xmp file.xmp set XMP metadata\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(" where: 'file.icc' contains the ICC profile to be set,\n");
|
||||||
printf(" 'file.exif' contains the EXIF metadata 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(" 'file.xmp' contains the XMP metadata to be set\n");
|
||||||
@ -327,7 +329,7 @@ static void PrintHelp(void) {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
printf("DURATION_OPTIONS:\n");
|
printf("DURATION_OPTIONS:\n");
|
||||||
printf(" Set duration of selected frames:\n");
|
printf(" Set duration of selected frames:\n");
|
||||||
printf(" duration set duration for each frames\n");
|
printf(" duration set duration for all frames\n");
|
||||||
printf(" duration,frame set duration of a particular frame\n");
|
printf(" duration,frame set duration of a particular frame\n");
|
||||||
printf(" duration,start,end set duration of frames in the\n");
|
printf(" duration,start,end set duration of frames in the\n");
|
||||||
printf(" interval [start,end])\n");
|
printf(" interval [start,end])\n");
|
||||||
@ -346,7 +348,7 @@ static void PrintHelp(void) {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
printf("FRAME_OPTIONS(i):\n");
|
printf("FRAME_OPTIONS(i):\n");
|
||||||
printf(" Create animation:\n");
|
printf(" Create animation:\n");
|
||||||
printf(" file_i +di+[xi+yi[+mi[bi]]]\n");
|
printf(" file_i +di[+xi+yi[+mi[bi]]]\n");
|
||||||
printf(" where: 'file_i' is the i'th animation frame (WebP format),\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(" 'di' is the pause duration before next frame,\n");
|
||||||
printf(" 'xi','yi' specify the image offset for this frame,\n");
|
printf(" 'xi','yi' specify the image offset for this frame,\n");
|
||||||
@ -458,7 +460,8 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
|||||||
if (err == WEBP_MUX_OK && metadata.size > 0) {
|
if (err == WEBP_MUX_OK && metadata.size > 0) {
|
||||||
err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
|
err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
|
||||||
if (err != WEBP_MUX_OK) {
|
if (err != WEBP_MUX_OK) {
|
||||||
ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
|
ERROR_GOTO1("Error transferring metadata in DuplicateMuxHeader().",
|
||||||
|
End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,11 +475,11 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||||
int dispose_method, dummy;
|
int dispose_method, unused;
|
||||||
char plus_minus, blend_method;
|
char plus_minus, blend_method;
|
||||||
const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
|
const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
|
||||||
&info->x_offset, &info->y_offset, &dispose_method,
|
&info->x_offset, &info->y_offset, &dispose_method,
|
||||||
&plus_minus, &blend_method, &dummy);
|
&plus_minus, &blend_method, &unused);
|
||||||
switch (num_args) {
|
switch (num_args) {
|
||||||
case 1:
|
case 1:
|
||||||
info->x_offset = info->y_offset = 0; // fall through
|
info->x_offset = info->y_offset = 0; // fall through
|
||||||
@ -495,7 +498,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
|||||||
|
|
||||||
WarnAboutOddOffset(info);
|
WarnAboutOddOffset(info);
|
||||||
|
|
||||||
// Note: The sanity of the following conversion is checked by
|
// Note: The validity of the following conversion is checked by
|
||||||
// WebPMuxPushFrame().
|
// WebPMuxPushFrame().
|
||||||
info->dispose_method = (WebPMuxAnimDispose)dispose_method;
|
info->dispose_method = (WebPMuxAnimDispose)dispose_method;
|
||||||
|
|
||||||
@ -682,7 +685,7 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
|||||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||||
}
|
}
|
||||||
arg->subtype_ = SUBTYPE_ANMF;
|
arg->subtype_ = SUBTYPE_ANMF;
|
||||||
arg->filename_ = argv[i + 1];
|
arg->filename_ = wargv[i + 1];
|
||||||
arg->params_ = argv[i + 2];
|
arg->params_ = argv[i + 2];
|
||||||
++feature_arg_index;
|
++feature_arg_index;
|
||||||
i += 3;
|
i += 3;
|
||||||
@ -778,6 +781,13 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
|||||||
arg->params_ = argv[i + 1];
|
arg->params_ = argv[i + 1];
|
||||||
++feature_arg_index;
|
++feature_arg_index;
|
||||||
i += 2;
|
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.
|
} else { // Assume input file.
|
||||||
if (config->input_ == NULL) {
|
if (config->input_ == NULL) {
|
||||||
config->input_ = wargv[i];
|
config->input_ = wargv[i];
|
||||||
@ -1053,6 +1063,30 @@ static int Process(const Config* config) {
|
|||||||
}
|
}
|
||||||
break;
|
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: {
|
default: {
|
||||||
ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2);
|
ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2);
|
||||||
break;
|
break;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#define XTRA_MAJ_VERSION 1
|
#define XTRA_MAJ_VERSION 1
|
||||||
#define XTRA_MIN_VERSION 2
|
#define XTRA_MIN_VERSION 2
|
||||||
#define XTRA_REV_VERSION 0
|
#define XTRA_REV_VERSION 3
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -223,7 +223,8 @@ static void Help(void) {
|
|||||||
" -o <file> . save the diff map as a WebP lossless file\n"
|
" -o <file> . save the diff map as a WebP lossless file\n"
|
||||||
" -scale .... scale the difference map to fit [0..255] range\n"
|
" -scale .... scale the difference map to fit [0..255] range\n"
|
||||||
" -gray ..... use grayscale for difference map (-scale)\n"
|
" -gray ..... use grayscale for difference map (-scale)\n"
|
||||||
" Also handles PNG, JPG and TIFF files, in addition to WebP.\n");
|
"\nSupported input formats:\n %s\n",
|
||||||
|
WebPGetEnabledInputFileFormats());
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
@ -11,6 +11,24 @@
|
|||||||
|
|
||||||
#include "./image_dec.h"
|
#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[]) {
|
static WEBP_INLINE uint32_t GetBE32(const uint8_t buf[]) {
|
||||||
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@ typedef enum {
|
|||||||
WEBP_UNSUPPORTED_FORMAT
|
WEBP_UNSUPPORTED_FORMAT
|
||||||
} WebPInputFileFormat;
|
} 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.
|
// Try to infer the image format. 'data_size' should be larger than 12.
|
||||||
// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely.
|
// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely.
|
||||||
WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
|
WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
|
||||||
|
@ -155,8 +155,8 @@ int WebPWritePNG(const char* out_file_name, int use_stdout,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
|
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
|
||||||
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
|
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
|
||||||
(void)dummy; // remove variable-unused warning
|
(void)unused; // remove variable-unused warning
|
||||||
longjmp(png_jmpbuf(png), 1);
|
longjmp(png_jmpbuf(png), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// BMP
|
// BMP (see https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage)
|
||||||
|
|
||||||
static void PutLE16(uint8_t* const dst, uint32_t value) {
|
static void PutLE16(uint8_t* const dst, uint32_t value) {
|
||||||
dst[0] = (value >> 0) & 0xff;
|
dst[0] = (value >> 0) & 0xff;
|
||||||
@ -293,8 +293,11 @@ static void PutLE32(uint8_t* const dst, uint32_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define BMP_HEADER_SIZE 54
|
#define BMP_HEADER_SIZE 54
|
||||||
|
#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info
|
||||||
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
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 width = buffer->width;
|
||||||
const uint32_t height = buffer->height;
|
const uint32_t height = buffer->height;
|
||||||
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
||||||
@ -303,8 +306,9 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
|||||||
uint32_t y;
|
uint32_t y;
|
||||||
const uint32_t line_size = bytes_per_px * width;
|
const uint32_t line_size = bytes_per_px * width;
|
||||||
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
|
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
|
||||||
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
|
const uint32_t image_size = bmp_stride * height;
|
||||||
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
|
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;
|
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||||
|
|
||||||
@ -312,30 +316,37 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
|||||||
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
|
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
|
||||||
PutLE32(bmp_header + 2, total_size); // size including header
|
PutLE32(bmp_header + 2, total_size); // size including header
|
||||||
PutLE32(bmp_header + 6, 0); // reserved
|
PutLE32(bmp_header + 6, 0); // reserved
|
||||||
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
|
PutLE32(bmp_header + 10, header_size); // offset to pixel array
|
||||||
// bitmap info header
|
// bitmap info header
|
||||||
PutLE32(bmp_header + 14, 40); // DIB header size
|
PutLE32(bmp_header + 14, header_size - 14); // DIB header size
|
||||||
PutLE32(bmp_header + 18, width); // dimensions
|
PutLE32(bmp_header + 18, width); // dimensions
|
||||||
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
|
PutLE32(bmp_header + 22, height); // no vertical flip
|
||||||
PutLE16(bmp_header + 26, 1); // number of planes
|
PutLE16(bmp_header + 26, 1); // number of planes
|
||||||
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
||||||
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
|
PutLE32(bmp_header + 30, has_alpha ? 3 : 0); // BI_BITFIELDS or BI_RGB
|
||||||
PutLE32(bmp_header + 34, 0); // image size (dummy)
|
PutLE32(bmp_header + 34, image_size);
|
||||||
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
||||||
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
||||||
PutLE32(bmp_header + 46, 0); // number of palette colors
|
PutLE32(bmp_header + 46, 0); // number of palette colors
|
||||||
PutLE32(bmp_header + 50, 0); // important color count
|
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
|
// TODO(skal): color profile
|
||||||
|
|
||||||
// write header
|
// write header
|
||||||
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
|
if (fwrite(bmp_header, header_size, 1, fout) != 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write pixel array
|
// write pixel array, bottom to top
|
||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
if (fwrite(rgba, line_size, 1, fout) != 1) {
|
const uint8_t* const src = &rgba[(uint64_t)(height - 1 - y) * stride];
|
||||||
|
if (fwrite(src, line_size, 1, fout) != 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// write padding zeroes
|
// write padding zeroes
|
||||||
@ -345,11 +356,11 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rgba += stride;
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#undef BMP_HEADER_SIZE
|
#undef BMP_HEADER_SIZE
|
||||||
|
#undef BMP_HEADER_ALPHA_EXTRA_SIZE
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// TIFF
|
// TIFF
|
||||||
|
@ -79,7 +79,7 @@ int WebPWriteTIFF(FILE* fout, const struct WebPDecBuffer* const buffer);
|
|||||||
int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer);
|
int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
// Save as YUV samples as PGM format (using IMC4 layout).
|
// Save as YUV samples as PGM format (using IMC4 layout).
|
||||||
// See: http://www.fourcc.org/yuv.php#IMC4.
|
// See: https://www.fourcc.org/yuv.php#IMC4.
|
||||||
// (very convenient format for viewing the samples, esp. for odd dimensions).
|
// (very convenient format for viewing the samples, esp. for odd dimensions).
|
||||||
int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||||
|
|
||||||
|
@ -148,9 +148,11 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) {
|
||||||
const uint64_t total_size = nmemb * size;
|
const uint64_t total_size = stride * height;
|
||||||
int ok = (total_size == (size_t)total_size);
|
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)
|
#if defined(WEBP_MAX_IMAGE_SIZE)
|
||||||
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
|
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,8 +54,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Returns 0 in case of overflow of nmemb * size.
|
// Returns 0 in case of overflow, memory over-allocation or excessive dimension.
|
||||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
|
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -274,7 +274,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
ctx.data = data;
|
ctx.data = data;
|
||||||
ctx.data_size = data_size;
|
ctx.data_size = data_size;
|
||||||
|
|
||||||
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
|
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety
|
||||||
dinfo.err = jpeg_std_error(&jerr.pub);
|
dinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
jerr.pub.error_exit = my_error_exit;
|
jerr.pub.error_exit = my_error_exit;
|
||||||
|
|
||||||
@ -336,7 +336,11 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
|||||||
pic->width = width;
|
pic->width = width;
|
||||||
pic->height = height;
|
pic->height = height;
|
||||||
ok = WebPPictureImportRGB(pic, rgb, (int)stride);
|
ok = WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||||
if (!ok) goto Error;
|
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:
|
End:
|
||||||
free(rgb);
|
free(rgb);
|
||||||
|
@ -133,7 +133,7 @@ static const struct {
|
|||||||
MetadataPayload* const payload);
|
MetadataPayload* const payload);
|
||||||
size_t storage_offset;
|
size_t storage_offset;
|
||||||
} kPNGMetadataMap[] = {
|
} kPNGMetadataMap[] = {
|
||||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
|
// https://exiftool.org/TagNames/PNG.html#TextualData
|
||||||
// See also: ExifTool on CPAN.
|
// See also: ExifTool on CPAN.
|
||||||
{ "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) },
|
{ "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) },
|
||||||
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
|
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
|
||||||
@ -259,11 +259,14 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
|||||||
goto End;
|
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
|
// If it looks like the bitstream is going to need more memory than libpng's
|
||||||
// internal limit (default: 8M), try to (reasonably) raise it.
|
// internal limit (default: 8M), try to (reasonably) raise it.
|
||||||
if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
|
if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
|
||||||
png_set_chunk_malloc_max(png, data_size);
|
png_set_chunk_malloc_max(png, data_size);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
info = png_create_info_struct(png);
|
info = png_create_info_struct(png);
|
||||||
if (info == NULL) goto Error;
|
if (info == NULL) goto Error;
|
||||||
|
@ -46,7 +46,7 @@ static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
|
|||||||
(MetadataPayload*)((uint8_t*)metadata +
|
(MetadataPayload*)((uint8_t*)metadata +
|
||||||
kTIFFMetadataMap[i].storage_offset);
|
kTIFFMetadataMap[i].storage_offset);
|
||||||
void* tag_data;
|
void* tag_data;
|
||||||
uint32 tag_data_len;
|
uint32_t tag_data_len;
|
||||||
|
|
||||||
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
|
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
|
||||||
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
|
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
|
||||||
@ -157,6 +157,7 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
MyData my_data = { data, (toff_t)data_size, 0 };
|
MyData my_data = { data, (toff_t)data_size, 0 };
|
||||||
TIFF* tif;
|
TIFF* tif;
|
||||||
uint32_t image_width, image_height, tile_width, tile_height;
|
uint32_t image_width, image_height, tile_width, tile_height;
|
||||||
|
uint64_t stride;
|
||||||
uint16_t samples_per_px = 0;
|
uint16_t samples_per_px = 0;
|
||||||
uint16_t extra_samples = 0;
|
uint16_t extra_samples = 0;
|
||||||
uint16_t* extra_samples_ptr = NULL;
|
uint16_t* extra_samples_ptr = NULL;
|
||||||
@ -187,27 +188,40 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
|
fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (samples_per_px < 3 || samples_per_px > 4) goto End; // not supported
|
if (!(samples_per_px == 1 || samples_per_px == 3 || samples_per_px == 4)) {
|
||||||
|
goto End; // not supported
|
||||||
|
}
|
||||||
|
|
||||||
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) &&
|
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) &&
|
||||||
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) {
|
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) {
|
||||||
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)image_width * image_height,
|
stride = (uint64_t)image_width * sizeof(*raster);
|
||||||
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;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to spec, a tile can be bigger than the image. However it should
|
// 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
|
// be a multiple of 16 and not way too large, so check that it's not more
|
||||||
// twice the image size, for dimensions above some arbitrary minimum 32.
|
// than twice the image size, for dimensions above some arbitrary minimum
|
||||||
if ((TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
|
// 32. We also check that they respect WebP's dimension and memory limit.
|
||||||
tile_width > 32 && tile_width / 2 > image_width) ||
|
// Note that a tile can be 6byte/px in some cases. Here we assume
|
||||||
(TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height) &&
|
// 4byte/px with sizeof(*raster), to be conservative.
|
||||||
tile_height > 32 && tile_height / 2 > image_height)) {
|
if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
|
||||||
fprintf(stderr, "Error! TIFF tile dimensions are too big.\n");
|
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) {
|
||||||
goto End;
|
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,
|
if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
|
||||||
&extra_samples, &extra_samples_ptr)) {
|
&extra_samples, &extra_samples_ptr)) {
|
||||||
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
|
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
|
||||||
@ -215,15 +229,13 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// _Tiffmalloc uses a signed type for size.
|
// _Tiffmalloc uses a signed type for size.
|
||||||
alloc_size =
|
alloc_size = (int64_t)(stride * image_height);
|
||||||
(int64_t)((uint64_t)image_width * image_height * sizeof(*raster));
|
|
||||||
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
|
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
|
||||||
|
|
||||||
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
|
raster = (uint32_t*)_TIFFmalloc((tsize_t)alloc_size);
|
||||||
if (raster != NULL) {
|
if (raster != NULL) {
|
||||||
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
|
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
|
||||||
ORIENTATION_TOPLEFT, 1)) {
|
ORIENTATION_TOPLEFT, 1)) {
|
||||||
const int stride = image_width * sizeof(*raster);
|
|
||||||
pic->width = image_width;
|
pic->width = image_width;
|
||||||
pic->height = image_height;
|
pic->height = image_height;
|
||||||
// TIFF data is ABGR
|
// TIFF data is ABGR
|
||||||
@ -241,8 +253,8 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = keep_alpha
|
ok = keep_alpha
|
||||||
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride)
|
||||||
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride);
|
||||||
}
|
}
|
||||||
_TIFFfree(raster);
|
_TIFFfree(raster);
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,7 +95,7 @@ VP8StatusCode DecodeWebPIncremental(
|
|||||||
{
|
{
|
||||||
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
||||||
if (idec == NULL) {
|
if (idec == NULL) {
|
||||||
fprintf(stderr, "Failed during WebPINewDecoder().\n");
|
fprintf(stderr, "Failed during WebPIDecode().\n");
|
||||||
return VP8_STATUS_OUT_OF_MEMORY;
|
return VP8_STATUS_OUT_OF_MEMORY;
|
||||||
} else {
|
} else {
|
||||||
status = WebPIUpdate(idec, data, data_size);
|
status = WebPIUpdate(idec, data, data_size);
|
||||||
|
@ -134,7 +134,10 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
|
|||||||
IWICColorContext** color_contexts;
|
IWICColorContext** color_contexts;
|
||||||
|
|
||||||
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
|
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
|
||||||
if (FAILED(hr) || count == 0) return hr;
|
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));
|
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
|
||||||
if (color_contexts == NULL) return E_OUTOFMEMORY;
|
if (color_contexts == NULL) return E_OUTOFMEMORY;
|
||||||
@ -270,10 +273,15 @@ int ReadPictureWithWIC(const char* const filename,
|
|||||||
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
|
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
|
||||||
const WICFormatImporter* importer = NULL;
|
const WICFormatImporter* importer = NULL;
|
||||||
GUID src_container_format = GUID_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[] = {
|
static const GUID* kAlphaContainers[] = {
|
||||||
&GUID_ContainerFormatBmp,
|
&GUID_ContainerFormatBmp,
|
||||||
&GUID_ContainerFormatPng,
|
&GUID_ContainerFormatPng,
|
||||||
&GUID_ContainerFormatTiff,
|
&GUID_ContainerFormatTiff,
|
||||||
|
&GUID_ContainerFormatWebp_,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
int has_alpha = 0;
|
int has_alpha = 0;
|
||||||
|
106
infra/common.sh
Normal file
106
infra/common.sh
Normal file
@ -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}" ]]
|
||||||
|
}
|
401
infra/compile.sh
Executable file
401
infra/compile.sh
Executable file
@ -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
|
224
infra/compile_android.sh
Executable file
224
infra/compile_android.sh
Executable file
@ -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
|
75
infra/compile_js.sh
Executable file
75
infra/compile_js.sh
Executable file
@ -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
|
98
infra/run_static_analysis.sh
Executable file
98
infra/run_static_analysis.sh
Executable file
@ -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
|
12
iosbuild.sh
12
iosbuild.sh
@ -9,7 +9,7 @@
|
|||||||
# (the previous build will be erased if it exists).
|
# (the previous build will be erased if it exists).
|
||||||
#
|
#
|
||||||
# This script is inspired by the build script written by Carson McDonald.
|
# This script is inspired by the build script written by Carson McDonald.
|
||||||
# (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
|
# (https://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ if [[ ! -e ${SRCDIR}/configure ]]; then
|
|||||||
Error creating configure script!
|
Error creating configure script!
|
||||||
This script requires the autoconf/automake and libtool to build. MacPorts can
|
This script requires the autoconf/automake and libtool to build. MacPorts can
|
||||||
be used to obtain these:
|
be used to obtain these:
|
||||||
http://www.macports.org/install.php
|
https://www.macports.org/install.php
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -133,10 +133,9 @@ for PLATFORM in ${PLATFORMS}; do
|
|||||||
CFLAGS="${CFLAGS}"
|
CFLAGS="${CFLAGS}"
|
||||||
set +x
|
set +x
|
||||||
|
|
||||||
# run make only in the src/ directory to create libwebp.a/libwebpdecoder.a
|
# Build only the libraries, skip the examples.
|
||||||
cd src/
|
make V=0 -C sharpyuv
|
||||||
make V=0
|
make V=0 -C src install
|
||||||
make install
|
|
||||||
|
|
||||||
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
|
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
|
||||||
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
|
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
|
||||||
@ -144,7 +143,6 @@ for PLATFORM in ${PLATFORMS}; do
|
|||||||
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
|
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
cd ..
|
|
||||||
|
|
||||||
export PATH=${OLDPATH}
|
export PATH=${OLDPATH}
|
||||||
done
|
done
|
||||||
|
@ -47,7 +47,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# To install libraries on Mac OS X:
|
# To install libraries on Mac OS X:
|
||||||
# 1. Install MacPorts (http://www.macports.org/install.php)
|
# 1. Install MacPorts (https://www.macports.org/install.php)
|
||||||
# 2. Run "sudo port install jpeg"
|
# 2. Run "sudo port install jpeg"
|
||||||
# 3. Run "sudo port install libpng"
|
# 3. Run "sudo port install libpng"
|
||||||
# 4. Run "sudo port install tiff"
|
# 4. Run "sudo port install tiff"
|
||||||
@ -125,6 +125,14 @@ endif
|
|||||||
ANIM_UTIL_OBJS = \
|
ANIM_UTIL_OBJS = \
|
||||||
examples/anim_util.o \
|
examples/anim_util.o \
|
||||||
|
|
||||||
|
SHARPYUV_OBJS = \
|
||||||
|
sharpyuv/sharpyuv.o \
|
||||||
|
sharpyuv/sharpyuv_csp.o \
|
||||||
|
sharpyuv/sharpyuv_dsp.o \
|
||||||
|
sharpyuv/sharpyuv_gamma.o \
|
||||||
|
sharpyuv/sharpyuv_neon.o \
|
||||||
|
sharpyuv/sharpyuv_sse2.o \
|
||||||
|
|
||||||
DEC_OBJS = \
|
DEC_OBJS = \
|
||||||
src/dec/alpha_dec.o \
|
src/dec/alpha_dec.o \
|
||||||
src/dec/buffer_dec.o \
|
src/dec/buffer_dec.o \
|
||||||
@ -166,6 +174,7 @@ DSP_DEC_OBJS = \
|
|||||||
src/dsp/lossless_msa.o \
|
src/dsp/lossless_msa.o \
|
||||||
src/dsp/lossless_neon.o \
|
src/dsp/lossless_neon.o \
|
||||||
src/dsp/lossless_sse2.o \
|
src/dsp/lossless_sse2.o \
|
||||||
|
src/dsp/lossless_sse41.o \
|
||||||
src/dsp/rescaler.o \
|
src/dsp/rescaler.o \
|
||||||
src/dsp/rescaler_mips32.o \
|
src/dsp/rescaler_mips32.o \
|
||||||
src/dsp/rescaler_mips_dsp_r2.o \
|
src/dsp/rescaler_mips_dsp_r2.o \
|
||||||
@ -281,8 +290,8 @@ EXTRA_OBJS = \
|
|||||||
extras/quality_estimate.o \
|
extras/quality_estimate.o \
|
||||||
|
|
||||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
LIBWEBP_OBJS = $(SHARPYUV_OBJS) $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
|
||||||
$(UTILS_ENC_OBJS)
|
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS)
|
||||||
LIBWEBPMUX_OBJS = $(MUX_OBJS)
|
LIBWEBPMUX_OBJS = $(MUX_OBJS)
|
||||||
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
|
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
|
||||||
LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
|
LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
|
||||||
@ -303,6 +312,7 @@ HDRS = \
|
|||||||
src/dec/vp8li_dec.h \
|
src/dec/vp8li_dec.h \
|
||||||
src/dec/webpi_dec.h \
|
src/dec/webpi_dec.h \
|
||||||
src/dsp/common_sse2.h \
|
src/dsp/common_sse2.h \
|
||||||
|
src/dsp/cpu.h \
|
||||||
src/dsp/dsp.h \
|
src/dsp/dsp.h \
|
||||||
src/dsp/lossless.h \
|
src/dsp/lossless.h \
|
||||||
src/dsp/lossless_common.h \
|
src/dsp/lossless_common.h \
|
||||||
@ -488,6 +498,7 @@ clean:
|
|||||||
examples/*.o examples/*~ \
|
examples/*.o examples/*~ \
|
||||||
extras/*.o extras/*~ \
|
extras/*.o extras/*~ \
|
||||||
imageio/*.o imageio/*~ \
|
imageio/*.o imageio/*~ \
|
||||||
|
sharpyuv/*.o sharpyuv/*~ \
|
||||||
src/dec/*.o src/dec/*~ \
|
src/dec/*.o src/dec/*~ \
|
||||||
src/demux/*.o src/demux/*~ \
|
src/demux/*.o src/demux/*~ \
|
||||||
src/dsp/*.o src/dsp/*~ \
|
src/dsp/*.o src/dsp/*~ \
|
||||||
|
20
man/cwebp.1
20
man/cwebp.1
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH CWEBP 1 "November 19, 2020"
|
.TH CWEBP 1 "March 17, 2022"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
cwebp \- compress an image file to a WebP file
|
cwebp \- compress an image file to a WebP file
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -90,15 +90,17 @@ additional encoding possibilities and decide on the quality gain.
|
|||||||
Lower value can result in faster processing time at the expense of
|
Lower value can result in faster processing time at the expense of
|
||||||
larger file size and lower compression quality.
|
larger file size and lower compression quality.
|
||||||
.TP
|
.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.
|
|
||||||
.TP
|
|
||||||
.BI \-crop " x_position y_position width height
|
.BI \-crop " x_position y_position width height
|
||||||
Crop the source to a rectangle with top\-left corner at coordinates
|
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.
|
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
|
||||||
This cropping area must be fully contained within the source rectangle.
|
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
|
.TP
|
||||||
.B \-mt
|
.B \-mt
|
||||||
Use multi\-threading for encoding, if possible.
|
Use multi\-threading for encoding, if possible.
|
||||||
@ -222,7 +224,7 @@ Compute and report average PSNR (Peak\-Signal\-To\-Noise ratio).
|
|||||||
.TP
|
.TP
|
||||||
.B \-print_ssim
|
.B \-print_ssim
|
||||||
Compute and report average SSIM (structural similarity
|
Compute and report average SSIM (structural similarity
|
||||||
metric, see http://en.wikipedia.org/wiki/SSIM for additional details).
|
metric, see https://en.wikipedia.org/wiki/SSIM for additional details).
|
||||||
.TP
|
.TP
|
||||||
.B \-print_lsim
|
.B \-print_lsim
|
||||||
Compute and report local similarity metric (sum of lowest error amongst the
|
Compute and report local similarity metric (sum of lowest error amongst the
|
||||||
@ -298,7 +300,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting\-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
|
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
|
||||||
@ -322,5 +324,5 @@ for the Debian project (and may be used by others).
|
|||||||
.BR dwebp (1),
|
.BR dwebp (1),
|
||||||
.BR gif2webp (1)
|
.BR gif2webp (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH DWEBP 1 "November 19, 2020"
|
.TH DWEBP 1 "November 17, 2021"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dwebp \- decompress a WebP file to an image file
|
dwebp \- decompress a WebP file to an image file
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -113,7 +113,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
dwebp picture.webp \-o output.png
|
dwebp picture.webp \-o output.png
|
||||||
@ -138,7 +138,7 @@ for the Debian project (and may be used by others).
|
|||||||
.BR gif2webp (1),
|
.BR gif2webp (1),
|
||||||
.BR webpmux (1)
|
.BR webpmux (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
.SS Output file format details
|
.SS Output file format details
|
||||||
PAM: http://netpbm.sourceforge.net/doc/pam.html
|
PAM: http://netpbm.sourceforge.net/doc/pam.html
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH GIF2WEBP 1 "May 1, 2020"
|
.TH GIF2WEBP 1 "November 17, 2021"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
gif2webp \- Convert a GIF image to WebP
|
gif2webp \- Convert a GIF image to WebP
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -131,7 +131,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
gif2webp picture.gif \-o picture.webp
|
gif2webp picture.gif \-o picture.webp
|
||||||
@ -160,5 +160,5 @@ Debian project (and may be used by others).
|
|||||||
.BR dwebp (1),
|
.BR dwebp (1),
|
||||||
.BR webpmux (1)
|
.BR webpmux (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH IMG2WEBP 1 "May 1, 2020"
|
.TH IMG2WEBP 1 "January 5, 2022"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
img2webp \- create animated WebP file from a sequence of input images.
|
img2webp \- create animated WebP file from a sequence of input images.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B img2webp
|
.B img2webp
|
||||||
[file_level_options] [files] [per_frame_options...]
|
[file_options] [[frame_options] frame_file]...
|
||||||
.br
|
.br
|
||||||
.B img2webp argument_file_name
|
.B img2webp argument_file_name
|
||||||
.br
|
.br
|
||||||
@ -86,7 +86,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting\-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
|
\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
|
||||||
@ -101,5 +101,5 @@ for the Debian project (and may be used by others).
|
|||||||
.BR webpmux (1),
|
.BR webpmux (1),
|
||||||
.BR gif2webp (1)
|
.BR gif2webp (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH VWEBP 1 "June 5, 2019"
|
.TH VWEBP 1 "November 17, 2021"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
vwebp \- decompress a WebP file and display it in a window
|
vwebp \- decompress a WebP file and display it in a window
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -77,7 +77,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
vwebp picture.webp
|
vwebp picture.webp
|
||||||
@ -97,5 +97,5 @@ This manual page was written for the Debian project (and may be used by others).
|
|||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR dwebp (1)
|
.BR dwebp (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH WEBPINFO 1 "November 24, 2017"
|
.TH WEBPINFO 1 "November 17, 2021"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
webpinfo \- print out the chunk level structure of WebP files
|
webpinfo \- print out the chunk level structure of WebP files
|
||||||
along with basic integrity checks.
|
along with basic integrity checks.
|
||||||
@ -52,7 +52,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting\-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.br
|
.br
|
||||||
@ -76,5 +76,5 @@ for the Debian project (and may be used by others).
|
|||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR webpmux (1)
|
.BR webpmux (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH WEBPMUX 1 "December 12, 2020"
|
.TH WEBPMUX 1 "November 17, 2021"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
webpmux \- create animated WebP files from non\-animated WebP images, extract
|
webpmux \- create animated WebP files from non\-animated WebP images, extract
|
||||||
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
|
||||||
@ -82,6 +82,12 @@ Set loop count on an animated file.
|
|||||||
.P
|
.P
|
||||||
Where: 'loop_count' must be in range [0, 65535].
|
Where: 'loop_count' must be in range [0, 65535].
|
||||||
.TP
|
.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
|
.BI icc " file.icc
|
||||||
Set ICC profile.
|
Set ICC profile.
|
||||||
.P
|
.P
|
||||||
@ -185,7 +191,7 @@ Please report all bugs to the issue tracker:
|
|||||||
https://bugs.chromium.org/p/webp
|
https://bugs.chromium.org/p/webp
|
||||||
.br
|
.br
|
||||||
Patches welcome! See this page to get started:
|
Patches welcome! See this page to get started:
|
||||||
http://www.webmproject.org/code/contribute/submitting\-patches/
|
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.P
|
.P
|
||||||
@ -261,5 +267,5 @@ for the Debian project (and may be used by others).
|
|||||||
.BR dwebp (1),
|
.BR dwebp (1),
|
||||||
.BR gif2webp (1)
|
.BR gif2webp (1)
|
||||||
.br
|
.br
|
||||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||||
information.
|
information.
|
||||||
|
34
sharpyuv/Makefile.am
Normal file
34
sharpyuv/Makefile.am
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
|
||||||
|
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||||
|
noinst_LTLIBRARIES =
|
||||||
|
noinst_LTLIBRARIES += libsharpyuv.la
|
||||||
|
noinst_LTLIBRARIES += libsharpyuv_sse2.la
|
||||||
|
noinst_LTLIBRARIES += libsharpyuv_neon.la
|
||||||
|
|
||||||
|
noinst_HEADERS =
|
||||||
|
noinst_HEADERS += ../src/webp/types.h
|
||||||
|
noinst_HEADERS += ../src/dsp/cpu.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_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 =
|
||||||
|
libsharpyuv_la_LIBADD =
|
||||||
|
libsharpyuv_la_LIBADD += libsharpyuv_sse2.la
|
||||||
|
libsharpyuv_la_LIBADD += libsharpyuv_neon.la
|
||||||
|
|
||||||
|
noinst_PROGRAMS =
|
498
sharpyuv/sharpyuv.c
Normal file
498
sharpyuv/sharpyuv.c
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
// 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 <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "src/webp/types.h"
|
||||||
|
#include "src/dsp/cpu.h"
|
||||||
|
#include "sharpyuv/sharpyuv_dsp.h"
|
||||||
|
#include "sharpyuv/sharpyuv_gamma.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Hidden exported init function.
|
||||||
|
// By default SharpYuvConvert calls it with NULL. If needed, users can declare
|
||||||
|
// it as extern and call it with a VP8CPUInfo function.
|
||||||
|
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;
|
||||||
|
const int initialized =
|
||||||
|
(sharpyuv_last_cpuinfo_used != (VP8CPUInfo)&sharpyuv_last_cpuinfo_used);
|
||||||
|
if (cpu_info_func == NULL && initialized) return;
|
||||||
|
if (sharpyuv_last_cpuinfo_used == cpu_info_func) return;
|
||||||
|
|
||||||
|
SharpYuvInitDsp(cpu_info_func);
|
||||||
|
if (!initialized) {
|
||||||
|
SharpYuvInitGammaTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
sharpyuv_last_cpuinfo_used = cpu_info_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
SharpYuvInit(NULL);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
81
sharpyuv/sharpyuv.h
Normal file
81
sharpyuv/sharpyuv.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SharpYUV API version following the convention from semver.org
|
||||||
|
#define SHARPYUV_VERSION_MAJOR 0
|
||||||
|
#define SHARPYUV_VERSION_MINOR 1
|
||||||
|
#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)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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_
|
110
sharpyuv/sharpyuv_csp.c
Normal file
110
sharpyuv/sharpyuv_csp.c
Normal file
@ -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 <string.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;
|
||||||
|
}
|
59
sharpyuv/sharpyuv_csp.h
Normal file
59
sharpyuv/sharpyuv_csp.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// 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.
|
||||||
|
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.
|
||||||
|
const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
|
||||||
|
SharpYuvMatrixType matrix_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_
|
102
sharpyuv/sharpyuv_dsp.c
Normal file
102
sharpyuv/sharpyuv_dsp.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// 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 "src/dsp/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(VP8CPUInfo cpu_info_func) {
|
||||||
|
(void)cpu_info_func;
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
SharpYuvUpdateY = SharpYuvUpdateY_C;
|
||||||
|
SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
|
||||||
|
SharpYuvFilterRow = SharpYuvFilterRow_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBP_HAVE_SSE2)
|
||||||
|
if (cpu_info_func == NULL || cpu_info_func(kSSE2)) {
|
||||||
|
InitSharpYuvSSE2();
|
||||||
|
}
|
||||||
|
#endif // WEBP_HAVE_SSE2
|
||||||
|
|
||||||
|
#if defined(WEBP_HAVE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE || cpu_info_func == NULL || cpu_info_func(kNEON)) {
|
||||||
|
InitSharpYuvNEON();
|
||||||
|
}
|
||||||
|
#endif // WEBP_HAVE_NEON
|
||||||
|
|
||||||
|
assert(SharpYuvUpdateY != NULL);
|
||||||
|
assert(SharpYuvUpdateRGB != NULL);
|
||||||
|
assert(SharpYuvFilterRow != NULL);
|
||||||
|
}
|
29
sharpyuv/sharpyuv_dsp.h
Normal file
29
sharpyuv/sharpyuv_dsp.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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 <stdint.h>
|
||||||
|
|
||||||
|
#include "src/dsp/cpu.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(VP8CPUInfo cpu_info_func);
|
||||||
|
|
||||||
|
#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
114
sharpyuv/sharpyuv_gamma.c
Normal file
114
sharpyuv/sharpyuv_gamma.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// 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 <stdint.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);
|
||||||
|
}
|
35
sharpyuv/sharpyuv_gamma.h
Normal file
35
sharpyuv/sharpyuv_gamma.h
Normal file
@ -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 <stdint.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_
|
182
sharpyuv/sharpyuv_neon.c
Normal file
182
sharpyuv/sharpyuv_neon.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// 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>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void InitSharpYuvNEON(void);
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
|
||||||
|
SharpYuvUpdateY = SharpYuvUpdateY_NEON;
|
||||||
|
SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON;
|
||||||
|
SharpYuvFilterRow = SharpYuvFilterRow_NEON;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !WEBP_USE_NEON
|
||||||
|
|
||||||
|
void InitSharpYuvNEON(void) {}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_NEON
|
204
sharpyuv/sharpyuv_sse2.c
Normal file
204
sharpyuv/sharpyuv_sse2.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// 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>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void InitSharpYuvSSE2(void);
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
void InitSharpYuvSSE2(void) {}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE2
|
@ -36,7 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
|
|||||||
# other than the ones listed on the command line, i.e., after linking, it will
|
# 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
|
# not have unresolved symbols. Some platforms (Windows among them) require all
|
||||||
# symbols in shared libraries to be resolved at library creation.
|
# symbols in shared libraries to be resolved at library creation.
|
||||||
libwebp_la_LDFLAGS = -no-undefined -version-info 8:1:1
|
libwebp_la_LDFLAGS = -no-undefined -version-info 8:4:1
|
||||||
libwebpincludedir = $(includedir)/webp
|
libwebpincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebp.pc
|
pkgconfig_DATA = libwebp.pc
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
|
|||||||
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
||||||
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
||||||
|
|
||||||
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:1:1
|
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:4:1
|
||||||
pkgconfig_DATA += libwebpdecoder.pc
|
pkgconfig_DATA += libwebpdecoder.pc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
|||||||
assert(dec != NULL && io != NULL);
|
assert(dec != NULL && io != NULL);
|
||||||
|
|
||||||
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
|
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
|
||||||
return NULL; // sanity check.
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dec->is_alpha_decoded_) {
|
if (!dec->is_alpha_decoded_) {
|
||||||
|
@ -102,7 +102,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
|||||||
int stride;
|
int stride;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
|
||||||
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
|
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) {
|
||||||
return VP8_STATUS_INVALID_PARAM;
|
return VP8_STATUS_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
stride = w * kModeBpp[mode];
|
stride = w * kModeBpp[mode];
|
||||||
@ -117,7 +117,6 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
|||||||
}
|
}
|
||||||
total_size = size + 2 * uv_size + a_size;
|
total_size = size + 2 * uv_size + a_size;
|
||||||
|
|
||||||
// Security/sanity checks
|
|
||||||
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
|
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
|
||||||
if (output == NULL) {
|
if (output == NULL) {
|
||||||
return VP8_STATUS_OUT_OF_MEMORY;
|
return VP8_STATUS_OUT_OF_MEMORY;
|
||||||
@ -156,11 +155,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
|
|||||||
}
|
}
|
||||||
if (WebPIsRGBMode(buffer->colorspace)) {
|
if (WebPIsRGBMode(buffer->colorspace)) {
|
||||||
WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
WebPRGBABuffer* const buf = &buffer->u.RGBA;
|
||||||
buf->rgba += (buffer->height - 1) * buf->stride;
|
buf->rgba += (int64_t)(buffer->height - 1) * buf->stride;
|
||||||
buf->stride = -buf->stride;
|
buf->stride = -buf->stride;
|
||||||
} else {
|
} else {
|
||||||
WebPYUVABuffer* const buf = &buffer->u.YUVA;
|
WebPYUVABuffer* const buf = &buffer->u.YUVA;
|
||||||
const int H = buffer->height;
|
const int64_t H = buffer->height;
|
||||||
buf->y += (H - 1) * buf->y_stride;
|
buf->y += (H - 1) * buf->y_stride;
|
||||||
buf->y_stride = -buf->y_stride;
|
buf->y_stride = -buf->y_stride;
|
||||||
buf->u += ((H - 1) >> 1) * buf->u_stride;
|
buf->u += ((H - 1) >> 1) * buf->u_stride;
|
||||||
@ -188,8 +187,7 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
|
|||||||
const int ch = options->crop_height;
|
const int ch = options->crop_height;
|
||||||
const int x = options->crop_left & ~1;
|
const int x = options->crop_left & ~1;
|
||||||
const int y = options->crop_top & ~1;
|
const int y = options->crop_top & ~1;
|
||||||
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
|
if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) {
|
||||||
x + cw > width || y + ch > height) {
|
|
||||||
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
|
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
|
||||||
}
|
}
|
||||||
width = cw;
|
width = cw;
|
||||||
|
@ -705,7 +705,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
|||||||
+ cache_size + alpha_size + WEBP_ALIGN_CST;
|
+ cache_size + alpha_size + WEBP_ALIGN_CST;
|
||||||
uint8_t* mem;
|
uint8_t* mem;
|
||||||
|
|
||||||
if (needed != (size_t)needed) return 0; // check for overflow
|
if (!CheckSizeOverflow(needed)) return 0; // check for overflow
|
||||||
if (needed > dec->mem_size_) {
|
if (needed > dec->mem_size_) {
|
||||||
WebPSafeFree(dec->mem_);
|
WebPSafeFree(dec->mem_);
|
||||||
dec->mem_size_ = 0;
|
dec->mem_size_ = 0;
|
||||||
|
@ -298,46 +298,57 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const int uv_out_height = (out_height + 1) >> 1;
|
const int uv_out_height = (out_height + 1) >> 1;
|
||||||
const int uv_in_width = (io->mb_w + 1) >> 1;
|
const int uv_in_width = (io->mb_w + 1) >> 1;
|
||||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||||
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
|
// scratch memory for luma rescaler
|
||||||
|
const size_t work_size = 2 * (size_t)out_width;
|
||||||
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
||||||
size_t tmp_size, rescaler_size;
|
uint64_t total_size;
|
||||||
|
size_t rescaler_size;
|
||||||
rescaler_t* work;
|
rescaler_t* work;
|
||||||
WebPRescaler* scalers;
|
WebPRescaler* scalers;
|
||||||
const int num_rescalers = has_alpha ? 4 : 3;
|
const int num_rescalers = has_alpha ? 4 : 3;
|
||||||
|
|
||||||
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
|
total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work);
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
tmp_size += work_size * sizeof(*work);
|
total_size += (uint64_t)work_size * sizeof(*work);
|
||||||
}
|
}
|
||||||
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||||
|
total_size += rescaler_size;
|
||||||
|
if (!CheckSizeOverflow(total_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
|
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
work = (rescaler_t*)p->memory;
|
work = (rescaler_t*)p->memory;
|
||||||
|
|
||||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
|
scalers = (WebPRescaler*)WEBP_ALIGN(
|
||||||
|
(const uint8_t*)work + total_size - rescaler_size);
|
||||||
p->scaler_y = &scalers[0];
|
p->scaler_y = &scalers[0];
|
||||||
p->scaler_u = &scalers[1];
|
p->scaler_u = &scalers[1];
|
||||||
p->scaler_v = &scalers[2];
|
p->scaler_v = &scalers[2];
|
||||||
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||||
|
|
||||||
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||||
buf->y, out_width, out_height, buf->y_stride, 1,
|
buf->y, out_width, out_height, buf->y_stride, 1,
|
||||||
work);
|
work) ||
|
||||||
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||||
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
|
||||||
work + work_size);
|
work + work_size) ||
|
||||||
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||||
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
|
||||||
work + work_size + uv_work_size);
|
work + work_size + uv_work_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
p->emit = EmitRescaledYUV;
|
p->emit = EmitRescaledYUV;
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||||
buf->a, out_width, out_height, buf->a_stride, 1,
|
buf->a, out_width, out_height, buf->a_stride, 1,
|
||||||
work + work_size + 2 * uv_work_size);
|
work + work_size + 2 * uv_work_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
p->emit_alpha = EmitRescaledAlphaYUV;
|
p->emit_alpha = EmitRescaledAlphaYUV;
|
||||||
WebPInitAlphaProcessing();
|
WebPInitAlphaProcessing();
|
||||||
}
|
}
|
||||||
@ -480,51 +491,58 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
|||||||
const int out_height = io->scaled_height;
|
const int out_height = io->scaled_height;
|
||||||
const int uv_in_width = (io->mb_w + 1) >> 1;
|
const int uv_in_width = (io->mb_w + 1) >> 1;
|
||||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||||
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
|
// scratch memory for one rescaler
|
||||||
|
const size_t work_size = 2 * (size_t)out_width;
|
||||||
rescaler_t* work; // rescalers work area
|
rescaler_t* work; // rescalers work area
|
||||||
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
||||||
size_t tmp_size1, tmp_size2, total_size, rescaler_size;
|
uint64_t tmp_size1, tmp_size2, total_size;
|
||||||
|
size_t rescaler_size;
|
||||||
WebPRescaler* scalers;
|
WebPRescaler* scalers;
|
||||||
const int num_rescalers = has_alpha ? 4 : 3;
|
const int num_rescalers = has_alpha ? 4 : 3;
|
||||||
|
|
||||||
tmp_size1 = 3 * work_size;
|
tmp_size1 = (uint64_t)num_rescalers * work_size;
|
||||||
tmp_size2 = 3 * out_width;
|
tmp_size2 = (uint64_t)num_rescalers * out_width;
|
||||||
if (has_alpha) {
|
|
||||||
tmp_size1 += work_size;
|
|
||||||
tmp_size2 += out_width;
|
|
||||||
}
|
|
||||||
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
|
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
|
||||||
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
|
||||||
|
total_size += rescaler_size;
|
||||||
|
if (!CheckSizeOverflow(total_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
|
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||||
if (p->memory == NULL) {
|
if (p->memory == NULL) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
work = (rescaler_t*)p->memory;
|
work = (rescaler_t*)p->memory;
|
||||||
tmp = (uint8_t*)(work + tmp_size1);
|
tmp = (uint8_t*)(work + tmp_size1);
|
||||||
|
|
||||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
|
scalers = (WebPRescaler*)WEBP_ALIGN(
|
||||||
|
(const uint8_t*)work + total_size - rescaler_size);
|
||||||
p->scaler_y = &scalers[0];
|
p->scaler_y = &scalers[0];
|
||||||
p->scaler_u = &scalers[1];
|
p->scaler_u = &scalers[1];
|
||||||
p->scaler_v = &scalers[2];
|
p->scaler_v = &scalers[2];
|
||||||
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
p->scaler_a = has_alpha ? &scalers[3] : NULL;
|
||||||
|
|
||||||
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
|
||||||
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
tmp + 0 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 0 * work_size);
|
work + 0 * work_size) ||
|
||||||
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
!WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
|
||||||
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
tmp + 1 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 1 * work_size);
|
work + 1 * work_size) ||
|
||||||
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
!WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
|
||||||
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
tmp + 2 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 2 * work_size);
|
work + 2 * work_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
p->emit = EmitRescaledRGB;
|
p->emit = EmitRescaledRGB;
|
||||||
WebPInitYUV444Converters();
|
WebPInitYUV444Converters();
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
|
||||||
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
tmp + 3 * out_width, out_width, out_height, 0, 1,
|
||||||
work + 3 * work_size);
|
work + 3 * work_size)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
p->emit_alpha = EmitRescaledAlphaRGB;
|
p->emit_alpha = EmitRescaledAlphaRGB;
|
||||||
if (p->output->colorspace == MODE_RGBA_4444 ||
|
if (p->output->colorspace == MODE_RGBA_4444 ||
|
||||||
p->output->colorspace == MODE_rgbA_4444) {
|
p->output->colorspace == MODE_rgbA_4444) {
|
||||||
|
@ -335,7 +335,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
io->scaled_width = io->width;
|
io->scaled_width = io->width;
|
||||||
io->scaled_height = io->height;
|
io->scaled_height = io->height;
|
||||||
|
|
||||||
io->mb_w = io->width; // sanity check
|
io->mb_w = io->width; // for soundness
|
||||||
io->mb_h = io->height; // ditto
|
io->mb_h = io->height; // ditto
|
||||||
|
|
||||||
VP8ResetProba(&dec->proba_);
|
VP8ResetProba(&dec->proba_);
|
||||||
@ -403,7 +403,7 @@ static const uint8_t kZigzag[16] = {
|
|||||||
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
|
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
|
||||||
};
|
};
|
||||||
|
|
||||||
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
|
// See section 13-2: https://datatracker.ietf.org/doc/html/rfc6386#section-13.2
|
||||||
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
||||||
int v;
|
int v;
|
||||||
if (!VP8GetBit(br, p[3], "coeffs")) {
|
if (!VP8GetBit(br, p[3], "coeffs")) {
|
||||||
|
@ -32,7 +32,7 @@ extern "C" {
|
|||||||
// version numbers
|
// version numbers
|
||||||
#define DEC_MAJ_VERSION 1
|
#define DEC_MAJ_VERSION 1
|
||||||
#define DEC_MIN_VERSION 2
|
#define DEC_MIN_VERSION 2
|
||||||
#define DEC_REV_VERSION 0
|
#define DEC_REV_VERSION 3
|
||||||
|
|
||||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||||
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
||||||
|
@ -84,7 +84,7 @@ static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
|
|||||||
// to 256 (green component values) + 24 (length prefix values)
|
// to 256 (green component values) + 24 (length prefix values)
|
||||||
// + color_cache_size (between 0 and 2048).
|
// + color_cache_size (between 0 and 2048).
|
||||||
// All values computed for 8-bit first level lookup with Mark Adler's tool:
|
// All values computed for 8-bit first level lookup with Mark Adler's tool:
|
||||||
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
|
// https://github.com/madler/zlib/blob/v1.2.5/examples/enough.c
|
||||||
#define FIXED_TABLE_SIZE (630 * 3 + 410)
|
#define FIXED_TABLE_SIZE (630 * 3 + 410)
|
||||||
static const uint16_t kTableSize[12] = {
|
static const uint16_t kTableSize[12] = {
|
||||||
FIXED_TABLE_SIZE + 654,
|
FIXED_TABLE_SIZE + 654,
|
||||||
@ -178,7 +178,7 @@ static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Decodes the next Huffman code from bit-stream.
|
// 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.
|
// to ReadSymbol, in order to pre-fetch enough bits.
|
||||||
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
|
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
|
||||||
VP8LBitReader* const br) {
|
VP8LBitReader* const br) {
|
||||||
@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
|
|||||||
int symbol;
|
int symbol;
|
||||||
int max_symbol;
|
int max_symbol;
|
||||||
int prev_code_len = DEFAULT_CODE_LENGTH;
|
int prev_code_len = DEFAULT_CODE_LENGTH;
|
||||||
HuffmanCode table[1 << LENGTHS_TABLE_BITS];
|
HuffmanTables tables;
|
||||||
|
|
||||||
if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
|
if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
|
||||||
code_length_code_lengths,
|
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
|
||||||
NUM_CODE_LENGTH_CODES)) {
|
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
|
|||||||
int code_len;
|
int code_len;
|
||||||
if (max_symbol-- == 0) break;
|
if (max_symbol-- == 0) break;
|
||||||
VP8LFillBitWindow(br);
|
VP8LFillBitWindow(br);
|
||||||
p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
||||||
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
|
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
|
||||||
code_len = p->value;
|
code_len = p->value;
|
||||||
if (code_len < kCodeLengthLiterals) {
|
if (code_len < kCodeLengthLiterals) {
|
||||||
@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
|
|||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
End:
|
End:
|
||||||
|
VP8LHuffmanTablesDeallocate(&tables);
|
||||||
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
|
|||||||
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
|
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
|
||||||
// tree.
|
// tree.
|
||||||
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
||||||
int* const code_lengths, HuffmanCode* const table) {
|
int* const code_lengths,
|
||||||
|
HuffmanTables* const table) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
VP8LBitReader* const br = &dec->br_;
|
VP8LBitReader* const br = &dec->br_;
|
||||||
@ -321,7 +323,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
|||||||
// The first code is either 1 bit or 8 bit code.
|
// The first code is either 1 bit or 8 bit code.
|
||||||
int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
|
int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
|
||||||
code_lengths[symbol] = 1;
|
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) {
|
if (num_symbols == 2) {
|
||||||
symbol = VP8LReadBits(br, 8);
|
symbol = VP8LReadBits(br, 8);
|
||||||
code_lengths[symbol] = 1;
|
code_lengths[symbol] = 1;
|
||||||
@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
VP8LMetadata* const hdr = &dec->hdr_;
|
VP8LMetadata* const hdr = &dec->hdr_;
|
||||||
uint32_t* huffman_image = NULL;
|
uint32_t* huffman_image = NULL;
|
||||||
HTreeGroup* htree_groups = NULL;
|
HTreeGroup* htree_groups = NULL;
|
||||||
HuffmanCode* huffman_tables = NULL;
|
HuffmanTables* huffman_tables = &hdr->huffman_tables_;
|
||||||
HuffmanCode* huffman_table = NULL;
|
|
||||||
int num_htree_groups = 1;
|
int num_htree_groups = 1;
|
||||||
int num_htree_groups_max = 1;
|
int num_htree_groups_max = 1;
|
||||||
int max_alphabet_size = 0;
|
int max_alphabet_size = 0;
|
||||||
@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
int* mapping = NULL;
|
int* mapping = NULL;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
|
// Check the table has been 0 initialized (through InitMetadata).
|
||||||
|
assert(huffman_tables->root.start == NULL);
|
||||||
|
assert(huffman_tables->curr_segment == NULL);
|
||||||
|
|
||||||
if (allow_recursion && VP8LReadBits(br, 1)) {
|
if (allow_recursion && VP8LReadBits(br, 1)) {
|
||||||
// use meta Huffman codes.
|
// use meta Huffman codes.
|
||||||
const int huffman_precision = VP8LReadBits(br, 3) + 2;
|
const int huffman_precision = VP8LReadBits(br, 3) + 2;
|
||||||
@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
|
|
||||||
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
|
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
|
||||||
sizeof(*code_lengths));
|
sizeof(*code_lengths));
|
||||||
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
|
|
||||||
sizeof(*huffman_tables));
|
|
||||||
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
|
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
|
||||||
|
|
||||||
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
|
if (htree_groups == NULL || code_lengths == NULL ||
|
||||||
|
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
|
||||||
|
huffman_tables)) {
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
huffman_table = huffman_tables;
|
|
||||||
for (i = 0; i < num_htree_groups_max; ++i) {
|
for (i = 0; i < num_htree_groups_max; ++i) {
|
||||||
// If the index "i" is unused in the Huffman image, just make sure the
|
// If the index "i" is unused in the Huffman image, just make sure the
|
||||||
// coefficients are valid but do not store them.
|
// coefficients are valid but do not store them.
|
||||||
@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
int max_bits = 0;
|
int max_bits = 0;
|
||||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||||
int alphabet_size = kAlphabetSize[j];
|
int alphabet_size = kAlphabetSize[j];
|
||||||
htrees[j] = huffman_table;
|
|
||||||
if (j == 0 && color_cache_bits > 0) {
|
if (j == 0 && color_cache_bits > 0) {
|
||||||
alphabet_size += (1 << color_cache_bits);
|
alphabet_size += (1 << color_cache_bits);
|
||||||
}
|
}
|
||||||
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
|
size =
|
||||||
|
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
|
||||||
|
htrees[j] = huffman_tables->curr_segment->curr_table;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||||
is_trivial_literal = (huffman_table->bits == 0);
|
is_trivial_literal = (htrees[j]->bits == 0);
|
||||||
}
|
}
|
||||||
total_size += huffman_table->bits;
|
total_size += htrees[j]->bits;
|
||||||
huffman_table += size;
|
huffman_tables->curr_segment->curr_table += size;
|
||||||
if (j <= ALPHA) {
|
if (j <= ALPHA) {
|
||||||
int local_max_bits = code_lengths[0];
|
int local_max_bits = code_lengths[0];
|
||||||
int k;
|
int k;
|
||||||
@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
hdr->huffman_image_ = huffman_image;
|
hdr->huffman_image_ = huffman_image;
|
||||||
hdr->num_htree_groups_ = num_htree_groups;
|
hdr->num_htree_groups_ = num_htree_groups;
|
||||||
hdr->htree_groups_ = htree_groups;
|
hdr->htree_groups_ = htree_groups;
|
||||||
hdr->huffman_tables_ = huffman_tables;
|
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
WebPSafeFree(code_lengths);
|
WebPSafeFree(code_lengths);
|
||||||
WebPSafeFree(mapping);
|
WebPSafeFree(mapping);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
WebPSafeFree(huffman_image);
|
WebPSafeFree(huffman_image);
|
||||||
WebPSafeFree(huffman_tables);
|
VP8LHuffmanTablesDeallocate(huffman_tables);
|
||||||
VP8LHtreeGroupsFree(htree_groups);
|
VP8LHtreeGroupsFree(htree_groups);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
@ -559,8 +563,11 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
|||||||
memory += work_size * sizeof(*work);
|
memory += work_size * sizeof(*work);
|
||||||
scaled_data = (uint32_t*)memory;
|
scaled_data = (uint32_t*)memory;
|
||||||
|
|
||||||
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
|
if (!WebPRescalerInit(dec->rescaler, in_width, in_height,
|
||||||
out_width, out_height, 0, num_channels, work);
|
(uint8_t*)scaled_data, out_width, out_height,
|
||||||
|
0, num_channels, work)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif // WEBP_REDUCE_SIZE
|
#endif // WEBP_REDUCE_SIZE
|
||||||
@ -574,13 +581,14 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
|||||||
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
|
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
|
||||||
int rgba_stride, uint8_t* const rgba) {
|
int rgba_stride, uint8_t* const rgba) {
|
||||||
uint32_t* const src = (uint32_t*)rescaler->dst;
|
uint32_t* const src = (uint32_t*)rescaler->dst;
|
||||||
|
uint8_t* dst = rgba;
|
||||||
const int dst_width = rescaler->dst_width;
|
const int dst_width = rescaler->dst_width;
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
while (WebPRescalerHasPendingOutput(rescaler)) {
|
while (WebPRescalerHasPendingOutput(rescaler)) {
|
||||||
uint8_t* const dst = rgba + num_lines_out * rgba_stride;
|
|
||||||
WebPRescalerExportRow(rescaler);
|
WebPRescalerExportRow(rescaler);
|
||||||
WebPMultARGBRow(src, dst_width, 1);
|
WebPMultARGBRow(src, dst_width, 1);
|
||||||
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
|
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
|
||||||
|
dst += rgba_stride;
|
||||||
++num_lines_out;
|
++num_lines_out;
|
||||||
}
|
}
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
@ -594,8 +602,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
|
|||||||
int num_lines_in = 0;
|
int num_lines_in = 0;
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
while (num_lines_in < mb_h) {
|
while (num_lines_in < mb_h) {
|
||||||
uint8_t* const row_in = in + num_lines_in * in_stride;
|
uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride;
|
||||||
uint8_t* const row_out = out + num_lines_out * out_stride;
|
uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride;
|
||||||
const int lines_left = mb_h - num_lines_in;
|
const int lines_left = mb_h - num_lines_in;
|
||||||
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
|
||||||
int lines_imported;
|
int lines_imported;
|
||||||
@ -796,7 +804,8 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
|
|||||||
const WebPDecBuffer* const output = dec->output_;
|
const WebPDecBuffer* const output = dec->output_;
|
||||||
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
|
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
|
||||||
const WebPRGBABuffer* const buf = &output->u.RGBA;
|
const WebPRGBABuffer* const buf = &output->u.RGBA;
|
||||||
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
|
uint8_t* const rgba =
|
||||||
|
buf->rgba + (int64_t)dec->last_out_row_ * buf->stride;
|
||||||
const int num_rows_out =
|
const int num_rows_out =
|
||||||
#if !defined(WEBP_REDUCE_SIZE)
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
io->use_scaling ?
|
io->use_scaling ?
|
||||||
@ -1276,7 +1285,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
|
|||||||
uint8_t* const new_data = (uint8_t*)new_color_map;
|
uint8_t* const new_data = (uint8_t*)new_color_map;
|
||||||
new_color_map[0] = transform->data_[0];
|
new_color_map[0] = transform->data_[0];
|
||||||
for (i = 4; i < 4 * num_colors; ++i) {
|
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;
|
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
|
||||||
}
|
}
|
||||||
for (; i < 4 * final_num_colors; ++i) {
|
for (; i < 4 * final_num_colors; ++i) {
|
||||||
@ -1353,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
|
|||||||
assert(hdr != NULL);
|
assert(hdr != NULL);
|
||||||
|
|
||||||
WebPSafeFree(hdr->huffman_image_);
|
WebPSafeFree(hdr->huffman_image_);
|
||||||
WebPSafeFree(hdr->huffman_tables_);
|
VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
|
||||||
VP8LHtreeGroupsFree(hdr->htree_groups_);
|
VP8LHtreeGroupsFree(hdr->htree_groups_);
|
||||||
VP8LColorCacheClear(&hdr->color_cache_);
|
VP8LColorCacheClear(&hdr->color_cache_);
|
||||||
VP8LColorCacheClear(&hdr->saved_color_cache_);
|
VP8LColorCacheClear(&hdr->saved_color_cache_);
|
||||||
@ -1514,7 +1523,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
|
|||||||
assert(dec->width_ <= final_width);
|
assert(dec->width_ <= final_width);
|
||||||
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
|
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
|
||||||
if (dec->pixels_ == NULL) {
|
if (dec->pixels_ == NULL) {
|
||||||
dec->argb_cache_ = NULL; // for sanity check
|
dec->argb_cache_ = NULL; // for soundness
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1524,7 +1533,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
|
|||||||
|
|
||||||
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
|
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
|
||||||
const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
|
const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
|
||||||
dec->argb_cache_ = NULL; // for sanity check
|
dec->argb_cache_ = NULL; // for soundness
|
||||||
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
|
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
|
||||||
if (dec->pixels_ == NULL) {
|
if (dec->pixels_ == NULL) {
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||||
@ -1666,10 +1675,9 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
|
|||||||
VP8Io* io = NULL;
|
VP8Io* io = NULL;
|
||||||
WebPDecParams* params = NULL;
|
WebPDecParams* params = NULL;
|
||||||
|
|
||||||
// Sanity checks.
|
|
||||||
if (dec == NULL) return 0;
|
if (dec == NULL) return 0;
|
||||||
|
|
||||||
assert(dec->hdr_.huffman_tables_ != NULL);
|
assert(dec->hdr_.huffman_tables_.root.start != NULL);
|
||||||
assert(dec->hdr_.htree_groups_ != NULL);
|
assert(dec->hdr_.htree_groups_ != NULL);
|
||||||
assert(dec->hdr_.num_htree_groups_ > 0);
|
assert(dec->hdr_.num_htree_groups_ > 0);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ typedef struct {
|
|||||||
uint32_t* huffman_image_;
|
uint32_t* huffman_image_;
|
||||||
int num_htree_groups_;
|
int num_htree_groups_;
|
||||||
HTreeGroup* htree_groups_;
|
HTreeGroup* htree_groups_;
|
||||||
HuffmanCode* huffman_tables_;
|
HuffmanTables huffman_tables_;
|
||||||
} VP8LMetadata;
|
} VP8LMetadata;
|
||||||
|
|
||||||
typedef struct VP8LDecoder VP8LDecoder;
|
typedef struct VP8LDecoder VP8LDecoder;
|
||||||
|
@ -785,6 +785,13 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Cropping and rescaling.
|
// Cropping and rescaling.
|
||||||
|
|
||||||
|
int WebPCheckCropDimensions(int image_width, int image_height,
|
||||||
|
int x, int y, int w, int h) {
|
||||||
|
return !(x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
||||||
|
x >= image_width || w > image_width || w > image_width - x ||
|
||||||
|
y >= image_height || h > image_height || h > image_height - y);
|
||||||
|
}
|
||||||
|
|
||||||
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||||
VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
|
VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
|
||||||
const int W = io->width;
|
const int W = io->width;
|
||||||
@ -792,7 +799,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
|||||||
int x = 0, y = 0, w = W, h = H;
|
int x = 0, y = 0, w = W, h = H;
|
||||||
|
|
||||||
// Cropping
|
// Cropping
|
||||||
io->use_cropping = (options != NULL) && (options->use_cropping > 0);
|
io->use_cropping = (options != NULL) && options->use_cropping;
|
||||||
if (io->use_cropping) {
|
if (io->use_cropping) {
|
||||||
w = options->crop_width;
|
w = options->crop_width;
|
||||||
h = options->crop_height;
|
h = options->crop_height;
|
||||||
@ -802,7 +809,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
|||||||
x &= ~1;
|
x &= ~1;
|
||||||
y &= ~1;
|
y &= ~1;
|
||||||
}
|
}
|
||||||
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
|
if (!WebPCheckCropDimensions(W, H, x, y, w, h)) {
|
||||||
return 0; // out of frame boundary error
|
return 0; // out of frame boundary error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,7 +821,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
|||||||
io->mb_h = h;
|
io->mb_h = h;
|
||||||
|
|
||||||
// Scaling
|
// Scaling
|
||||||
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
|
io->use_scaling = (options != NULL) && options->use_scaling;
|
||||||
if (io->use_scaling) {
|
if (io->use_scaling) {
|
||||||
int scaled_width = options->scaled_width;
|
int scaled_width = options->scaled_width;
|
||||||
int scaled_height = options->scaled_height;
|
int scaled_height = options->scaled_height;
|
||||||
@ -835,8 +842,8 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
|||||||
|
|
||||||
if (io->use_scaling) {
|
if (io->use_scaling) {
|
||||||
// disable filter (only for large downscaling ratio).
|
// disable filter (only for large downscaling ratio).
|
||||||
io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
|
io->bypass_filtering |= (io->scaled_width < W * 3 / 4) &&
|
||||||
(io->scaled_height < H * 3 / 4);
|
(io->scaled_height < H * 3 / 4);
|
||||||
io->fancy_upsampling = 0;
|
io->fancy_upsampling = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -77,6 +77,10 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Misc utils
|
// Misc utils
|
||||||
|
|
||||||
|
// Returns true if crop dimensions are within image bounds.
|
||||||
|
int WebPCheckCropDimensions(int image_width, int image_height,
|
||||||
|
int x, int y, int w, int h);
|
||||||
|
|
||||||
// Initializes VP8Io with custom setup, io and teardown functions. The default
|
// Initializes VP8Io with custom setup, io and teardown functions. The default
|
||||||
// hooks will use the supplied 'params' as io->opaque handle.
|
// hooks will use the supplied 'params' as io->opaque handle.
|
||||||
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
|
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
|
||||||
|
@ -13,6 +13,6 @@ noinst_HEADERS =
|
|||||||
noinst_HEADERS += ../webp/format_constants.h
|
noinst_HEADERS += ../webp/format_constants.h
|
||||||
|
|
||||||
libwebpdemux_la_LIBADD = ../libwebp.la
|
libwebpdemux_la_LIBADD = ../libwebp.la
|
||||||
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:7:0
|
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:10:0
|
||||||
libwebpdemuxincludedir = $(includedir)/webp
|
libwebpdemuxincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebpdemux.pc
|
pkgconfig_DATA = libwebpdemux.pc
|
||||||
|
@ -23,6 +23,14 @@
|
|||||||
|
|
||||||
#define NUM_CHANNELS 4
|
#define NUM_CHANNELS 4
|
||||||
|
|
||||||
|
// Channel extraction from a uint32_t representation of a uint8_t RGBA/BGRA
|
||||||
|
// buffer.
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
#define CHANNEL_SHIFT(i) (24 - (i) * 8)
|
||||||
|
#else
|
||||||
|
#define CHANNEL_SHIFT(i) ((i) * 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
|
typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
|
||||||
static void BlendPixelRowNonPremult(uint32_t* const src,
|
static void BlendPixelRowNonPremult(uint32_t* const src,
|
||||||
const uint32_t* const dst, int num_pixels);
|
const uint32_t* const dst, int num_pixels);
|
||||||
@ -87,11 +95,19 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
|||||||
int abi_version) {
|
int abi_version) {
|
||||||
WebPAnimDecoderOptions options;
|
WebPAnimDecoderOptions options;
|
||||||
WebPAnimDecoder* dec = NULL;
|
WebPAnimDecoder* dec = NULL;
|
||||||
|
WebPBitstreamFeatures features;
|
||||||
if (webp_data == NULL ||
|
if (webp_data == NULL ||
|
||||||
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
|
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the bitstream before doing expensive allocations. The demuxer may
|
||||||
|
// be more tolerant than the decoder.
|
||||||
|
if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
|
||||||
|
VP8_STATUS_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: calloc() so that the pointer members are initialized to NULL.
|
// Note: calloc() so that the pointer members are initialized to NULL.
|
||||||
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
|
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
|
||||||
if (dec == NULL) goto Error;
|
if (dec == NULL) goto Error;
|
||||||
@ -145,7 +161,7 @@ static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
|
|||||||
uint32_t canvas_height) {
|
uint32_t canvas_height) {
|
||||||
const uint64_t size =
|
const uint64_t size =
|
||||||
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
|
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
|
||||||
if (size != (size_t)size) return 0;
|
if (!CheckSizeOverflow(size)) return 0;
|
||||||
memset(buf, 0, (size_t)size);
|
memset(buf, 0, (size_t)size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -166,7 +182,7 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
|
|||||||
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
|
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
|
||||||
uint32_t width, uint32_t height) {
|
uint32_t width, uint32_t height) {
|
||||||
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
|
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
|
||||||
if (size != (size_t)size) return 0;
|
if (!CheckSizeOverflow(size)) return 0;
|
||||||
assert(src != NULL && dst != NULL);
|
assert(src != NULL && dst != NULL);
|
||||||
memcpy(dst, src, (size_t)size);
|
memcpy(dst, src, (size_t)size);
|
||||||
return 1;
|
return 1;
|
||||||
@ -201,35 +217,35 @@ static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a,
|
|||||||
const uint8_t dst_channel = (dst >> shift) & 0xff;
|
const uint8_t dst_channel = (dst >> shift) & 0xff;
|
||||||
const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
|
const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
|
||||||
assert(blend_unscaled < (1ULL << 32) / scale);
|
assert(blend_unscaled < (1ULL << 32) / scale);
|
||||||
return (blend_unscaled * scale) >> 24;
|
return (blend_unscaled * scale) >> CHANNEL_SHIFT(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
|
// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
|
||||||
static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
|
static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
|
||||||
const uint8_t src_a = (src >> 24) & 0xff;
|
const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
|
|
||||||
if (src_a == 0) {
|
if (src_a == 0) {
|
||||||
return dst;
|
return dst;
|
||||||
} else {
|
} else {
|
||||||
const uint8_t dst_a = (dst >> 24) & 0xff;
|
const uint8_t dst_a = (dst >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
// This is the approximate integer arithmetic for the actual formula:
|
// This is the approximate integer arithmetic for the actual formula:
|
||||||
// dst_factor_a = (dst_a * (255 - src_a)) / 255.
|
// dst_factor_a = (dst_a * (255 - src_a)) / 255.
|
||||||
const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
|
const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
|
||||||
const uint8_t blend_a = src_a + dst_factor_a;
|
const uint8_t blend_a = src_a + dst_factor_a;
|
||||||
const uint32_t scale = (1UL << 24) / blend_a;
|
const uint32_t scale = (1UL << 24) / blend_a;
|
||||||
|
|
||||||
const uint8_t blend_r =
|
const uint8_t blend_r = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 0);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0));
|
||||||
const uint8_t blend_g =
|
const uint8_t blend_g = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 8);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1));
|
||||||
const uint8_t blend_b =
|
const uint8_t blend_b = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 16);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2));
|
||||||
assert(src_a + dst_factor_a < 256);
|
assert(src_a + dst_factor_a < 256);
|
||||||
|
|
||||||
return (blend_r << 0) |
|
return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) |
|
||||||
(blend_g << 8) |
|
((uint32_t)blend_g << CHANNEL_SHIFT(1)) |
|
||||||
(blend_b << 16) |
|
((uint32_t)blend_b << CHANNEL_SHIFT(2)) |
|
||||||
((uint32_t)blend_a << 24);
|
((uint32_t)blend_a << CHANNEL_SHIFT(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +255,7 @@ static void BlendPixelRowNonPremult(uint32_t* const src,
|
|||||||
const uint32_t* const dst, int num_pixels) {
|
const uint32_t* const dst, int num_pixels) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_pixels; ++i) {
|
for (i = 0; i < num_pixels; ++i) {
|
||||||
const uint8_t src_alpha = (src[i] >> 24) & 0xff;
|
const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
if (src_alpha != 0xff) {
|
if (src_alpha != 0xff) {
|
||||||
src[i] = BlendPixelNonPremult(src[i], dst[i]);
|
src[i] = BlendPixelNonPremult(src[i], dst[i]);
|
||||||
}
|
}
|
||||||
@ -256,7 +272,7 @@ static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) {
|
|||||||
|
|
||||||
// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
|
// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
|
||||||
static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
|
static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
|
||||||
const uint8_t src_a = (src >> 24) & 0xff;
|
const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
return src + ChannelwiseMultiply(dst, 256 - src_a);
|
return src + ChannelwiseMultiply(dst, 256 - src_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +282,7 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
|
|||||||
int num_pixels) {
|
int num_pixels) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_pixels; ++i) {
|
for (i = 0; i < num_pixels; ++i) {
|
||||||
const uint8_t src_alpha = (src[i] >> 24) & 0xff;
|
const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
if (src_alpha != 0xff) {
|
if (src_alpha != 0xff) {
|
||||||
src[i] = BlendPixelPremult(src[i], dst[i]);
|
src[i] = BlendPixelPremult(src[i], dst[i]);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define DMUX_MAJ_VERSION 1
|
#define DMUX_MAJ_VERSION 1
|
||||||
#define DMUX_MIN_VERSION 2
|
#define DMUX_MIN_VERSION 2
|
||||||
#define DMUX_REV_VERSION 0
|
#define DMUX_REV_VERSION 3
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t start_; // start location of the data
|
size_t start_; // start location of the data
|
||||||
@ -221,12 +221,16 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
|||||||
const size_t chunk_start_offset = mem->start_;
|
const size_t chunk_start_offset = mem->start_;
|
||||||
const uint32_t fourcc = ReadLE32(mem);
|
const uint32_t fourcc = ReadLE32(mem);
|
||||||
const uint32_t payload_size = ReadLE32(mem);
|
const uint32_t payload_size = ReadLE32(mem);
|
||||||
const uint32_t payload_size_padded = payload_size + (payload_size & 1);
|
uint32_t payload_size_padded;
|
||||||
const size_t payload_available = (payload_size_padded > MemDataSize(mem))
|
size_t payload_available;
|
||||||
? MemDataSize(mem) : payload_size_padded;
|
size_t chunk_size;
|
||||||
const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
|
|
||||||
|
|
||||||
if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||||
|
|
||||||
|
payload_size_padded = payload_size + (payload_size & 1);
|
||||||
|
payload_available = (payload_size_padded > MemDataSize(mem))
|
||||||
|
? MemDataSize(mem) : payload_size_padded;
|
||||||
|
chunk_size = CHUNK_HEADER_SIZE + payload_available;
|
||||||
if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
|
if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
|
||||||
if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
|
if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
|
||||||
|
|
||||||
@ -451,9 +455,11 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
|
|||||||
const size_t chunk_start_offset = mem->start_;
|
const size_t chunk_start_offset = mem->start_;
|
||||||
const uint32_t fourcc = ReadLE32(mem);
|
const uint32_t fourcc = ReadLE32(mem);
|
||||||
const uint32_t chunk_size = ReadLE32(mem);
|
const uint32_t chunk_size = ReadLE32(mem);
|
||||||
const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
|
uint32_t chunk_size_padded;
|
||||||
|
|
||||||
if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
|
||||||
|
|
||||||
|
chunk_size_padded = chunk_size + (chunk_size & 1);
|
||||||
if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
|
if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
|
||||||
|
|
||||||
switch (fourcc) {
|
switch (fourcc) {
|
||||||
@ -608,7 +614,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
|||||||
|
|
||||||
while (f != NULL) {
|
while (f != NULL) {
|
||||||
const int cur_frame_set = f->frame_num_;
|
const int cur_frame_set = f->frame_num_;
|
||||||
int frame_count = 0;
|
|
||||||
|
|
||||||
// Check frame properties.
|
// Check frame properties.
|
||||||
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
|
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
|
||||||
@ -643,8 +648,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
|
|||||||
dmux->canvas_width_, dmux->canvas_height_)) {
|
dmux->canvas_width_, dmux->canvas_height_)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++frame_count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,2,0
|
FILEVERSION 1,0,2,3
|
||||||
PRODUCTVERSION 1,0,2,0
|
PRODUCTVERSION 1,0,2,3
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -24,12 +24,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Google, Inc."
|
VALUE "CompanyName", "Google, Inc."
|
||||||
VALUE "FileDescription", "libwebpdemux DLL"
|
VALUE "FileDescription", "libwebpdemux DLL"
|
||||||
VALUE "FileVersion", "1.2.0"
|
VALUE "FileVersion", "1.2.3"
|
||||||
VALUE "InternalName", "libwebpdemux.dll"
|
VALUE "InternalName", "libwebpdemux.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2019"
|
VALUE "LegalCopyright", "Copyright (C) 2022"
|
||||||
VALUE "OriginalFilename", "libwebpdemux.dll"
|
VALUE "OriginalFilename", "libwebpdemux.dll"
|
||||||
VALUE "ProductName", "WebP Image Demuxer"
|
VALUE "ProductName", "WebP Image Demuxer"
|
||||||
VALUE "ProductVersion", "1.2.0"
|
VALUE "ProductVersion", "1.2.3"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -24,6 +24,7 @@ commondir = $(includedir)/webp
|
|||||||
COMMON_SOURCES =
|
COMMON_SOURCES =
|
||||||
COMMON_SOURCES += alpha_processing.c
|
COMMON_SOURCES += alpha_processing.c
|
||||||
COMMON_SOURCES += cpu.c
|
COMMON_SOURCES += cpu.c
|
||||||
|
COMMON_SOURCES += cpu.h
|
||||||
COMMON_SOURCES += dec.c
|
COMMON_SOURCES += dec.c
|
||||||
COMMON_SOURCES += dec_clip_tables.c
|
COMMON_SOURCES += dec_clip_tables.c
|
||||||
COMMON_SOURCES += dsp.h
|
COMMON_SOURCES += dsp.h
|
||||||
@ -46,6 +47,7 @@ ENC_SOURCES += ssim.c
|
|||||||
libwebpdspdecode_sse41_la_SOURCES =
|
libwebpdspdecode_sse41_la_SOURCES =
|
||||||
libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
|
libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
|
||||||
libwebpdspdecode_sse41_la_SOURCES += dec_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 += upsampling_sse41.c
|
||||||
libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
|
libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
|
||||||
libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
||||||
|
@ -157,7 +157,8 @@ void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
|
||||||
|
const uint8_t* WEBP_RESTRICT const alpha,
|
||||||
int width, int inverse) {
|
int width, int inverse) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
@ -178,7 +179,8 @@ void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
|||||||
#undef MFIX
|
#undef MFIX
|
||||||
|
|
||||||
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
|
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
|
||||||
void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
|
void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
|
||||||
|
const uint8_t* WEBP_RESTRICT const alpha,
|
||||||
int width, int inverse);
|
int width, int inverse);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -193,8 +195,8 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPMultRows(uint8_t* ptr, int stride,
|
void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
|
||||||
const uint8_t* alpha, int alpha_stride,
|
const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||||
int width, int num_rows, int inverse) {
|
int width, int num_rows, int inverse) {
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < num_rows; ++n) {
|
for (n = 0; n < num_rows; ++n) {
|
||||||
@ -290,9 +292,9 @@ static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !WEBP_NEON_OMIT_C_CODE
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||||
uint32_t alpha_mask = 0xff;
|
uint32_t alpha_mask = 0xff;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@ -309,9 +311,10 @@ static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
|||||||
return (alpha_mask != 0xff);
|
return (alpha_mask != 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
|
static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
|
||||||
int width, int height,
|
int alpha_stride, int width, int height,
|
||||||
uint32_t* dst, int dst_stride) {
|
uint32_t* WEBP_RESTRICT dst,
|
||||||
|
int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (j = 0; j < height; ++j) {
|
for (j = 0; j < height; ++j) {
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
@ -322,9 +325,9 @@ static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||||
uint8_t alpha_mask = 0xff;
|
uint8_t alpha_mask = 0xff;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@ -340,7 +343,8 @@ static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
|
|||||||
return (alpha_mask == 0xff);
|
return (alpha_mask == 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
|
static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb,
|
||||||
|
uint8_t* WEBP_RESTRICT alpha, int size) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
||||||
}
|
}
|
||||||
@ -372,8 +376,11 @@ static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
|
||||||
const uint8_t* b, int len, uint32_t* out) {
|
const uint8_t* WEBP_RESTRICT r,
|
||||||
|
const uint8_t* WEBP_RESTRICT g,
|
||||||
|
const uint8_t* WEBP_RESTRICT b,
|
||||||
|
int len, uint32_t* WEBP_RESTRICT out) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
|
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
|
||||||
@ -381,8 +388,10 @@ static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
|
||||||
int len, int step, uint32_t* out) {
|
const uint8_t* WEBP_RESTRICT g,
|
||||||
|
const uint8_t* WEBP_RESTRICT b,
|
||||||
|
int len, int step, uint32_t* WEBP_RESTRICT out) {
|
||||||
int i, offset = 0;
|
int i, offset = 0;
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
|
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
|
||||||
@ -392,16 +401,22 @@ static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
|||||||
|
|
||||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
||||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
||||||
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||||
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
uint8_t* WEBP_RESTRICT, int);
|
||||||
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||||
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
uint32_t* WEBP_RESTRICT, int);
|
||||||
|
int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
|
||||||
|
uint8_t* WEBP_RESTRICT, int);
|
||||||
|
void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
|
||||||
|
uint8_t* WEBP_RESTRICT alpha, int size);
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
||||||
const uint8_t* b, int, uint32_t*);
|
const uint8_t* b, int, uint32_t*);
|
||||||
#endif
|
#endif
|
||||||
void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
|
||||||
int len, int step, uint32_t* out);
|
const uint8_t* WEBP_RESTRICT g,
|
||||||
|
const uint8_t* WEBP_RESTRICT b,
|
||||||
|
int len, int step, uint32_t* WEBP_RESTRICT out);
|
||||||
|
|
||||||
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
||||||
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
|
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
|
||||||
@ -438,10 +453,10 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
|
|||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_HAVE_SSE2)
|
||||||
if (VP8GetCPUInfo(kSSE2)) {
|
if (VP8GetCPUInfo(kSSE2)) {
|
||||||
WebPInitAlphaProcessingSSE2();
|
WebPInitAlphaProcessingSSE2();
|
||||||
#if defined(WEBP_USE_SSE41)
|
#if defined(WEBP_HAVE_SSE41)
|
||||||
if (VP8GetCPUInfo(kSSE4_1)) {
|
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||||
WebPInitAlphaProcessingSSE41();
|
WebPInitAlphaProcessingSSE41();
|
||||||
}
|
}
|
||||||
@ -455,7 +470,7 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_HAVE_NEON)
|
||||||
if (WEBP_NEON_OMIT_C_CODE ||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
WebPInitAlphaProcessingNEON();
|
WebPInitAlphaProcessingNEON();
|
||||||
|
@ -80,10 +80,10 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||||
int width, int height,
|
int alpha_stride, int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||||
uint32_t alpha_mask = 0xffffffffu;
|
uint32_t alpha_mask = 0xffu;
|
||||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
uint32_t tmp[2];
|
uint32_t tmp[2];
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -107,14 +107,16 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
|||||||
dst += dst_stride;
|
dst += dst_stride;
|
||||||
}
|
}
|
||||||
vst1_u8((uint8_t*)tmp, mask8);
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask *= 0x01010101;
|
||||||
alpha_mask &= tmp[0];
|
alpha_mask &= tmp[0];
|
||||||
alpha_mask &= tmp[1];
|
alpha_mask &= tmp[1];
|
||||||
return (alpha_mask != 0xffffffffu);
|
return (alpha_mask != 0xffffffffu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
|
static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
|
||||||
int width, int height,
|
int alpha_stride, int width, int height,
|
||||||
uint32_t* dst, int dst_stride) {
|
uint32_t* WEBP_RESTRICT dst,
|
||||||
|
int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
uint8x8x4_t greens; // leave A/R/B channels zero'd.
|
uint8x8x4_t greens; // leave A/R/B channels zero'd.
|
||||||
greens.val[0] = vdup_n_u8(0);
|
greens.val[0] = vdup_n_u8(0);
|
||||||
@ -131,10 +133,10 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||||
uint32_t alpha_mask = 0xffffffffu;
|
uint32_t alpha_mask = 0xffu;
|
||||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
uint32_t tmp[2];
|
uint32_t tmp[2];
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -156,13 +158,14 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
|||||||
alpha += alpha_stride;
|
alpha += alpha_stride;
|
||||||
}
|
}
|
||||||
vst1_u8((uint8_t*)tmp, mask8);
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask *= 0x01010101;
|
||||||
alpha_mask &= tmp[0];
|
alpha_mask &= tmp[0];
|
||||||
alpha_mask &= tmp[1];
|
alpha_mask &= tmp[1];
|
||||||
return (alpha_mask == 0xffffffffu);
|
return (alpha_mask == 0xffffffffu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExtractGreen_NEON(const uint32_t* argb,
|
static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,
|
||||||
uint8_t* alpha, int size) {
|
uint8_t* WEBP_RESTRICT alpha, int size) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i + 16 <= size; i += 16) {
|
for (i = 0; i + 16 <= size; i += 16) {
|
||||||
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
|
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||||
int width, int height,
|
int alpha_stride, int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
@ -72,9 +72,10 @@ static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
|
|||||||
return (alpha_and != 0xff);
|
return (alpha_and != 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
|
static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha,
|
||||||
int width, int height,
|
int alpha_stride, int width, int height,
|
||||||
uint32_t* dst, int dst_stride) {
|
uint32_t* WEBP_RESTRICT dst,
|
||||||
|
int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const int limit = width & ~15;
|
const int limit = width & ~15;
|
||||||
@ -98,9 +99,9 @@ static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
@ -317,7 +318,8 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
|
|||||||
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
|
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
static void MultRow_SSE2(uint8_t* WEBP_RESTRICT const ptr,
|
||||||
|
const uint8_t* WEBP_RESTRICT const alpha,
|
||||||
int width, int inverse) {
|
int width, int inverse) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
if (!inverse) {
|
if (!inverse) {
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb,
|
||||||
int width, int height,
|
int argb_stride, int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
|
@ -395,12 +395,12 @@ WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
|
|||||||
VP8EncDspCostInitMIPSdspR2();
|
VP8EncDspCostInitMIPSdspR2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_HAVE_SSE2)
|
||||||
if (VP8GetCPUInfo(kSSE2)) {
|
if (VP8GetCPUInfo(kSSE2)) {
|
||||||
VP8EncDspCostInitSSE2();
|
VP8EncDspCostInitSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_HAVE_NEON)
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
if (VP8GetCPUInfo(kNEON)) {
|
||||||
VP8EncDspCostInitNEON();
|
VP8EncDspCostInitNEON();
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
// Author: Christian Duvivier (cduvivier@google.com)
|
// Author: Christian Duvivier (cduvivier@google.com)
|
||||||
|
|
||||||
#include "src/dsp/dsp.h"
|
#include "src/dsp/cpu.h"
|
||||||
|
|
||||||
#if defined(WEBP_HAVE_NEON_RTCD)
|
#if defined(WEBP_HAVE_NEON_RTCD)
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -189,17 +189,17 @@ VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
|
|||||||
// Use compile flags as an indicator of SIMD support instead of a runtime check.
|
// Use compile flags as an indicator of SIMD support instead of a runtime check.
|
||||||
static int wasmCPUInfo(CPUFeature feature) {
|
static int wasmCPUInfo(CPUFeature feature) {
|
||||||
switch (feature) {
|
switch (feature) {
|
||||||
#ifdef WEBP_USE_SSE2
|
#ifdef WEBP_HAVE_SSE2
|
||||||
case kSSE2:
|
case kSSE2:
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef WEBP_USE_SSE41
|
#ifdef WEBP_HAVE_SSE41
|
||||||
case kSSE3:
|
case kSSE3:
|
||||||
case kSlowSSSE3:
|
case kSlowSSSE3:
|
||||||
case kSSE4_1:
|
case kSSE4_1:
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef WEBP_USE_NEON
|
#ifdef WEBP_HAVE_NEON
|
||||||
case kNEON:
|
case kNEON:
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
@ -209,9 +209,10 @@ static int wasmCPUInfo(CPUFeature feature) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
|
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
|
||||||
#elif defined(WEBP_USE_NEON)
|
#elif defined(WEBP_HAVE_NEON)
|
||||||
// define a dummy function to enable turning off NEON at runtime by setting
|
// In most cases this function doesn't check for NEON support (it's assumed by
|
||||||
// VP8DecGetCPUInfo = NULL
|
// the configuration), but enables turning off NEON at runtime, for testing
|
||||||
|
// purposes, by setting VP8DecGetCPUInfo = NULL.
|
||||||
static int armCPUInfo(CPUFeature feature) {
|
static int armCPUInfo(CPUFeature feature) {
|
||||||
if (feature != kNEON) return 0;
|
if (feature != kNEON) return 0;
|
||||||
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)
|
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user