Compare commits

..

1 Commits

Author SHA1 Message Date
86c756929c rescaler_mips32: disable ImportRowShrink
this function is failing the 'accum == 0' assert on skia bots for
rescaling to 13x13

BUG=skia:6682

Change-Id: I9f9f3adf28cec63ad6e38ed3128f18825d5b70cc
2017-06-02 19:58:33 -07:00
314 changed files with 12631 additions and 33051 deletions

View File

@ -1,240 +0,0 @@
# ----------------------------------
# Options affecting listfile parsing
# ----------------------------------
with section("parse"):
# Specify structure for custom cmake functions
additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'],
'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}
# Override configurations per-command where available
override_spec = {}
# Specify variable tags.
vartags = []
# Specify property tags.
proptags = []
# -----------------------------
# Options affecting formatting.
# -----------------------------
with section("format"):
# Disable formatting entirely, making cmake-format a no-op
disable = False
# How wide to allow formatted cmake files
line_width = 80
# How many spaces to tab for indent
tab_size = 2
# If true, lines are indented using tab characters (utf-8 0x09) instead of
# <tab_size> space characters (utf-8 0x20). In cases where the layout would
# require a fractional tab character, the behavior of the fractional
# indentation is governed by <fractional_tab_policy>
use_tabchars = False
# If <use_tabchars> is True, then the value of this variable indicates how
# fractional indentions are handled during whitespace replacement. If set to
# 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set
# to `round-up` fractional indentation is replaced with a single tab character
# (utf-8 0x09) effectively shifting the column to the next tabstop
fractional_tab_policy = 'use-space'
# If an argument group contains more than this many sub-groups (parg or kwarg
# groups) then force it to a vertical layout.
max_subgroups_hwrap = 3
# If a positional argument group contains more than this many arguments, then
# force it to a vertical layout.
max_pargs_hwrap = 6
# If a cmdline positional group consumes more than this many lines without
# nesting, then invalidate the layout (and nest)
max_rows_cmdline = 2
# If true, separate flow control names from their parentheses with a space
separate_ctrl_name_with_space = False
# If true, separate function names from parentheses with a space
separate_fn_name_with_space = False
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on its own line.
dangle_parens = False
# If the trailing parenthesis must be 'dangled' on its on line, then align it
# to this reference: `prefix`: the start of the statement, `prefix-indent`:
# the start of the statement, plus one indentation level, `child`: align to
# the column of the arguments
dangle_align = 'prefix'
# If the statement spelling length (including space and parenthesis) is
# smaller than this amount, then force reject nested layouts.
min_prefix_chars = 4
# If the statement spelling length (including space and parenthesis) is larger
# than the tab width by more than this amount, then force reject un-nested
# layouts.
max_prefix_chars = 10
# If a candidate layout is wrapped horizontally but it exceeds this many
# lines, then reject the layout.
max_lines_hwrap = 2
# What style line endings to use in the output.
line_ending = 'unix'
# Format command names consistently as 'lower' or 'upper' case
command_case = 'canonical'
# Format keywords consistently as 'lower' or 'upper' case
keyword_case = 'unchanged'
# A list of command names which should always be wrapped
always_wrap = []
# If true, the argument lists which are known to be sortable will be sorted
# lexicographicall
enable_sort = True
# If true, the parsers may infer whether or not an argument list is sortable
# (without annotation).
autosort = False
# By default, if cmake-format cannot successfully fit everything into the
# desired linewidth it will apply the last, most agressive attempt that it
# made. If this flag is True, however, cmake-format will print error, exit
# with non-zero status code, and write-out nothing
require_valid_layout = False
# A dictionary mapping layout nodes to a list of wrap decisions. See the
# documentation for more information.
layout_passes = {}
# ------------------------------------------------
# Options affecting comment reflow and formatting.
# ------------------------------------------------
with section("markup"):
# What character to use for bulleted lists
bullet_char = '*'
# What character to use as punctuation after numerals in an enumerated list
enum_char = '.'
# If comment markup is enabled, don't reflow the first comment block in each
# listfile. Use this to preserve formatting of your copyright/license
# statements.
first_comment_is_literal = True
# If comment markup is enabled, don't reflow any comment block which matches
# this (regex) pattern. Default is `None` (disabled).
literal_comment_pattern = None
# Regular expression to match preformat fences in comments default=
# ``r'^\s*([`~]{3}[`~]*)(.*)$'``
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
# Regular expression to match rulers in comments default=
# ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'``
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
# If a comment line matches starts with this pattern then it is explicitly a
# trailing comment for the preceeding argument. Default is '#<'
explicit_trailing_pattern = '#<'
# If a comment line starts with at least this many consecutive hash
# characters, then don't lstrip() them off. This allows for lazy hash rulers
# where the first hash char is not separated by space
hashruler_min_length = 10
# If true, then insert a space between the first hash char and remaining hash
# chars in a hash ruler, and normalize its length to fill the column
canonicalize_hashrulers = True
# enable comment markup parsing and reflow
enable_markup = True
# ----------------------------
# Options affecting the linter
# ----------------------------
with section("lint"):
# a list of lint codes to disable
disabled_codes = []
# regular expression pattern describing valid function names
function_pattern = '[0-9a-z_]+'
# regular expression pattern describing valid macro names
macro_pattern = '[0-9A-Z_]+'
# regular expression pattern describing valid names for variables with global
# (cache) scope
global_var_pattern = '[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for variables with global
# scope (but internal semantic)
internal_var_pattern = '_[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for variables with local
# scope
local_var_pattern = '[a-z][a-z0-9_]+'
# regular expression pattern describing valid names for privatedirectory
# variables
private_var_pattern = '_[0-9a-z_]+'
# regular expression pattern describing valid names for public directory
# variables
public_var_pattern = '[A-Z][0-9A-Z_]+'
# regular expression pattern describing valid names for function/macro
# arguments and loop variables.
argument_var_pattern = '[a-z][a-z0-9_]+'
# regular expression pattern describing valid names for keywords used in
# functions or macros
keyword_pattern = '[A-Z][0-9A-Z_]+'
# In the heuristic for C0201, how many conditionals to match within a loop in
# before considering the loop a parser.
max_conditionals_custom_parser = 2
# Require at least this many newlines between statements
min_statement_spacing = 1
# Require no more than this many newlines between statements
max_statement_spacing = 2
max_returns = 6
max_branches = 12
max_arguments = 5
max_localvars = 15
max_statements = 50
# -------------------------------
# Options affecting file encoding
# -------------------------------
with section("encode"):
# If true, emit the unicode byte-order mark (BOM) at the start of the file
emit_byteorder_mark = False
# Specify the encoding of the input file. Defaults to utf-8
input_encoding = 'utf-8'
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
# only claims to support utf-8 so be careful when using anything else
output_encoding = 'utf-8'
# -------------------------------------
# Miscellaneous configurations options.
# -------------------------------------
with section("misc"):
# A dictionary containing any per-command configuration overrides. Currently
# only `command_case` is supported.
per_command = {}

1
.gitattributes vendored
View File

@ -1,6 +1,5 @@
.gitattributes export-ignore .gitattributes export-ignore
.gitignore export-ignore .gitignore export-ignore
.mailmap export-ignore .mailmap export-ignore
*.bat text eol=crlf
*.pdf -text -diff *.pdf -text -diff
*.ppm -text -diff *.ppm -text -diff

17
.gitignore vendored
View File

@ -1,11 +1,8 @@
*.l[ao] *.l[ao]
*.[ao] *.[ao]
*.pc *.pc
.DS_Store
.deps .deps
.idea
.libs .libs
.vscode
/aclocal.m4 /aclocal.m4
/ar-lib /ar-lib
/autom4te.cache /autom4te.cache
@ -23,11 +20,9 @@
Makefile Makefile
Makefile.in Makefile.in
examples/anim_diff examples/anim_diff
examples/anim_dump
examples/[cdv]webp examples/[cdv]webp
examples/gif2webp examples/gif2webp
examples/img2webp examples/img2webp
examples/webpinfo
examples/webpmux examples/webpmux
src/webp/config.h* src/webp/config.h*
src/webp/stamp-h1 src/webp/stamp-h1
@ -36,21 +31,11 @@ src/webp/stamp-h1
*.idb *.idb
*.pdb *.pdb
/iosbuild /iosbuild
/xcframeworkbuild /WebP.framework
/WebP*.*framework
CMakeCache.txt CMakeCache.txt
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
.gradle .gradle
/build /build
extras/get_disto extras/get_disto
extras/vwebp_sdl
extras/webp_quality extras/webp_quality
tests/fuzzer/advanced_api_fuzzer
tests/fuzzer/animation_api_fuzzer
tests/fuzzer/animdecoder_fuzzer
tests/fuzzer/animencoder_fuzzer
tests/fuzzer/demux_api_fuzzer
tests/fuzzer/enc_dec_fuzzer
tests/fuzzer/mux_demux_api_fuzzer
tests/fuzzer/simple_api_fuzzer

View File

@ -1,19 +1,12 @@
Johann Koenig <johann.koenig@duck.com> <johann.koenig@duck.com> <johannkoenig@google.com>
Johann Koenig <johann.koenig@duck.com> <johannkoenig@google.com>
Mikołaj Zalewski <mikolajz@google.com> Mikołaj Zalewski <mikolajz@google.com>
Pascal Massimino <pascal.massimino@gmail.com> Pascal Massimino <pascal.massimino@gmail.com>
Pascal Massimino <pascal.massimino@gmail.com> <skal@google.com> <pascal.massimino@gmail.com> <skal@google.com>
Vikas Arora <vikasa@google.com> Vikas Arora <vikasa@google.com>
<vikasa@google.com> <vikasa@gmail.com> <vikasa@google.com> <vikasa@gmail.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>
Yannis Guyon <yguyon@google.com>

441
.pylintrc
View File

@ -1,441 +0,0 @@
# 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

View File

@ -1,2 +0,0 @@
[style]
based_on_style = yapf

24
AUTHORS
View File

@ -1,45 +1,28 @@
Contributors: Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Alexandru Ardelean (ardeleanalex at gmail dot com)
- Brian Ledger (brianpl at google dot com)
- Charles Munger (clm at google dot com) - Charles Munger (clm 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)
- H. Vetinari (h dot vetinari at gmx dot com)
- Ilya Kurdyukov (jpegqs at gmail dot com)
- Ingvar Stepanyan (rreverser at google dot com)
- James Zern (jzern at google dot com) - James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de) - Jan Engelhardt (jengelh at medozas dot de)
- Jehan (jehan at girinstud dot io) - Jehan (jehan at girinstud dot io)
- Jeremy Maitin-Shepard (jbms at google dot com) - Johann (johann dot koenig at duck dot com)
- Johann Koenig (johann dot koenig at duck dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com) - Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
- Lode Vandevenne (lode at google dot com) - Lode Vandevenne (lode at google dot com)
- Lou Quillio (louquillio at google dot com) - Lou Quillio (louquillio at google dot com)
- 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)
- Noel Chromium (noel at chromium dot org) - Noel Chromium (noel at chromium dot org)
- Nozomi Isozaki (nontan at pixiv dot co dot jp)
- Oliver Wolff (oliver dot wolff at qt dot io)
- Owen Rodley (orodley at google dot com) - Owen Rodley (orodley at google dot com)
- Parag Salasakar (img dot mips1 at gmail dot com) - Parag Salasakar (img dot mips1 at gmail dot com)
- 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)
@ -48,13 +31,8 @@ Contributors:
- Somnath Banerjee (somnath dot banerjee at gmail dot com) - Somnath Banerjee (somnath dot banerjee at gmail dot com)
- Sriraman Tallam (tmsriram at google dot com) - Sriraman Tallam (tmsriram at google dot com)
- Tamar Levy (tamar dot levy at intel dot com) - Tamar Levy (tamar dot levy at intel dot com)
- Thiago Perrotta (tperrotta at google dot com)
- Timothy Gu (timothygu99 at gmail dot com) - Timothy Gu (timothygu99 at gmail dot com)
- Urvang Joshi (urvang at google dot com) - Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com) - Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com) - Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Wan-Teh Chang (wtc at google dot com)
- Yang Zhang (yang dot zhang at arm dot com) - Yang Zhang (yang dot zhang at arm dot com)
- Yannis Guyon (yguyon at google dot com)
- Zhi An Ng (zhin at chromium dot org)

View File

@ -1,5 +1,3 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
@ -13,37 +11,16 @@ ifeq ($(APP_OPTIM),release)
endif endif
endif endif
# mips32 fails to build with clang from r14b
# https://bugs.chromium.org/p/webp/issues/detail?id=343
ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),clang)
ifeq ($(TARGET_ARCH),mips)
clang_version := $(shell $(TARGET_CC) --version)
ifneq ($(findstring clang version 3,$(clang_version)),)
WEBP_CFLAGS += -no-integrated-as
endif
endif
endif
ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),) ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),)
# Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal # Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal
# instructions to be generated for armv7a code. Instead target the neon code # instructions to be generated for armv7a code. Instead target the neon code
# specifically. # specifically.
NEON := c.neon NEON := c.neon
USE_CPUFEATURES := yes USE_CPUFEATURES := yes
WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H
else else
NEON := c NEON := c
endif endif
sharpyuv_srcs := \
sharpyuv/sharpyuv.c \
sharpyuv/sharpyuv_cpu.c \
sharpyuv/sharpyuv_csp.c \
sharpyuv/sharpyuv_dsp.c \
sharpyuv/sharpyuv_gamma.c \
sharpyuv/sharpyuv_neon.$(NEON) \
sharpyuv/sharpyuv_sse2.c \
dec_srcs := \ dec_srcs := \
src/dec/alpha_dec.c \ src/dec/alpha_dec.c \
src/dec/buffer_dec.c \ src/dec/buffer_dec.c \
@ -66,6 +43,9 @@ dsp_dec_srcs := \
src/dsp/alpha_processing_neon.$(NEON) \ src/dsp/alpha_processing_neon.$(NEON) \
src/dsp/alpha_processing_sse2.c \ src/dsp/alpha_processing_sse2.c \
src/dsp/alpha_processing_sse41.c \ src/dsp/alpha_processing_sse41.c \
src/dsp/argb.c \
src/dsp/argb_mips_dsp_r2.c \
src/dsp/argb_sse2.c \
src/dsp/cpu.c \ src/dsp/cpu.c \
src/dsp/dec.c \ src/dsp/dec.c \
src/dsp/dec_clip_tables.c \ src/dsp/dec_clip_tables.c \
@ -85,7 +65,6 @@ 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 \
@ -97,21 +76,18 @@ dsp_dec_srcs := \
src/dsp/upsampling_msa.c \ src/dsp/upsampling_msa.c \
src/dsp/upsampling_neon.$(NEON) \ src/dsp/upsampling_neon.$(NEON) \
src/dsp/upsampling_sse2.c \ src/dsp/upsampling_sse2.c \
src/dsp/upsampling_sse41.c \
src/dsp/yuv.c \ src/dsp/yuv.c \
src/dsp/yuv_mips32.c \ src/dsp/yuv_mips32.c \
src/dsp/yuv_mips_dsp_r2.c \ src/dsp/yuv_mips_dsp_r2.c \
src/dsp/yuv_neon.$(NEON) \
src/dsp/yuv_sse2.c \ src/dsp/yuv_sse2.c \
src/dsp/yuv_sse41.c \
dsp_enc_srcs := \ dsp_enc_srcs := \
src/dsp/cost.c \ src/dsp/cost.c \
src/dsp/cost_mips32.c \ src/dsp/cost_mips32.c \
src/dsp/cost_mips_dsp_r2.c \ src/dsp/cost_mips_dsp_r2.c \
src/dsp/cost_neon.$(NEON) \
src/dsp/cost_sse2.c \ src/dsp/cost_sse2.c \
src/dsp/enc.c \ src/dsp/enc.c \
src/dsp/enc_avx2.c \
src/dsp/enc_mips32.c \ src/dsp/enc_mips32.c \
src/dsp/enc_mips_dsp_r2.c \ src/dsp/enc_mips_dsp_r2.c \
src/dsp/enc_msa.c \ src/dsp/enc_msa.c \
@ -125,16 +101,14 @@ dsp_enc_srcs := \
src/dsp/lossless_enc_neon.$(NEON) \ src/dsp/lossless_enc_neon.$(NEON) \
src/dsp/lossless_enc_sse2.c \ src/dsp/lossless_enc_sse2.c \
src/dsp/lossless_enc_sse41.c \ src/dsp/lossless_enc_sse41.c \
src/dsp/ssim.c \
src/dsp/ssim_sse2.c \
enc_srcs := \ enc_srcs := \
src/enc/alpha_enc.c \ src/enc/alpha_enc.c \
src/enc/analysis_enc.c \ src/enc/analysis_enc.c \
src/enc/backward_references_cost_enc.c \
src/enc/backward_references_enc.c \ src/enc/backward_references_enc.c \
src/enc/config_enc.c \ src/enc/config_enc.c \
src/enc/cost_enc.c \ src/enc/cost_enc.c \
src/enc/delta_palettization_enc.c \
src/enc/filter_enc.c \ src/enc/filter_enc.c \
src/enc/frame_enc.c \ src/enc/frame_enc.c \
src/enc/histogram_enc.c \ src/enc/histogram_enc.c \
@ -186,7 +160,7 @@ LOCAL_SRC_FILES := \
$(utils_dec_srcs) \ $(utils_dec_srcs) \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains # prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
@ -215,13 +189,12 @@ 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) \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH) LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains # prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
@ -244,7 +217,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(demux_srcs) LOCAL_SRC_FILES := $(demux_srcs)
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains # prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
@ -267,7 +240,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(mux_srcs) LOCAL_SRC_FILES := $(mux_srcs)
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains # prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
@ -291,4 +264,3 @@ include $(WEBP_SRC_PATH)/examples/Android.mk
ifeq ($(USE_CPUFEATURES),yes) ifeq ($(USE_CPUFEATURES),yes)
$(call import-module,android/cpufeatures) $(call import-module,android/cpufeatures)
endif endif
endif # NDK_ROOT

View File

@ -1,802 +1,189 @@
# Copyright (c) 2020 Google LLC. cmake_minimum_required(VERSION 2.8.7)
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
if(APPLE) project(libwebp C)
cmake_minimum_required(VERSION 3.17)
else()
cmake_minimum_required(VERSION 3.7)
endif()
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
endif()
project(WebP C)
# Options for coder / decoder executables. # Options for coder / decoder executables.
if(BUILD_SHARED_LIBS) option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF)
set(WEBP_LINK_STATIC_DEFAULT OFF) option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF)
else() option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." OFF)
set(WEBP_LINK_STATIC_DEFAULT ON) option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." OFF)
endif() option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
option(WEBP_LINK_STATIC option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF)
"Link using static libraries. If OFF, use dynamic libraries."
${WEBP_LINK_STATIC_DEFAULT})
if(NOT EMSCRIPTEN)
# Disable SIMD on Emscripten by default, as it's a new unstable Wasm feature.
# Users can still explicitly opt-in to make a SIMD-enabled build.
set(WEBP_ENABLE_SIMD_DEFAULT ON)
endif()
option(WEBP_ENABLE_SIMD "Enable any SIMD optimization."
${WEBP_ENABLE_SIMD_DEFAULT})
option(WEBP_BUILD_ANIM_UTILS "Build animation utilities." ON)
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." ON)
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." ON)
option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON)
option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON)
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON)
option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON)
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
option(WEBP_BUILD_EXTRAS "Build extras." ON)
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
option(WEBP_USE_THREAD "Enable threading support" ON)
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
OFF)
set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2)
if(WEBP_LINK_STATIC)
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# vwebp does not compile on Ubuntu with static libraries so disabling it for
# now.
set(WEBP_BUILD_VWEBP OFF)
endif()
# Option needed for handling Unicode file names on Windows.
if(WIN32)
option(WEBP_UNICODE "Build Unicode executables." ON)
endif()
if(WEBP_BUILD_WEBP_JS)
set(WEBP_BUILD_ANIM_UTILS OFF)
set(WEBP_BUILD_CWEBP OFF)
set(WEBP_BUILD_DWEBP OFF)
set(WEBP_BUILD_GIF2WEBP OFF)
set(WEBP_BUILD_IMG2WEBP OFF)
set(WEBP_BUILD_VWEBP OFF)
set(WEBP_BUILD_WEBPINFO OFF)
set(WEBP_BUILD_WEBPMUX OFF)
set(WEBP_BUILD_EXTRAS OFF)
set(WEBP_USE_THREAD OFF)
if(WEBP_ENABLE_SIMD)
message(NOTICE
"wasm2js does not support SIMD, disabling webp.js generation.")
endif()
endif()
set(SHARPYUV_DEP_LIBRARIES)
set(SHARPYUV_DEP_INCLUDE_DIRS)
set(WEBP_DEP_LIBRARIES) set(WEBP_DEP_LIBRARIES)
set(WEBP_DEP_INCLUDE_DIRS) set(WEBP_DEP_INCLUDE_DIRS)
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" set(CMAKE_BUILD_TYPE "Release" CACHE
CACHE STRING "Build type: Release, Debug, MinSizeRel or RelWithDebInfo" "Build type: Release, Debug or RelWithDebInfo" STRING FORCE
FORCE) )
endif() endif()
# Include dependencies. include(cmake/config.h.cmake)
if(WEBP_BUILD_ANIM_UTILS
OR WEBP_BUILD_CWEBP
OR WEBP_BUILD_DWEBP
OR WEBP_BUILD_EXTRAS
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP)
set(WEBP_FIND_IMG_LIBS TRUE)
else()
set(WEBP_FIND_IMG_LIBS FALSE)
endif()
include(cmake/deps.cmake)
include(GNUInstallDirs)
if(BUILD_SHARED_LIBS AND NOT DEFINED CMAKE_INSTALL_RPATH) ################################################################################
# Set the rpath to match autoconf/libtool behavior. Note this must be set
# before target creation.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
# ##############################################################################
# Options. # Options.
if(WEBP_ENABLE_SWAP_16BIT_CSP) if(WEBP_ENABLE_SWAP_16BIT_CSP)
add_definitions(-DWEBP_SWAP_16BIT_CSP=1) add_definitions(-DWEBP_SWAP_16BIT_CSP)
endif() endif()
if(NOT WEBP_BITTRACE STREQUAL "0") ################################################################################
add_definitions(-DBITTRACE=${WEBP_BITTRACE})
endif()
if(WEBP_UNICODE)
# Windows recommends setting both UNICODE and _UNICODE.
add_definitions(-DUNICODE -D_UNICODE)
endif()
if(MSVC AND BUILD_SHARED_LIBS)
add_definitions(-DWEBP_DLL)
endif()
# pkg-config variables used by *.pc.in.
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\${prefix}")
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(libdir "${CMAKE_INSTALL_LIBDIR}")
else()
set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
else()
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
set(INSTALLED_LIBRARIES)
if(MSVC)
# match the naming convention used by nmake
set(webp_libname_prefix "lib")
set(CMAKE_SHARED_LIBRARY_PREFIX "${webp_libname_prefix}")
set(CMAKE_IMPORT_LIBRARY_PREFIX "${webp_libname_prefix}")
set(CMAKE_STATIC_LIBRARY_PREFIX "${webp_libname_prefix}")
endif()
set(CMAKE_C_VISIBILITY_PRESET hidden)
# ##############################################################################
# Android only. # Android only.
if(ANDROID) if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures) include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures-webp STATIC add_library(cpufeatures STATIC
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c) ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
list(APPEND INSTALLED_LIBRARIES cpufeatures-webp) )
target_link_libraries(cpufeatures-webp dl) target_link_libraries(cpufeatures dl)
set(SHARPYUV_DEP_LIBRARIES ${SHARPYUV_DEP_LIBRARIES} cpufeatures-webp) set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures)
set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures-webp) set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS}
set(cpufeatures_include_dir ${ANDROID_NDK}/sources/android/cpufeatures) ${ANDROID_NDK}/sources/android/cpufeatures
set(SHARPYUV_DEP_INCLUDE_DIRS ${SHARPYUV_DEP_INCLUDE_DIRS} )
${cpufeatures_include_dir})
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${cpufeatures_include_dir})
add_definitions(-DHAVE_CPU_FEATURES_H=1)
set(HAVE_CPU_FEATURES_H 1)
else()
set(HAVE_CPU_FEATURES_H 0)
endif() endif()
function(configure_pkg_config FILE) ################################################################################
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}.in" # WebP source files.
"${CMAKE_CURRENT_BINARY_DIR}/${FILE}" @ONLY) # Read the Makefile.am to get the source files.
if(HAVE_MATH_LIBRARY) function(parse_Makefile_am FOLDER VAR)
# MSVC doesn't have libm
file(READ ${CMAKE_CURRENT_BINARY_DIR}/${FILE} data)
string(REPLACE "-lm" "" data ${data})
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${FILE} ${data})
endif()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endfunction()
# ##############################################################################
# WebP source files. Read the Makefile.am to get the source files.
# We expect the Makefiles to define the sources as defined in the first regex.
# E.g.: libimagedec_la_SOURCES = image_dec.c image_dec.h
function(parse_Makefile_am FOLDER VAR SRC_REGEX)
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM) file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
string(REGEX MATCHALL "${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*" string(REGEX MATCHALL "_SOURCES \\+= [^\n]*"
FILES_PER_LINE ${MAKEFILE_AM}) FILES_PER_LINE ${MAKEFILE_AM}
)
set(SRCS ${${VAR}}) set(SRCS ${${VAR}})
foreach(FILES ${FILES_PER_LINE}) foreach(FILES ${FILES_PER_LINE})
string(FIND ${FILES} "=" OFFSET) string(SUBSTRING ${FILES} 12 -1 FILES)
math(EXPR OFFSET "${OFFSET} + 2") string(REGEX MATCHALL "[0-9a-z\\._]+"
string(SUBSTRING ${FILES} ${OFFSET} -1 FILES) FILES ${FILES}
if(FILES) )
string(REGEX MATCHALL "[0-9a-z\\._]+" FILES ${FILES})
foreach(FILE ${FILES}) foreach(FILE ${FILES})
list(APPEND SRCS ${FOLDER}/${FILE}) list(APPEND SRCS ${FOLDER}/${FILE})
endforeach() endforeach()
endif()
endforeach() endforeach()
set(${VAR} ${SRCS} PARENT_SCOPE) set(${VAR} ${SRCS} PARENT_SCOPE)
endfunction() endfunction()
set(WEBP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(WEBP_SRCS)
parse_makefile_am(${WEBP_SRC_DIR}/dec "WEBP_DEC_SRCS" "") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dec "WEBP_SRCS")
parse_makefile_am(${WEBP_SRC_DIR}/demux "WEBP_DEMUX_SRCS" "") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/demux "WEBP_SRCS")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_COMMON_SRCS" "COMMON") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dsp "WEBP_SRCS")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "ENC") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/enc "WEBP_SRCS")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "dsp_[^ ]*") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/utils "WEBP_SRCS")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_DEC_SRCS" "decode_[^ ]*")
parse_makefile_am(${WEBP_SRC_DIR}/enc "WEBP_ENC_SRCS" "")
parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_COMMON_SRCS" "COMMON")
parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_ENC_SRCS" "ENC")
parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_DEC_SRCS" "decode_[^ ]*")
# Remove the files specific to SIMD we don't use. # Remove the files specific to SIMD we don't use.
foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE}) foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
list(REMOVE_ITEM WEBP_DSP_ENC_SRCS ${FILE}) list(REMOVE_ITEM WEBP_SRCS ${FILE})
list(REMOVE_ITEM WEBP_DSP_DEC_SRCS ${FILE})
endforeach() endforeach()
# Generate the config.h file. # Build the library.
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in add_definitions(-Wall)
${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h @ONLY) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/ ${WEBP_DEP_INCLUDE_DIRS})
add_definitions(-DHAVE_CONFIG_H) add_library(webp ${WEBP_SRCS})
# Set the version numbers.
macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} SOURCE_FILE)
string(REGEX MATCH
"${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+" TMP
${SOURCE_FILE})
string(REGEX MATCH "[0-9:]+" TMP ${TMP})
string(REGEX REPLACE ":" " " LT_VERSION ${TMP})
# See the libtool docs for more information:
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
#
# c=<current>, a=<age>, r=<revision>
#
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
# passed to libtool.
#
# We set FULL = [c-a].a.r and MAJOR = [c-a].
separate_arguments(LT_VERSION)
list(GET LT_VERSION 0 LT_CURRENT)
list(GET LT_VERSION 1 LT_REVISION)
list(GET LT_VERSION 2 LT_AGE)
math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}")
set_target_properties(
${TARGET_NAME}
PROPERTIES VERSION ${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION}
SOVERSION ${LT_CURRENT_MINUS_AGE})
if(APPLE)
# For compatibility, set MACHO_COMPATIBILITY_VERSION and
# MACHO_CURRENT_VERSION to match libtool. These properties were introduced
# in 3.17:
# https://cmake.org/cmake/help/latest/prop_tgt/MACHO_COMPATIBILITY_VERSION.html
math(EXPR LIBWEBP_MACHO_COMPATIBILITY_VERSION "${LT_CURRENT} + 1")
set_target_properties(
${TARGET_NAME}
PROPERTIES MACHO_COMPATIBILITY_VERSION
${LIBWEBP_MACHO_COMPATIBILITY_VERSION}
MACHO_CURRENT_VERSION
${LIBWEBP_MACHO_COMPATIBILITY_VERSION}.${LT_REVISION})
endif()
endmacro()
# ##############################################################################
# Build the webpdecoder library.
# Creates a source file with an unused stub function in $CMAKE_BINARY_DIR and
# adds it to the specified target. Currently used only with Xcode.
#
# See also:
# https://cmake.org/cmake/help/v3.18/command/add_library.html#object-libraries
# "Some native build systems (such as Xcode) may not like targets that have only
# object files, so consider adding at least one real source file to any target
# that references $<TARGET_OBJECTS:objlib>."
function(libwebp_add_stub_file TARGET)
set(stub_source_dir "${CMAKE_BINARY_DIR}")
set(stub_source_file "${stub_source_dir}/libwebp_${TARGET}_stub.c")
set(stub_source_code
"// Generated file. DO NOT EDIT!\n"
"// C source file created for target ${TARGET}.\n"
"void libwebp_${TARGET}_stub_function(void)\;\n"
"void libwebp_${TARGET}_stub_function(void) {}\n")
file(WRITE "${stub_source_file}" ${stub_source_code})
target_sources(${TARGET} PRIVATE ${stub_source_file})
endfunction()
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS" "")
add_library(sharpyuv ${WEBP_SHARPYUV_SRCS})
target_link_libraries(sharpyuv ${SHARPYUV_DEP_LIBRARIES})
set_version(sharpyuv/Makefile.am sharpyuv sharpyuv)
target_include_directories(
sharpyuv PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
set_target_properties(
sharpyuv
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\
${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h")
configure_pkg_config("sharpyuv/libsharpyuv.pc")
install(
TARGETS sharpyuv
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp/sharpyuv
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
${CMAKE_INSTALL_INCLUDEDIR}/webp
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(MSVC)
# avoid security warnings for e.g., fopen() used in the examples.
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_compile_options(-Wall)
endif()
include_directories(${WEBP_DEP_INCLUDE_DIRS})
add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
target_include_directories(webpdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
target_include_directories(webpdspdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputilsdecode OBJECT ${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS})
target_include_directories(webputilsdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(
webpdecoder $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdspdecode>
$<TARGET_OBJECTS:webputilsdecode>)
if(XCODE)
libwebp_add_stub_file(webpdecoder)
endif()
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
target_include_directories(
webpdecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
set_target_properties(
webpdecoder
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/libwebpdecoder.pc")
# Build the webp library.
add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
target_include_directories(
webpencode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
add_library(webpdsp OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS}
${WEBP_DSP_ENC_SRCS})
target_include_directories(webpdsp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputils OBJECT ${WEBP_UTILS_COMMON_SRCS} ${WEBP_UTILS_DEC_SRCS}
${WEBP_UTILS_ENC_SRCS})
target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
target_link_libraries(webp sharpyuv)
if(XCODE)
libwebp_add_stub_file(webp)
endif()
target_link_libraries(webp ${WEBP_DEP_LIBRARIES}) target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
target_include_directories(
webp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>)
set_target_properties(
webp
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
# Make sure the OBJECT libraries are built with position independent code (it is # Change the compile flags for SIMD files we use.
# not ON by default).
set_target_properties(webpdecode webpdspdecode webputilsdecode webpencode
webpdsp webputils PROPERTIES POSITION_INDEPENDENT_CODE ON)
configure_pkg_config("src/libwebp.pc")
# Build the webp demux library.
add_library(webpdemux ${WEBP_DEMUX_SRCS})
target_link_libraries(webpdemux webp)
target_include_directories(
webpdemux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
set_target_properties(
webpdemux
PROPERTIES
PUBLIC_HEADER
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/demux/libwebpdemux.pc")
set_version(src/Makefile.am webp webp)
set_version(src/Makefile.am webpdecoder webpdecoder)
set_version(src/demux/Makefile.am webpdemux webpdemux)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
string(REGEX MATCH "AC_INIT\\([^\n]*\\[[0-9\\.]+\\]" TMP ${CONFIGURE_FILE})
string(REGEX MATCH "[0-9\\.]+" PROJECT_VERSION ${TMP})
# Define the libraries to install.
list(APPEND INSTALLED_LIBRARIES webpdecoder webp webpdemux)
# Deal with SIMD. Change the compile flags for SIMD files we use.
list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH) list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH)
math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE
"${WEBP_SIMD_FILES_TO_INCLUDE_LENGTH}-1") "${WEBP_SIMD_FILES_TO_INCLUDE_LENGTH}-1"
)
foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE}) foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE) list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE)
list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG) list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG)
set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS set_source_files_properties(${FILE} PROPERTIES
${SIMD_COMPILE_FLAG}) COMPILE_FLAGS ${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)
set(WEBP_BUILD_GIF2WEBP OFF)
endif()
if(WEBP_BUILD_ANIM_UTILS AND NOT GIF_FOUND)
set(WEBP_BUILD_ANIM_UTILS OFF)
endif()
# Build the executables if asked for. # Build the executables if asked for.
if(WEBP_BUILD_ANIM_UTILS if(WEBP_BUILD_CWEBP OR WEBP_BUILD_DWEBP OR
OR WEBP_BUILD_CWEBP WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
OR WEBP_BUILD_DWEBP
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP
OR WEBP_BUILD_VWEBP
OR WEBP_BUILD_WEBPMUX
OR WEBP_BUILD_WEBPINFO)
# Example utility library. # Example utility library.
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS" set(exampleutil_SRCS
"example_util_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h) ${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.c
add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.h)
target_include_directories( add_library(exampleutil ${exampleutil_SRCS})
exampleutil PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>) target_link_libraries(exampleutil webp ${WEBP_DEP_LIBRARIES})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS" set(imageioutil_SRCS
"imageio_util_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/imageio/imageio_util.c
add_library(imageioutil STATIC ${IMAGEIOUTILS_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/imageio/imageio_util.h)
target_link_libraries(imageioutil webp) add_library(imageioutil ${imageioutil_SRCS})
target_link_libraries(exampleutil imageioutil) target_link_libraries(imageioutil ${WEBP_DEP_LIBRARIES})
# Image-decoding utility library. # Image-decoding utility library.
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS" set(imagedec_SRCS
"imagedec_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/examples/gifdec.c
add_library(imagedec STATIC ${IMAGEDEC_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/examples/gifdec.h
target_link_libraries(imagedec imageioutil webpdemux webp ${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_dec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_dec.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/jpegdec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/jpegdec.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/metadata.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/metadata.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/pngdec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/pngdec.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/tiffdec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/tiffdec.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/webpdec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/webpdec.h
${CMAKE_CURRENT_SOURCE_DIR}/imageio/wicdec.c
${CMAKE_CURRENT_SOURCE_DIR}/imageio/wicdec.h)
add_library(imagedec ${imagedec_SRCS})
target_link_libraries(imagedec webp ${WEBP_DEP_LIBRARIES}
${WEBP_DEP_IMG_LIBRARIES}) ${WEBP_DEP_IMG_LIBRARIES})
# Image-encoding utility library. # Image-encoding utility library.
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEENC_SRCS" set(imageenc_SRCS
"imageenc_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_enc.c
add_library(imageenc STATIC ${IMAGEENC_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/imageio/image_enc.h)
target_link_libraries(imageenc imageioutil webp) add_library(imageenc ${imageenc_SRCS})
target_link_libraries(imageenc webp imageioutil
set_property( ${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES})
TARGET exampleutil imageioutil imagedec imageenc
PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
endif() endif()
if(WEBP_BUILD_DWEBP) if(WEBP_BUILD_DWEBP)
# dwebp # dwebp
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "DWEBP_SRCS" "dwebp") include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
add_executable(dwebp ${DWEBP_SRCS}) add_executable(dwebp
target_link_libraries(dwebp exampleutil imagedec imageenc) ${CMAKE_CURRENT_SOURCE_DIR}/examples/dwebp.c
target_include_directories(dwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
install(TARGETS dwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) target_link_libraries(dwebp imagedec imageenc webp
exampleutil imageioutil
${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
)
endif() endif()
if(WEBP_BUILD_CWEBP) if(WEBP_BUILD_CWEBP)
# cwebp # cwebp
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" "cwebp") include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
add_executable(cwebp ${CWEBP_SRCS}) add_executable(cwebp
target_link_libraries(cwebp exampleutil imagedec webp) ${CMAKE_CURRENT_SOURCE_DIR}/examples/cwebp.c
target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(cwebp imagedec webp exampleutil imageioutil
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
endif() )
if(WEBP_BUILD_LIBWEBPMUX)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
add_library(libwebpmux ${WEBP_MUX_SRCS})
target_link_libraries(libwebpmux webp)
target_include_directories(libwebpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
set_version(src/mux/Makefile.am libwebpmux webpmux)
set_target_properties(
libwebpmux
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux)
list(APPEND INSTALLED_LIBRARIES libwebpmux)
configure_pkg_config("src/mux/libwebpmux.pc")
endif() endif()
if(WEBP_BUILD_GIF2WEBP) if(WEBP_BUILD_GIF2WEBP)
# gif2webp # gif2webp
include_directories(${WEBP_DEP_GIF_INCLUDE_DIRS}) include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "GIF2WEBP_SRCS" set(GIF2WEBP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/gif2webp.c)
"gif2webp") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "GIF2WEBP_SRCS")
add_executable(gif2webp ${GIF2WEBP_SRCS}) add_executable(gif2webp ${GIF2WEBP_SRCS})
target_link_libraries(gif2webp exampleutil imageioutil webp libwebpmux target_link_libraries(gif2webp imagedec webp exampleutil imageioutil
${WEBP_DEP_GIF_LIBRARIES}) ${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) )
install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
if(WEBP_BUILD_IMG2WEBP) if(WEBP_BUILD_IMG2WEBP)
# img2webp # img2webp
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "IMG2WEBP_SRCS" set(IMG2WEBP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/img2webp.c)
"img2webp") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "IMG2WEBP_SRCS")
add_executable(img2webp ${IMG2WEBP_SRCS}) add_executable(img2webp ${IMG2WEBP_SRCS})
target_link_libraries(img2webp exampleutil imagedec imageioutil webp target_link_libraries(img2webp imagedec webp exampleutil imageioutil
libwebpmux) ${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src )
${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
if(WEBP_BUILD_VWEBP)
# vwebp
find_package(GLUT)
if(GLUT_FOUND)
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "VWEBP_SRCS" "vwebp")
add_executable(vwebp ${VWEBP_SRCS})
target_link_libraries(
vwebp
${OPENGL_LIBRARIES}
exampleutil
GLUT::GLUT
imageioutil
webp
webpdemux)
target_include_directories(
vwebp PRIVATE ${GLUT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src
${OPENGL_INCLUDE_DIR})
install(TARGETS vwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
check_c_compiler_flag("-Wno-deprecated-declarations" HAS_NO_DEPRECATED)
if(HAS_NO_DEPRECATED)
target_compile_options(vwebp PRIVATE "-Wno-deprecated-declarations")
endif()
endif()
endif()
endif()
if(WEBP_BUILD_WEBPINFO)
# webpinfo
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPINFO_SRCS"
"webpinfo")
add_executable(webpinfo ${WEBPINFO_SRCS})
target_link_libraries(webpinfo exampleutil imageioutil)
target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src)
install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_WEBPMUX)
# webpmux
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS"
"webpmux")
add_executable(webpmux ${WEBPMUX_SRCS})
target_link_libraries(webpmux exampleutil imageioutil libwebpmux webp)
target_include_directories(webpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS webpmux RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_EXTRAS)
set(EXTRAS_MAKEFILE "${CMAKE_CURRENT_SOURCE_DIR}/extras")
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_EXTRAS_SRCS" "libwebpextras_la")
parse_makefile_am(${EXTRAS_MAKEFILE} "GET_DISTO_SRCS" "get_disto")
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality")
parse_makefile_am(${EXTRAS_MAKEFILE} "VWEBP_SDL_SRCS" "vwebp_sdl")
# libextras
add_library(extras STATIC ${WEBP_EXTRAS_SRCS})
target_include_directories(
extras PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src)
# get_disto
add_executable(get_disto ${GET_DISTO_SRCS})
target_link_libraries(get_disto imagedec)
target_include_directories(get_disto PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src)
# webp_quality
add_executable(webp_quality ${WEBP_QUALITY_SRCS})
target_link_libraries(webp_quality exampleutil imagedec extras)
target_include_directories(webp_quality PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
# vwebp_sdl
find_package(SDL)
if(WEBP_BUILD_VWEBP AND SDL_FOUND)
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
target_include_directories(
vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src ${SDL_INCLUDE_DIR})
set(WEBP_HAVE_SDL 1)
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
endif()
endif()
if(WEBP_BUILD_WEBP_JS)
# The default stack size changed from 5MB to 64KB in 3.1.27. See
# https://crbug.com/webp/614.
if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.27")
# TOTAL_STACK size was renamed to STACK_SIZE in 3.1.27. The old name was
# kept for compatibility, but prefer the new one in case it is removed in
# the future.
set(emscripten_stack_size "-sSTACK_SIZE=5MB")
else()
set(emscripten_stack_size "-sTOTAL_STACK=5MB")
endif()
# wasm2js does not support SIMD.
if(NOT WEBP_ENABLE_SIMD)
# JavaScript version
add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_js webpdecoder SDL)
target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set(WEBP_HAVE_SDL 1)
set_target_properties(
webp_js
PROPERTIES LINK_FLAGS "-sWASM=0 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-sEXPORTED_RUNTIME_METHODS=cwrap")
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
endif()
# WASM version
add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_wasm webpdecoder SDL)
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(
webp_wasm
PROPERTIES LINK_FLAGS "-sWASM=1 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-sEXPORTED_RUNTIME_METHODS=cwrap")
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
endif()
if(WEBP_BUILD_ANIM_UTILS)
# anim_diff
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DIFF_SRCS"
"anim_diff")
add_executable(anim_diff ${ANIM_DIFF_SRCS})
target_link_libraries(
anim_diff
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
# anim_dump
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DUMP_SRCS"
"anim_dump")
add_executable(anim_dump ${ANIM_DUMP_SRCS})
target_link_libraries(
anim_dump
exampleutil
imagedec
imageenc
imageioutil
webp
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
# Install the different headers and libraries.
install(
TARGETS ${INSTALLED_LIBRARIES}
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
set(ConfigPackageLocation ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/)
install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::
DESTINATION ${ConfigPackageLocation})
# Create the CMake version file.
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion)
# Create the Config file.
include(CMakePackageConfigHelpers)
# Fix libwebpmux reference. The target name libwebpmux is used for compatibility
# purposes, but the library mentioned in WebPConfig.cmake should be the
# unprefixed version. Note string(...) can be replaced with list(TRANSFORM ...)
# if cmake_minimum_required is >= 3.12.
string(REGEX REPLACE "libwebpmux" "webpmux" INSTALLED_LIBRARIES
"${INSTALLED_LIBRARIES}")
if(MSVC)
# For compatibility with nmake, MSVC builds use a custom prefix (lib) that
# needs to be included in the library name.
string(REGEX REPLACE "[A-Za-z0-9_]+" "${CMAKE_STATIC_LIBRARY_PREFIX}\\0"
INSTALLED_LIBRARIES "${INSTALLED_LIBRARIES}")
endif()
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake
INSTALL_DESTINATION ${ConfigPackageLocation}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
# Install the generated CMake files.
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake"
DESTINATION ${ConfigPackageLocation})
# Install the man pages.
set(MAN_PAGES
cwebp.1
dwebp.1
gif2webp.1
img2webp.1
vwebp.1
webpmux.1
webpinfo.1)
set(EXEC_BUILDS
"CWEBP"
"DWEBP"
"GIF2WEBP"
"IMG2WEBP"
"VWEBP"
"WEBPMUX"
"WEBPINFO")
list(LENGTH MAN_PAGES MAN_PAGES_LENGTH)
math(EXPR MAN_PAGES_RANGE "${MAN_PAGES_LENGTH} - 1")
foreach(I_MAN RANGE ${MAN_PAGES_RANGE})
list(GET EXEC_BUILDS ${I_MAN} EXEC_BUILD)
if(WEBP_BUILD_${EXEC_BUILD})
list(GET MAN_PAGES ${I_MAN} MAN_PAGE)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man/${MAN_PAGE}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc)
endif()
endforeach()

View File

@ -1,78 +0,0 @@
# 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.
## Sending patches
The basic git workflow for modifying libwebp code and sending for review is:
1. Get the latest version of the repository locally:
```sh
git clone https://chromium.googlesource.com/webm/libwebp && cd libwebp
```
2. Copy the commit-msg script into ./git/hooks (this will add an ID to all of
your commits):
```sh
curl -Lo .git/hooks/commit-msg https://chromium-review.googlesource.com/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg
```
3. Modify the local copy of libwebp. Make sure the code
[builds successfully](https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/building.md#cmake).
4. Choose a short and representative commit message:
```sh
git commit -a -m "Set commit message here"
```
5. Send the patch for review:
```sh
git push https://chromium-review.googlesource.com/webm/libwebp HEAD:refs/for/main
```
Go to https://chromium-review.googlesource.com to view your patch and
request a review from the maintainers.
See the
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
for additional details.
## Code Style
The C code style is based on the
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
`clang-format --style=Google`, though this project doesn't use the tool to
enforce the formatting.
CMake files are formatted with
[cmake-format](https://cmake-format.readthedocs.io/en/latest/). `cmake-format
-i` can be used to format individual files, it will use the settings from
`.cmake-format.py`.
## Community Guidelines
This project follows
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).

1154
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = sharpyuv src imageio man SUBDIRS = src imageio man
EXTRA_DIST = COPYING autogen.sh EXTRA_DIST = COPYING autogen.sh
if BUILD_EXTRAS if WANT_EXTRAS
SUBDIRS += extras SUBDIRS += extras
endif endif

View File

@ -5,7 +5,6 @@ LIBWEBPDECODER_BASENAME = libwebpdecoder
LIBWEBP_BASENAME = libwebp LIBWEBP_BASENAME = libwebp
LIBWEBPMUX_BASENAME = libwebpmux LIBWEBPMUX_BASENAME = libwebpmux
LIBWEBPDEMUX_BASENAME = libwebpdemux LIBWEBPDEMUX_BASENAME = libwebpdemux
LIBSHARPYUV_BASENAME = libsharpyuv
!IFNDEF ARCH !IFNDEF ARCH
!IF ! [ cl 2>&1 | find "x86" > NUL ] !IF ! [ cl 2>&1 | find "x86" > NUL ]
@ -29,14 +28,15 @@ PLATFORM_LDFLAGS = /SAFESEH
NOLOGO = /nologo NOLOGO = /nologo
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1 CCDEBUG = cl.exe $(NOLOGO) /Od /Gm /Zi /D_DEBUG /RTC1
CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c CFLAGS = /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:EMBED /NXCOMPAT /DYNAMICBASE LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /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
@ -53,6 +53,11 @@ OUTDIR = ..\obj\
OUTDIR = $(OBJDIR) OUTDIR = $(OBJDIR)
!ENDIF !ENDIF
!IF "$(HAVE_AVX2)" == "1"
CFLAGS = $(CFLAGS) /DWEBP_HAVE_AVX2
AVX2_FLAGS = /arch:AVX2
!ENDIF
############################################################## ##############################################################
# Runtime library configuration # Runtime library configuration
!IF "$(RTLIBCFG)" == "static" !IF "$(RTLIBCFG)" == "static"
@ -82,7 +87,6 @@ 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
@ -97,7 +101,6 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
!ELSE IF "$(CFG)" == "release-dynamic" !ELSE IF "$(CFG)" == "release-dynamic"
CC = $(CCNODBG) CC = $(CCNODBG)
RC = $(RCNODBG) RC = $(RCNODBG)
@ -111,7 +114,6 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
!ENDIF !ENDIF
!IF "$(STATICLIBBUILD)" == "TRUE" !IF "$(STATICLIBBUILD)" == "TRUE"
@ -121,28 +123,23 @@ LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME).lib
!ELSE IF "$(DLLBUILD)" == "TRUE" !ELSE IF "$(DLLBUILD)" == "TRUE"
CC = $(CC) /I$(DIROBJ) $(RTLIB) /DWEBP_DLL DLLINC = webp_dll.h
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME)_dll.lib
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
CFGSET = TRUE CFGSET = TRUE
!ENDIF !ENDIF
!IF "$(UNICODE)" == "1"
CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
!ENDIF
####################### #######################
# Usage # Usage
# #
!IF "$(CFGSET)" == "FALSE" !IF "$(CFGSET)" == "FALSE"
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>] !MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [UNICODE=1] [<target>] !MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
!MESSAGE !MESSAGE
!MESSAGE where <config> is one of: !MESSAGE where <config> is one of:
!MESSAGE - release-static - release static library !MESSAGE - release-static - release static library
@ -158,7 +155,6 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
!MESSAGE - all - build (de)mux-based targets for CFG !MESSAGE - all - build (de)mux-based targets for CFG
!MESSAGE - gif2webp - requires libgif & >= VS2013 !MESSAGE - gif2webp - requires libgif & >= VS2013
!MESSAGE - anim_diff - requires libgif & >= VS2013 !MESSAGE - anim_diff - requires libgif & >= VS2013
!MESSAGE - anim_dump
!MESSAGE !MESSAGE
!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'. !MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'.
!MESSAGE 'legacy' will produce a Windows 2000 compatible library. !MESSAGE 'legacy' will produce a Windows 2000 compatible library.
@ -178,15 +174,6 @@ 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_cpu.obj \
$(DIROBJ)\sharpyuv\sharpyuv_csp.obj \
$(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
$(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
$(DIROBJ)\sharpyuv\sharpyuv_neon.obj \
$(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \
DEC_OBJS = \ DEC_OBJS = \
$(DIROBJ)\dec\alpha_dec.obj \ $(DIROBJ)\dec\alpha_dec.obj \
$(DIROBJ)\dec\buffer_dec.obj \ $(DIROBJ)\dec\buffer_dec.obj \
@ -228,7 +215,6 @@ 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 \
@ -240,21 +226,21 @@ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\upsampling_msa.obj \ $(DIROBJ)\dsp\upsampling_msa.obj \
$(DIROBJ)\dsp\upsampling_neon.obj \ $(DIROBJ)\dsp\upsampling_neon.obj \
$(DIROBJ)\dsp\upsampling_sse2.obj \ $(DIROBJ)\dsp\upsampling_sse2.obj \
$(DIROBJ)\dsp\upsampling_sse41.obj \
$(DIROBJ)\dsp\yuv.obj \ $(DIROBJ)\dsp\yuv.obj \
$(DIROBJ)\dsp\yuv_mips32.obj \ $(DIROBJ)\dsp\yuv_mips32.obj \
$(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \ $(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \
$(DIROBJ)\dsp\yuv_neon.obj \
$(DIROBJ)\dsp\yuv_sse2.obj \ $(DIROBJ)\dsp\yuv_sse2.obj \
$(DIROBJ)\dsp\yuv_sse41.obj \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\argb.obj \
$(DIROBJ)\dsp\argb_mips_dsp_r2.obj \
$(DIROBJ)\dsp\argb_sse2.obj \
$(DIROBJ)\dsp\cost.obj \ $(DIROBJ)\dsp\cost.obj \
$(DIROBJ)\dsp\cost_mips32.obj \ $(DIROBJ)\dsp\cost_mips32.obj \
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \ $(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
$(DIROBJ)\dsp\cost_neon.obj \
$(DIROBJ)\dsp\cost_sse2.obj \ $(DIROBJ)\dsp\cost_sse2.obj \
$(DIROBJ)\dsp\enc.obj \ $(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_avx2.obj \
$(DIROBJ)\dsp\enc_mips32.obj \ $(DIROBJ)\dsp\enc_mips32.obj \
$(DIROBJ)\dsp\enc_mips_dsp_r2.obj \ $(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
$(DIROBJ)\dsp\enc_msa.obj \ $(DIROBJ)\dsp\enc_msa.obj \
@ -268,8 +254,6 @@ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\lossless_enc_neon.obj \ $(DIROBJ)\dsp\lossless_enc_neon.obj \
$(DIROBJ)\dsp\lossless_enc_sse2.obj \ $(DIROBJ)\dsp\lossless_enc_sse2.obj \
$(DIROBJ)\dsp\lossless_enc_sse41.obj \ $(DIROBJ)\dsp\lossless_enc_sse41.obj \
$(DIROBJ)\dsp\ssim.obj \
$(DIROBJ)\dsp\ssim_sse2.obj \
EX_ANIM_UTIL_OBJS = \ EX_ANIM_UTIL_OBJS = \
$(DIROBJ)\examples\anim_util.obj \ $(DIROBJ)\examples\anim_util.obj \
@ -279,7 +263,6 @@ IMAGEIO_DEC_OBJS = \
$(DIROBJ)\imageio\jpegdec.obj \ $(DIROBJ)\imageio\jpegdec.obj \
$(DIROBJ)\imageio\metadata.obj \ $(DIROBJ)\imageio\metadata.obj \
$(DIROBJ)\imageio\pngdec.obj \ $(DIROBJ)\imageio\pngdec.obj \
$(DIROBJ)\imageio\pnmdec.obj \
$(DIROBJ)\imageio\tiffdec.obj \ $(DIROBJ)\imageio\tiffdec.obj \
$(DIROBJ)\imageio\webpdec.obj \ $(DIROBJ)\imageio\webpdec.obj \
$(DIROBJ)\imageio\wicdec.obj \ $(DIROBJ)\imageio\wicdec.obj \
@ -296,10 +279,10 @@ EX_UTIL_OBJS = \
ENC_OBJS = \ ENC_OBJS = \
$(DIROBJ)\enc\alpha_enc.obj \ $(DIROBJ)\enc\alpha_enc.obj \
$(DIROBJ)\enc\analysis_enc.obj \ $(DIROBJ)\enc\analysis_enc.obj \
$(DIROBJ)\enc\backward_references_cost_enc.obj \
$(DIROBJ)\enc\backward_references_enc.obj \ $(DIROBJ)\enc\backward_references_enc.obj \
$(DIROBJ)\enc\config_enc.obj \ $(DIROBJ)\enc\config_enc.obj \
$(DIROBJ)\enc\cost_enc.obj \ $(DIROBJ)\enc\cost_enc.obj \
$(DIROBJ)\enc\delta_palettization_enc.obj \
$(DIROBJ)\enc\filter_enc.obj \ $(DIROBJ)\enc\filter_enc.obj \
$(DIROBJ)\enc\frame_enc.obj \ $(DIROBJ)\enc\frame_enc.obj \
$(DIROBJ)\enc\histogram_enc.obj \ $(DIROBJ)\enc\histogram_enc.obj \
@ -348,13 +331,12 @@ 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) \ LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_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)
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) $(LIBSHARPYUV) OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
!IF "$(ARCH)" == "ARM" !IF "$(ARCH)" == "ARM"
ex: $(OUT_LIBS) ex: $(OUT_LIBS)
all: ex all: ex
@ -362,8 +344,7 @@ all: ex
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \ EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \
$(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \ $(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \
$(DIRBIN)\webp_quality.exe $(DIRBIN)\vwebp_sdl.exe \ $(DIRBIN)\webp_quality.exe
$(DIRBIN)\webpinfo.exe
ex: $(OUT_LIBS) $(OUT_EXAMPLES) ex: $(OUT_LIBS) $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES) all: ex $(EXTRA_EXAMPLES)
@ -371,68 +352,53 @@ all: ex $(EXTRA_EXAMPLES)
# C99 support which is only available from VS2013 onward. # C99 support which is only available from VS2013 onward.
gif2webp: $(DIRBIN)\gif2webp.exe gif2webp: $(DIRBIN)\gif2webp.exe
anim_diff: $(DIRBIN)\anim_diff.exe anim_diff: $(DIRBIN)\anim_diff.exe
anim_dump: $(DIRBIN)\anim_dump.exe
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS) $(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) $(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS)
$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS) $(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX) $(LIBSHARPYUV)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS) $(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS) $(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS) $(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX) $(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
$(DIRBIN)\gif2webp.exe: $(LIBWEBP) $(DIRBIN)\gif2webp.exe: $(LIBWEBP)
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS) $(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) $(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\webp_to_sdl.obj
$(DIRBIN)\vwebp_sdl.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX) $(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP) $(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX) $(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS) $(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP) $(LIBSHARPYUV)
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj $(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj $(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj
$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) $(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) $(LIBWEBP)
# EXTRA_OBJS requires private symbols from dsp. Explicitly add those when
# building libwebp as a dll.
!IF "$(DLLBUILD)" == "TRUE"
$(DIRBIN)\webp_quality.exe: $(DSP_DEC_OBJS)
!ENDIF
$(DIRBIN)\webp_quality.exe: $(LIBWEBP)
$(DIRBIN)\webpinfo.exe: $(DIROBJ)\examples\webpinfo.obj
$(DIRBIN)\webpinfo.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\webpinfo.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\webpinfo.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP) $(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS) $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS)
$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS) $(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
!ENDIF # ARCH == ARM !ENDIF # ARCH == ARM
$(LIBSHARPYUV): $(LIBSHARPYUV_OBJS) experimental:
$(MAKE) /f Makefile.vc \
CFG=$(CFG) \
CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS) $(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBSHARPYUV) $(LIBWEBP): $(LIBWEBP_OBJS)
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS) $(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS) $(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
$(OUTPUT_DIRS)
!IF "$(DLLBUILD)" == "TRUE" !IF "$(DLLBUILD)" == "TRUE"
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(DIROBJ)\$(DLLINC)
{$(DIROBJ)}.c{$(DIROBJ)}.obj: {$(DIROBJ)}.c{$(DIROBJ)}.obj:
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
@ -442,20 +408,20 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \
$(RC) /fo$@ $< $(RC) /fo$@ $<
{src\mux}.rc{$(DIROBJ)\mux}.res: {src\mux}.rc{$(DIROBJ)\mux}.res:
$(RC) /fo$@ $< $(RC) /fo$@ $<
{sharpyuv}.rc{$(DIROBJ)\sharpyuv}.res:
$(RC) /fo$@ $<
$(LIBSHARPYUV): $(DIROBJ)\sharpyuv\$(LIBSHARPYUV_BASENAME:_debug=).res $(LIBWEBP): $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
$(LIBWEBP): $(LIBSHARPYUV) $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res $(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res $(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res $(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $** $(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
clean::
@-erase /s $(DIROBJ)\$(DLLINC) 2> NUL
!ELSE !ELSE
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKLIB) /out:$@ $** $(LNKLIB) /out:$@ $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
!ENDIF !ENDIF
@ -463,15 +429,22 @@ $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
$(OUTPUT_DIRS): $(OUTPUT_DIRS):
@if not exist "$(@)" mkdir "$(@)" @if not exist "$(@)" mkdir "$(@)"
# generate a helper include to define WEBP_EXTERN suitable for the DLL build
$(DIROBJ)\$(DLLINC):
@echo #ifndef WEBP_DLL_H_ > $@
@echo #define WEBP_DLL_H_ >> $@
@echo #define WEBP_EXTERN(type) __declspec(dllexport) type >> $@
@echo #endif /* WEBP_DLL_H_ */ >> $@
.SUFFIXES: .c .obj .res .exe .SUFFIXES: .c .obj .res .exe
# File-specific flag builds. Note batch rules take precedence over wildcards, # File-specific flag builds. Note batch rules take precedence over wildcards,
# so for now name each file individually. # so for now name each file individually.
$(DIROBJ)\dsp\enc_avx2.obj: src\dsp\enc_avx2.c
$(CC) $(CFLAGS) $(AVX2_FLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ \
src\dsp\$(@B).c
$(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c $(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c /Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c $(DIROBJ)\examples\anim_util.obj: examples\anim_util.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c /Fo$(DIROBJ)\examples\ examples\$(@B).c
@ -488,8 +461,6 @@ $(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::
@ -503,16 +474,17 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
{src\utils}.c{$(DIROBJ)\utils}.obj:: {src\utils}.c{$(DIROBJ)\utils}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib
!IF "$(UNICODE)" == "1"
LNKLIBS = $(LNKLIBS) Shell32.lib
!ENDIF
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe: {$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) $(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
ole32.lib windowscodecs.lib shlwapi.lib
$(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe: {$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) $(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
ole32.lib windowscodecs.lib shlwapi.lib
$(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest
clean:: clean::
@-erase /s $(DIROBJ)\*.dll 2> NUL @-erase /s $(DIROBJ)\*.dll 2> NUL

139
NEWS
View File

@ -1,142 +1,3 @@
- 9/13/2023: version 1.3.2
This is a binary compatible release.
* security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
- 6/23/2023: version 1.3.1
This is a binary compatible release.
* security fixes for lossless encoder (#603, chromium: #1420107, #1455619,
CVE-2023-1999)
* improve error reporting through WebPPicture error codes
* fix upsampling for RGB565 and RGBA4444 in NEON builds
* img2webp: add -sharp_yuv & -near_lossless
* Windows builds:
- fix compatibility with clang-cl (#607)
- improve Arm64 performance with cl.exe
- add Arm64EC support
* fix webp_js with emcc >= 3.1.27 (stack size change, #614)
* CMake fixes (#592, #610, #612)
* further updates to the container and lossless bitstream docs (#581, #611)
- 12/16/2022: version 1.3.0
This is a binary compatible release.
* add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
functionality to other libraries; libwebp now depends on this library
* major updates to the container and lossless bitstream docs (#448, #546,
#551)
* miscellaneous warning, bug & build fixes (#576, #583, #584)
- 8/4/2022: version 1.2.4
This is a binary compatible release.
* restore CMake libwebpmux target name for compatibility with 1.2.2 (#575)
* fix lossless crunch mode encoding with WEBP_REDUCE_SIZE
(chromium: #1345547, #1345595, #1345772, #1345804)
- 6/30/2022: version 1.2.3
This is a binary compatible release.
* security fix for lossless encoder (#565, chromium:1313709)
* improved progress granularity in WebPReportProgress() when using lossless
* improved precision in Sharp YUV (-sharp_yuv) conversion
* many corrections to webp-lossless-bitstream-spec.txt (#551)
* crash/leak fixes on error/OOM and other bug fixes (#558, #563, #569, #573)
- 1/11/2022: version 1.2.2
This is a binary compatible release.
* webpmux: add "-set bgcolor A,R,G,B"
* add ARM64 NEON support for MSVC builds (#539)
* fix duplicate include error in Xcode when using multiple XCFrameworks in a
project (#542)
* doc updates and bug fixes (#538, #544, #548, #550)
- 7/20/2021: version 1.2.1
This is a binary compatible release.
* minor lossless encoder improvements and x86 color conversion speed up
* add ARM64 simulator support to xcframeworkbuild.sh (#510)
* further security related hardening in libwebp & examples
(issues: #497, #508, #518)
(chromium: #1196480, #1196773, #1196775, #1196777, #1196778, #1196850)
(oss-fuzz: #28658, #28978)
* toolchain updates and bug fixes (#498, #501, #502, #504, #505, #506, #509,
#533)
* use more inclusive language within the source (#507)
- 12/23/2020: version 1.2.0
* API changes:
- libwebp:
encode.h: add a qmin / qmax range for quality factor (cwebp adds -qrange)
* lossless encoder improvements
* SIMD support for Wasm builds
* add xcframeworkbuild.sh, supports Mac Catalyst builds
* import fuzzers from oss-fuzz & chromium (#409)
* webpmux: add an '-set loop <value>' option (#494)
* toolchain updates and bug fixes (#449, #463, #470, #475, #477, #478, #479,
#488, #491)
- 12/18/2019: version 1.1.0
* API changes:
- libwebp:
WebPMalloc (issue #442)
- extras:
WebPUnmultiplyARGB
* alpha decode fix (issue #439)
* toolchain updates and bug fixes
(chromium: #1026858, #1027136, #1027409, #1028620, #1028716, #995200)
(oss-fuzz: #19430, #19447)
- 7/4/2019: version 1.0.3
This is a binary compatible release.
* resize fixes for Nx1 sizes and the addition of non-opaque alpha values for
odd sizes (issues #418, #434)
* lossless encode/decode performance improvements
* lossy compression performance improvement at low quality levels with flat
content (issue #432)
* python swig files updated to support python 3
Tool updates:
vwebp will now preserve the aspect ratio of images that exceed monitor
resolution by scaling the image to fit (issue #433)
- 1/14/2019: version 1.0.2
This is a binary compatible release.
* (Windows) unicode file support in the tools (linux and mac already had
support, issue #398)
* lossless encoder speedups
* lossy encoder speedup on ARM
* lossless multi-threaded security fix (chromium:917029)
- 11/2/2018: version 1.0.1
This is a binary compatible release.
* lossless encoder speedups
* big-endian fix for alpha decoding (issue #393)
* gif2webp fix for loop count=65535 transcode (issue #382)
* further security related hardening in libwebp & libwebpmux
(issues #383, #385, #386, #387, #388, #391)
(oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170,
#9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349,
#10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152)
* miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400)
- 4/2/2018: version 1.0.0
This is a binary compatible release.
* lossy encoder improvements to avoid chroma shifts in various circumstances
(issues #308, #340)
* big-endian fixes for decode, RGBA import and WebPPictureDistortion
Tool updates:
gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
web browsers, transcoding tools (issue #379)
img2webp, webpmux - allow options to be passed in via a file (issue #355)
- 11/24/2017: version 0.6.1
This is a binary compatible release.
* lossless performance and compression improvements + a new 'cruncher' mode
(-m 6 -q 100)
* ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
* webp-js: emscripten/webassembly based javascript decoder
* miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
#363)
Tool updates / additions:
added webpinfo - prints file format information (issue #330)
gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
'-loop_compatibility' can be used for the old behavior
- 1/26/2017: version 0.6.0 - 1/26/2017: version 0.6.0
* lossless performance and compression improvements * lossless performance and compression improvements
* miscellaneous performance improvements (SSE2, NEON, MSA) * miscellaneous performance improvements (SSE2, NEON, MSA)

View File

@ -1,245 +0,0 @@
# 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

750
README Normal file
View File

@ -0,0 +1,750 @@
__ __ ____ ____ ____
/ \\/ \/ _ \/ _ )/ _ \
\ / __/ _ \ __/
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v0.6.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:
------
The support for CMake is minimal: it only helps you compile libwebp, cwebp and
dwebp.
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
configure script.
mkdir build && cd build && cmake ../
make
make install
If you also want cwebp or dwebp, you will need to enable them through CMake:
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
or through your favorite interface (like ccmake or cmake-qt-gui).
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.
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)
-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]
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
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
-mt .......... use multi-threading
-info ........ print info
-h ........... this help message
Keyboard shortcuts:
'c' ................ toggle use of color profile
'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
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
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)
-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
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

View File

@ -1,53 +0,0 @@
# WebP Codec
```
__ __ ____ ____ ____
/ \\/ \/ _ \/ _ )/ _ \
\ / __/ _ \ __/
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.3.2
```
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

223
README.mux Normal file
View File

@ -0,0 +1,223 @@
 __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.4.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
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:
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.
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).
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

View File

@ -74,22 +74,12 @@ model {
cCompiler.args "-frename-registers -s" cCompiler.args "-frename-registers -s"
} }
} }
// mips32 fails to build with clang from r14b
// https://bugs.chromium.org/p/webp/issues/detail?id=343
if (toolChain in Clang) {
if (getTargetPlatform() == "mips") {
cCompiler.args "-no-integrated-as"
}
}
// Check for NEON usage. // Check for NEON usage.
if (getTargetPlatform() == "arm") { if (getTargetPlatform() == "arm" || getTargetPlatform() == "arm64") {
NEON = "c.neon" NEON = "c.neon"
cCompiler.define "HAVE_CPU_FEATURES_H"
} else { } else {
NEON = "c" NEON = "c"
} }
cCompiler.args "-I" + file(".").absolutePath
} }
// Link to pthread for shared libraries. // Link to pthread for shared libraries.
withType(SharedLibraryBinarySpec) { withType(SharedLibraryBinarySpec) {
@ -105,14 +95,6 @@ model {
sources { sources {
c { c {
source { source {
srcDir "sharpyuv"
include "sharpyuv.c"
include "sharpyuv_cpu.c"
include "sharpyuv_csp.c"
include "sharpyuv_dsp.c"
include "sharpyuv_gamma.c"
include "sharpyuv_neon.c"
include "sharpyuv_sse2.c"
srcDir "src/dec" srcDir "src/dec"
include "alpha_dec.c" include "alpha_dec.c"
include "buffer_dec.c" include "buffer_dec.c"
@ -130,6 +112,9 @@ model {
include "alpha_processing_neon.$NEON" include "alpha_processing_neon.$NEON"
include "alpha_processing_sse2.c" include "alpha_processing_sse2.c"
include "alpha_processing_sse41.c" include "alpha_processing_sse41.c"
include "argb.c"
include "argb_mips_dsp_r2.c"
include "argb_sse2.c"
include "cpu.c" include "cpu.c"
include "dec.c" include "dec.c"
include "dec_clip_tables.c" include "dec_clip_tables.c"
@ -149,7 +134,6 @@ 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"
@ -161,13 +145,10 @@ model {
include "upsampling_msa.c" include "upsampling_msa.c"
include "upsampling_neon.$NEON" include "upsampling_neon.$NEON"
include "upsampling_sse2.c" include "upsampling_sse2.c"
include "upsampling_sse41.c"
include "yuv.c" include "yuv.c"
include "yuv_mips32.c" include "yuv_mips32.c"
include "yuv_mips_dsp_r2.c" include "yuv_mips_dsp_r2.c"
include "yuv_neon.$NEON"
include "yuv_sse2.c" include "yuv_sse2.c"
include "yuv_sse41.c"
srcDir "src/utils" srcDir "src/utils"
include "bit_reader_utils.c" include "bit_reader_utils.c"
include "color_cache_utils.c" include "color_cache_utils.c"
@ -182,9 +163,9 @@ model {
include "cost.c" include "cost.c"
include "cost_mips32.c" include "cost_mips32.c"
include "cost_mips_dsp_r2.c" include "cost_mips_dsp_r2.c"
include "cost_neon.$NEON"
include "cost_sse2.c" include "cost_sse2.c"
include "enc.c" include "enc.c"
include "enc_avx2.c"
include "enc_mips32.c" include "enc_mips32.c"
include "enc_mips_dsp_r2.c" include "enc_mips_dsp_r2.c"
include "enc_msa.c" include "enc_msa.c"
@ -198,15 +179,13 @@ model {
include "lossless_enc_neon.$NEON" include "lossless_enc_neon.$NEON"
include "lossless_enc_sse2.c" include "lossless_enc_sse2.c"
include "lossless_enc_sse41.c" include "lossless_enc_sse41.c"
include "ssim.c"
include "ssim_sse2.c"
srcDir "src/enc" srcDir "src/enc"
include "alpha_enc.c" include "alpha_enc.c"
include "analysis_enc.c" include "analysis_enc.c"
include "backward_references_cost_enc.c"
include "backward_references_enc.c" include "backward_references_enc.c"
include "config_enc.c" include "config_enc.c"
include "cost_enc.c" include "cost_enc.c"
include "delta_palettization_enc.c"
include "filter_enc.c" include "filter_enc.c"
include "frame_enc.c" include "frame_enc.c"
include "histogram_enc.c" include "histogram_enc.c"
@ -298,7 +277,6 @@ model {
imagedec(NativeLibrarySpec) { imagedec(NativeLibrarySpec) {
binaries { binaries {
all { all {
lib library: "webpdemux", linkage: "static"
lib library: "webp", linkage: "static" lib library: "webp", linkage: "static"
} }
} }
@ -310,7 +288,6 @@ model {
include "jpegdec.c" include "jpegdec.c"
include "metadata.c" include "metadata.c"
include "pngdec.c" include "pngdec.c"
include "pnmdec.c"
include "tiffdec.c" include "tiffdec.c"
include "webpdec.c" include "webpdec.c"
} }
@ -341,7 +318,6 @@ model {
lib library: "example_util", linkage: "static" lib library: "example_util", linkage: "static"
lib library: "imagedec", linkage: "static" lib library: "imagedec", linkage: "static"
lib library: "imageio_util", linkage: "static" lib library: "imageio_util", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp", linkage: "static" lib library: "webp", linkage: "static"
} }
} }
@ -362,7 +338,6 @@ model {
lib library: "imagedec", linkage: "static" lib library: "imagedec", linkage: "static"
lib library: "imageenc", linkage: "static" lib library: "imageenc", linkage: "static"
lib library: "imageio_util", linkage: "static" lib library: "imageio_util", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp" lib library: "webp"
} }
} }
@ -402,7 +377,6 @@ model {
lib library: "imagedec", linkage: "static" lib library: "imagedec", linkage: "static"
lib library: "imageio_util", linkage: "static" lib library: "imageio_util", linkage: "static"
lib library: "webpmux", linkage: "static" lib library: "webpmux", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp" lib library: "webp"
} }
} }
@ -415,24 +389,6 @@ model {
} }
} }
} }
webpinfo_example(NativeExecutableSpec) {
binaries {
all {
lib library: "example_util", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webp"
}
}
sources {
c {
source {
srcDir "./examples"
include "webpinfo.c"
}
}
}
}
} }
tasks { tasks {
// Task to test all possible configurations. // Task to test all possible configurations.
@ -441,3 +397,8 @@ model {
} }
} }
} }
// Task to generate the wrapper.
task wrapper(type: Wrapper) {
gradleVersion = '2.13'
}

View File

@ -1,18 +0,0 @@
set(WebP_VERSION @PROJECT_VERSION@)
set(WEBP_VERSION ${WebP_VERSION})
@PACKAGE_INIT@
if(@WEBP_USE_THREAD@)
include(CMakeFindDependencyMacro)
find_dependency(Threads REQUIRED)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
set_and_check(WebP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
check_required_components(WebP)

141
cmake/config.h.cmake Normal file
View File

@ -0,0 +1,141 @@
# Generate the config.h to compile with specific intrinsics / libs.
## Check for compiler options.
include(CheckCSourceCompiles)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap16(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP16
)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap32(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP32
)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap64(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP64
)
## Check for libraries.
find_package(Threads)
if(Threads_FOUND)
if(CMAKE_USE_PTHREADS_INIT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
endif()
foreach(PTHREAD_TEST HAVE_PTHREAD_PRIO_INHERIT PTHREAD_CREATE_UNDETACHED)
check_c_source_compiles("
#include <pthread.h>
int main (void) {
int attr = ${PTHREAD_TEST};
return attr;
}
" ${PTHREAD_TEST}
)
endforeach()
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
# TODO: this seems unused, check with autotools.
set(LT_OBJDIR ".libs/")
# Only useful for vwebp, so useless for now.
# find_package(OpenGL)
# set(WEBP_HAVE_GL ${OPENGL_FOUND})
# set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS})
# set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} ${OPENGL_LIBRARIES})
# Find the standard C math library.
find_library(MATH_LIBRARY NAMES m)
if(MATH_LIBRARY)
list(APPEND WEBP_DEP_LIBRARIES ${MATH_LIBRARY})
endif()
# Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS)
foreach(I_LIB PNG JPEG TIFF GIF)
find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIRS})
endif()
endforeach()
## Check for specific headers.
include(CheckIncludeFiles)
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
check_include_files(dlfcn.h HAVE_DLFCN_H)
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(memory.h HAVE_MEMORY_H)
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(stdlib.h HAVE_STDLIB_H)
check_include_files(strings.h HAVE_STRINGS_H)
check_include_files(string.h HAVE_STRING_H)
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(wincodec.h HAVE_WINCODEC_H)
check_include_files(windows.h HAVE_WINDOWS_H)
# Windows specifics
if(HAVE_WINCODEC_H)
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
endif()
## Check for SIMD extensions.
include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
## Define extra info.
set(PACKAGE ${PROJECT_NAME})
set(PACKAGE_NAME ${PROJECT_NAME})
# Read from configure.ac.
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]"
CONFIGURE_AC_PACKAGE_INFO ${CONFIGURE_AC}
)
function(strip_bracket VAR)
string(LENGTH ${${VAR}} TMP_LEN)
math(EXPR TMP_LEN ${TMP_LEN}-2)
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
endfunction()
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
strip_bracket(PACKAGE_VERSION)
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
strip_bracket(PACKAGE_BUGREPORT)
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
strip_bracket(PACKAGE_URL)
# Build more info.
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME ${PACKAGE_NAME})
set(VERSION ${PACKAGE_VERSION})
## Generate the config.h header.
configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/webp/config.h)
add_definitions(-DHAVE_CONFIG_H)
# The webp folder is included as we reference config.h as
# ../webp/config.h or webp/config.h
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/include/webp
)

View File

@ -13,8 +13,8 @@
/* Set to 1 if __builtin_bswap64 is available */ /* Set to 1 if __builtin_bswap64 is available */
#cmakedefine HAVE_BUILTIN_BSWAP64 1 #cmakedefine HAVE_BUILTIN_BSWAP64 1
/* Define to 1 if you have the <cpu-features.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_CPU_FEATURES_H 1 #cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <GLUT/glut.h> header file. */ /* Define to 1 if you have the <GLUT/glut.h> header file. */
#cmakedefine HAVE_GLUT_GLUT_H 1 #cmakedefine HAVE_GLUT_GLUT_H 1
@ -22,12 +22,39 @@
/* Define to 1 if you have the <GL/glut.h> header file. */ /* Define to 1 if you have the <GL/glut.h> header file. */
#cmakedefine HAVE_GL_GLUT_H 1 #cmakedefine HAVE_GL_GLUT_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H 1
/* Define to 1 if you have the <OpenGL/glut.h> header file. */ /* Define to 1 if you have the <OpenGL/glut.h> header file. */
#cmakedefine HAVE_OPENGL_GLUT_H 1 #cmakedefine HAVE_OPENGL_GLUT_H 1
/* Have PTHREAD_PRIO_INHERIT. */
#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
/* Define to 1 if you have the <shlwapi.h> header file. */ /* Define to 1 if you have the <shlwapi.h> header file. */
#cmakedefine HAVE_SHLWAPI_H 1 #cmakedefine HAVE_SHLWAPI_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1 #cmakedefine HAVE_UNISTD_H 1
@ -63,9 +90,22 @@
/* Define to the version of this package. */ /* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine PTHREAD_CREATE_JOINABLE 1
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
/* Version number of package */ /* Version number of package */
#cmakedefine VERSION "@VERSION@" #cmakedefine VERSION "@VERSION@"
/* Enable experimental code */
#cmakedefine WEBP_EXPERIMENTAL_FEATURES 1
/* Set to 1 if AVX2 is supported */
#cmakedefine WEBP_HAVE_AVX2 1
/* Set to 1 if GIF library is installed */ /* Set to 1 if GIF library is installed */
#cmakedefine WEBP_HAVE_GIF 1 #cmakedefine WEBP_HAVE_GIF 1
@ -75,19 +115,9 @@
/* Set to 1 if JPEG library is installed */ /* Set to 1 if JPEG library is installed */
#cmakedefine WEBP_HAVE_JPEG 1 #cmakedefine WEBP_HAVE_JPEG 1
/* Set to 1 if NEON is supported */
#cmakedefine WEBP_HAVE_NEON
/* Set to 1 if runtime detection of NEON is enabled */
/* TODO: handle properly in CMake */
#cmakedefine WEBP_HAVE_NEON_RTCD
/* Set to 1 if PNG library is installed */ /* Set to 1 if PNG library is installed */
#cmakedefine WEBP_HAVE_PNG 1 #cmakedefine WEBP_HAVE_PNG 1
/* Set to 1 if SDL library is installed */
#cmakedefine WEBP_HAVE_SDL 1
/* Set to 1 if SSE2 is supported */ /* Set to 1 if SSE2 is supported */
#cmakedefine WEBP_HAVE_SSE2 1 #cmakedefine WEBP_HAVE_SSE2 1
@ -97,9 +127,6 @@
/* Set to 1 if TIFF library is installed */ /* Set to 1 if TIFF library is installed */
#cmakedefine WEBP_HAVE_TIFF 1 #cmakedefine WEBP_HAVE_TIFF 1
/* Enable near lossless encoding */
#cmakedefine WEBP_NEAR_LOSSLESS 1
/* Undefine this to disable thread support. */ /* Undefine this to disable thread support. */
#cmakedefine WEBP_USE_THREAD 1 #cmakedefine WEBP_USE_THREAD 1

View File

@ -1,25 +1,8 @@
# Copyright (c) 2021 Google LLC. ## Check for SIMD extensions.
#
# 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. function(webp_check_compiler_flag WEBP_SIMD_FLAG)
include(CMakePushCheckState)
function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
if(NOT ENABLE_SIMD)
message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.")
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
return()
endif()
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE) unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state() check_c_source_compiles("
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
check_c_source_compiles(
"
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\" #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
int main(void) { int main(void) {
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG}) #if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
@ -27,9 +10,8 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
#endif #endif
return 0; return 0;
} }
" " WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}
WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) )
cmake_pop_check_state()
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE) set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
else() else()
@ -38,34 +20,28 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
endfunction() endfunction()
# those are included in the names of WEBP_USE_* in c++ code. # those are included in the names of WEBP_USE_* in c++ code.
set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA") set(WEBP_SIMD_FLAGS "SSE2;SSE41;AVX2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FILE_EXTENSIONS set(WEBP_SIMD_FILE_EXTENSIONS "_sse2.c;_sse41.c;_avx2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
"_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c") if(MSVC)
if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC does not have a SSE4 flag but AVX2 support implies
# With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2 # SSE4 support.
# or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4 set(SIMD_ENABLE_FLAGS "/arch:SSE2;/arch:AVX2;/arch:AVX2;;;;")
# flag, but an AVX one. Using that with SSE4 code risks generating illegal
# instructions when used on machines with SSE4 only. The flags are left for
# older (untested) versions to avoid any potential compatibility issues.
if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:")
set(SIMD_ENABLE_FLAGS)
else()
set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;")
endif()
set(SIMD_DISABLE_FLAGS) set(SIMD_DISABLE_FLAGS)
else() else()
set(SIMD_ENABLE_FLAGS "-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa") set(SIMD_ENABLE_FLAGS "-msse2;-msse4.1;-mavx2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
set(SIMD_DISABLE_FLAGS "-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa") set(SIMD_DISABLE_FLAGS "-mno-sse2;-mno-sse4.1;-mno-avx2;;-mno-dspr2;;-mno-msa")
endif() endif()
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
set(WEBP_SIMD_FILES_TO_INCLUDE) set(WEBP_SIMD_FILES_TO_INCLUDE)
set(WEBP_SIMD_FLAGS_TO_INCLUDE) set(WEBP_SIMD_FLAGS_TO_INCLUDE)
if(${ANDROID}) if(${ANDROID})
if(${ANDROID_ABI} STREQUAL "armeabi-v7a") if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
# This is because Android studio uses the configuration "-march=armv7-a # This is because Android studio uses the configuration
# -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon # "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
# optimizations but should (as this configuration does not exist anymore). # that does not trigger neon optimizations but should
# (as this configuration does not exist anymore).
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
endif() endif()
endif() endif()
@ -74,40 +50,25 @@ list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1") math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE}) foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
# With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source
# will fail to compile.
if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2)
break()
endif()
list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG) list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
# First try with no extra flag added as the compiler might have default flags # First try with no extra flag added as the compiler might have default flags
# (especially on Android). # (especially on Android).
unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE) unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS) set(CMAKE_REQUIRED_FLAGS)
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) webp_check_compiler_flag(${WEBP_SIMD_FLAG})
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG}) if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
if(EMSCRIPTEN)
set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}")
endif()
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG}) set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) webp_check_compiler_flag(${WEBP_SIMD_FLAG})
else()
if(MSVC AND SIMD_ENABLE_FLAGS)
# The detection for SSE2/SSE4 support under MSVC is based on the compiler
# version so e.g., clang-cl will require flags to enable the assembly.
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
else() else()
set(SIMD_COMPILE_FLAG " ") set(SIMD_COMPILE_FLAG " ")
endif() endif()
endif()
# Check which files we should include or not. # Check which files we should include or not.
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION) list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../" file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
"src/dsp/*${WEBP_SIMD_FILE_EXTENSION}") "src/dsp/*${WEBP_SIMD_FILE_EXTENSION}"
)
if(WEBP_HAVE_${WEBP_SIMD_FLAG}) if(WEBP_HAVE_${WEBP_SIMD_FLAG})
# Memorize the file and flags. # Memorize the file and flags.
foreach(FILE ${SIMD_FILES}) foreach(FILE ${SIMD_FILES})
@ -124,12 +85,6 @@ 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)
@ -141,11 +96,11 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
set(COMMON_PATTERNS) set(COMMON_PATTERNS)
endif() endif()
set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG}) set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
check_c_source_compiles( check_c_source_compiles("int main(void) {return 0;}" FLAG2
"int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX FAIL_REGEX "warning: argument unused during compilation:"
"warning: argument unused during compilation:" ${COMMON_PATTERNS}) ${COMMON_PATTERNS}
if(NOT FLAG_${SIMD_COMPILE_FLAG}) )
unset(HAS_COMPILE_FLAG) if(NOT FLAG2)
unset(HAS_COMPILE_FLAG CACHE) unset(HAS_COMPILE_FLAG CACHE)
endif() endif()
endif() endif()
@ -155,5 +110,4 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
endif() endif()
endif() endif()
endif() endif()
cmake_pop_check_state()
endforeach() endforeach()

View File

@ -1,172 +0,0 @@
# Copyright (c) 2021 Google LLC.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
# Generate the config.h to compile with specific intrinsics / libs.
# Check for compiler options.
include(CheckCSourceCompiles)
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap16(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP16)
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap32(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP32)
check_c_source_compiles(
"
int main(void) {
(void)__builtin_bswap64(0);
return 0;
}
"
HAVE_BUILTIN_BSWAP64)
# Check for libraries.
if(WEBP_USE_THREAD)
find_package(Threads)
if(Threads_FOUND)
# work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333)
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
endif()
list(APPEND WEBP_DEP_LIBRARIES Threads::Threads)
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
endif()
# TODO: this seems unused, check with autotools.
set(LT_OBJDIR ".libs/")
# Only useful for vwebp, so useless for now.
find_package(OpenGL)
set(WEBP_HAVE_GL ${OPENGL_FOUND})
# Check if we need to link to the C math library. We do not look for it as it is
# not found when cross-compiling, while it is here.
check_c_source_compiles(
"
#include <math.h>
int main(int argc, char** argv) {
return (int)pow(argc, 2.5);
}
"
HAVE_MATH_LIBRARY)
if(NOT HAVE_MATH_LIBRARY)
message(STATUS "Adding -lm flag.")
list(APPEND SHARPYUV_DEP_LIBRARIES m)
list(APPEND WEBP_DEP_LIBRARIES m)
endif()
# Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS)
if(WEBP_FIND_IMG_LIBS)
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(STATUS "TIFF is disabled when statically linking.")
continue()
endif()
find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
${${I_LIB}_INCLUDE_DIRS})
endif()
endforeach()
if(WEBP_DEP_IMG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
# GIF detection, gifdec isn't part of the imageio lib.
include(CMakePushCheckState)
set(WEBP_DEP_GIF_LIBRARIES)
set(WEBP_DEP_GIF_INCLUDE_DIRS)
find_package(GIF)
set(WEBP_HAVE_GIF ${GIF_FOUND})
if(GIF_FOUND)
# GIF find_package only locates the header and library, it doesn't fail
# compile tests when detecting the version, but falls back to 3 (as of at
# least cmake 3.7.2). Make sure the library links to avoid incorrect
# detection when cross compiling.
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
check_c_source_compiles(
"
#include <gif_lib.h>
int main(void) {
(void)DGifOpenFileHandle;
return 0;
}
"
GIF_COMPILES)
cmake_pop_check_state()
if(GIF_COMPILES)
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
else()
unset(GIF_FOUND)
endif()
endif()
endif()
# Check for specific headers.
include(CheckIncludeFiles)
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(wincodec.h HAVE_WINCODEC_H)
check_include_files(windows.h HAVE_WINDOWS_H)
# Windows specifics
if(HAVE_WINCODEC_H)
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
endif()
# Check for SIMD extensions.
include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
# Define extra info.
set(PACKAGE ${PROJECT_NAME})
set(PACKAGE_NAME ${PROJECT_NAME})
# Read from configure.ac.
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]" CONFIGURE_AC_PACKAGE_INFO
${CONFIGURE_AC})
function(strip_bracket VAR)
string(LENGTH ${${VAR}} TMP_LEN)
math(EXPR TMP_LEN ${TMP_LEN}-2)
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
endfunction()
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
strip_bracket(PACKAGE_VERSION)
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
strip_bracket(PACKAGE_BUGREPORT)
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
strip_bracket(PACKAGE_URL)
# Build more info.
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME ${PACKAGE_NAME})
set(VERSION ${PACKAGE_VERSION})

View File

@ -1,4 +0,0 @@
# This file is used by git cl to get repository specific information.
GERRIT_HOST: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
GERRIT_SQUASH_UPLOADS: False

View File

@ -1,6 +1,6 @@
AC_INIT([libwebp], [1.3.2], AC_INIT([libwebp], [0.6.0],
[https://bugs.chromium.org/p/webp],, [https://bugs.chromium.org/p/webp],,
[https://developers.google.com/speed/webp]) [http://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,8 +9,7 @@ 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])
dnl === AC_PROG_LIBTOOL is deprecated. AC_PROG_LIBTOOL
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
@ -28,46 +27,11 @@ 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_libsharpyuv], [$enableval]) [SET_IF_UNSET([enable_libwebpdecoder], [$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)
@ -103,7 +67,6 @@ AC_DEFUN([TEST_AND_ADD_CFLAGS],
CFLAGS="$SAVED_CFLAGS"]) CFLAGS="$SAVED_CFLAGS"])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
@ -112,11 +75,8 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code-aggressive])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused])
@ -159,6 +119,31 @@ AS_IF([test "$GCC" = "yes" ], [
AC_SUBST([AM_CFLAGS]) AC_SUBST([AM_CFLAGS])
dnl === Check for machine specific flags dnl === Check for machine specific flags
AC_ARG_ENABLE([avx2],
AS_HELP_STRING([--disable-avx2],
[Disable detection of AVX2 support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_avx2" != "xno" -a "x$enable_sse4_1" != "xno" \
-a "x$enable_sse2" != "xno"], [
AVX2_CFLAGS="$INTRINSICS_CFLAGS $AVX2_FLAGS"
TEST_AND_ADD_CFLAGS([AVX2_FLAGS], [-mavx2])
AS_IF([test -n "$AVX2_FLAGS"], [
SAVED_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $AVX2_FLAGS"
AC_CHECK_HEADER([immintrin.h],
[AC_DEFINE(WEBP_HAVE_AVX2, [1],
[Set to 1 if AVX2 is supported])],
[AVX2_FLAGS=""],
dnl it's illegal to directly include avx2intrin.h, but it's
dnl included conditionally in immintrin.h, tricky!
[#ifndef __AVX2__
#error avx2 is not enabled
#endif
])
CFLAGS=$SAVED_CFLAGS])
AC_SUBST([AVX2_FLAGS])])
AC_ARG_ENABLE([sse4.1], AC_ARG_ENABLE([sse4.1],
AS_HELP_STRING([--disable-sse4.1], AS_HELP_STRING([--disable-sse4.1],
[Disable detection of SSE4.1 support [Disable detection of SSE4.1 support
@ -256,13 +241,6 @@ AS_IF([test "x$enable_neon" != "xno"], [
NEON_FLAGS=""], NEON_FLAGS=""],
[AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1], [AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
[Set to 1 if runtime detection of NEON is enabled])])]) [Set to 1 if runtime detection of NEON is enabled])])])
case "$host_os" in
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
esac
;;
aarch64*|arm64*)
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
;; ;;
esac esac
AC_SUBST([NEON_FLAGS])]) AC_SUBST([NEON_FLAGS])])
@ -362,8 +340,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
# override with --with-gl* # override with --with-gl*
glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL" glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL"
glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL" glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL"
# quiet deprecation warnings for glut
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wno-deprecated-declarations])
;; ;;
esac esac
@ -448,75 +424,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"])
dnl === check for SDL support ===
AC_ARG_ENABLE([sdl],
AS_HELP_STRING([--disable-sdl],
[Disable detection of SDL support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sdl" != "xno"], [
CLEAR_LIBVARS([SDL])
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
if test -n "$LIBSDL_CONFIG"; then
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
fi
WITHLIB_OPTION([sdl], [SDL])
sdl_header="no"
LIBCHECK_PROLOGUE([SDL])
AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
[AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
[AC_MSG_WARN(SDL library not available - no sdl.h)])])
if test x"$sdl_header" != "xno"; then
AC_LANG_PUSH(C)
SDL_SAVED_LIBS="$LIBS"
for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
LIBS="$SDL_SAVED_LIBS $lib"
# Perform a full link to ensure SDL_main is resolved if needed.
AC_LINK_IFELSE(
[AC_LANG_SOURCE([
#include <$sdl_header>
int main(int argc, char** argv) {
SDL_Init(0);
return 0;
}])],
[SDL_LIBS="$LDFLAGS $LIBS"
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_SDL"
AC_DEFINE(WEBP_HAVE_SDL, [1],
[Set to 1 if SDL library is installed])
sdl_support=yes]
)
if test x"$sdl_support" = "xyes"; then
break
fi
done
# LIBS is restored by LIBCHECK_EPILOGUE
AC_LANG_POP
if test x"$sdl_header" = "xSDL.h"; then
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_JUST_SDL_H"
fi
fi
LIBCHECK_EPILOGUE([SDL])
if test x"$sdl_support" = "xyes"; then
build_vwebp_sdl=yes
else
AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
fi
])
AM_CONDITIONAL([BUILD_VWEBP_SDL], [test "$build_vwebp_sdl" = "yes"])
dnl === check for PNG support === dnl === check for PNG support ===
AC_ARG_ENABLE([png], AS_HELP_STRING([--disable-png], AC_ARG_ENABLE([png], AS_HELP_STRING([--disable-png],
@ -634,39 +545,22 @@ 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_animdiff=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_animdiff}" = "yes"])
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"]) AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then if test "$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
build_webpinfo=yes
else
AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
fi
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
dnl === check for WIC support === dnl === check for WIC support ===
AC_ARG_ENABLE([wic], AC_ARG_ENABLE([wic],
@ -719,7 +613,7 @@ if test "$enable_wic" = "yes"; then
fi fi
esac esac
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP=1 dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
USE_SWAP_16BIT_CSP="" USE_SWAP_16BIT_CSP=""
AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified) AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified)
@ -727,35 +621,62 @@ AC_ARG_ENABLE([swap-16bit-csp],
AS_HELP_STRING([--enable-swap-16bit-csp], AS_HELP_STRING([--enable-swap-16bit-csp],
[Enable byte swap for 16 bit colorspaces])) [Enable byte swap for 16 bit colorspaces]))
if test "$enable_swap_16bit_csp" = "yes"; then if test "$enable_swap_16bit_csp" = "yes"; then
USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP=1" USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP"
fi fi
AC_MSG_RESULT(${enable_swap_16bit_csp-no}) AC_MSG_RESULT(${enable_swap_16bit_csp-no})
AC_SUBST(USE_SWAP_16BIT_CSP) AC_SUBST(USE_SWAP_16BIT_CSP)
dnl === If --disable-near-lossless is defined, add -DWEBP_NEAR_LOSSLESS=0 dnl === If --enable-experimental is defined, add -DWEBP_EXPERIMENTAL_FEATURES
AC_DEFINE(WEBP_NEAR_LOSSLESS, [1], [Enable near lossless encoding]) USE_EXPERIMENTAL_CODE=""
AC_MSG_CHECKING(if --disable-near-lossless option is specified) AC_MSG_CHECKING(if --enable-experimental option is specified)
AC_ARG_ENABLE([near_lossless], AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental],
AS_HELP_STRING([--disable-near-lossless], [Activate experimental features]))
[Disable near lossless encoding]), if test "$enable_experimental" = "yes"; then
[], [enable_near_lossless=yes]) AC_DEFINE(WEBP_EXPERIMENTAL_FEATURES, [1], [Enable experimental code])
if test "$enable_near_lossless" = "no"; then USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
AC_DEFINE(WEBP_NEAR_LOSSLESS, [0], [Enable near lossless encoding])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi fi
AC_MSG_RESULT(${enable_experimental-no})
AC_SUBST(USE_EXPERIMENTAL_CODE)
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([WANT_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([--enable-libwebpdemux],
[Build libwebpdemux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([WANT_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([WANT_EXTRAS], [test "$enable_libwebpextras" = "yes"])
dnl ========================= dnl =========================
dnl Add an empty webp_libname_prefix variable for use in *.pc.in.
AC_SUBST([webp_libname_prefix])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_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 sharpyuv/libsharpyuv.pc \
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 \
@ -779,25 +700,22 @@ libwebpmux: ${enable_libwebpmux-no}
libwebpextras: ${enable_libwebpextras-no} libwebpextras: ${enable_libwebpextras-no}
Tools: Tools:
cwebp : ${enable_libwebpdemux-no} cwebp : yes
Input format support Input format support
==================== ====================
JPEG : ${jpeg_support-no} JPEG : ${jpeg_support-no}
PNG : ${png_support-no} PNG : ${png_support-no}
TIFF : ${tiff_support-no} TIFF : ${tiff_support-no}
WIC : ${wic_support-no} WIC : ${wic_support-no}
dwebp : ${enable_libwebpdemux-no} dwebp : yes
Output format support Output format support
===================== =====================
PNG : ${png_support-no} PNG : ${png_support-no}
WIC : ${wic_support-no} WIC : ${wic_support-no}
GIF support : ${gif_support-no} GIF support : ${gif_support-no}
anim_diff : ${build_anim_diff-no} anim_diff : ${build_animdiff-no}
gif2webp : ${build_gif2webp-no} gif2webp : ${build_gif2webp-no}
img2webp : ${build_img2webp-no} img2webp : ${build_img2webp-no}
webpmux : ${enable_libwebpmux-no} webpmux : ${enable_libwebpmux-no}
vwebp : ${build_vwebp-no} vwebp : ${build_vwebp-no}
webpinfo : ${build_webpinfo-no}
SDL support : ${sdl_support-no}
vwebp_sdl : ${build_vwebp_sdl-no}
]) ])

29
doc/README Normal file
View File

@ -0,0 +1,29 @@
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/

View File

@ -1,385 +0,0 @@
# 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, &timestamp);
// ... (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).

View File

@ -1,213 +0,0 @@
# 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)

View File

@ -1,26 +0,0 @@
# 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.

View File

@ -1,516 +0,0 @@
# 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]... [-o webp_file]
```
File-level options (only used at the start of compression):
```
-min_size ............ minimize size
-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
-near_lossless <int> . use near-lossless image preprocessing
(0..100=off), default=100
-sharp_yuv ........... use sharper (and slower) RGB->YUV conversion
(lossy only)
-loop <int> .......... loop count (default: 0, = infinite loop)
-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 '-'.
```

View File

@ -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](https://kramdown.gettalong.org/) transformer. the [kramdown](http://kramdown.rubyforge.org/) transformer.
See the accompanying specs_generation.md. External link targets are referenced See the accompanying README. External link targets are referenced at the
at the end of this file. end of this file.
--> -->
@ -20,25 +20,25 @@ WebP Container Specification
Introduction Introduction
------------ ------------
WebP is an image format that uses either (i) the VP8 key frame encoding to WebP is an image format that uses either (i) the VP8 key frame encoding
compress image data in a lossy way, or (ii) the WebP lossless encoding. These to compress image data in a lossy way, or (ii) the WebP lossless encoding
encoding schemes should make it more efficient than older formats such as JPEG, (and possibly other encodings in the future). These encoding schemes should
GIF and PNG. It is optimized for fast image transfer over the network (for make it more efficient than currently used formats. It is optimized for fast
example, for websites). The WebP format has feature parity (color profile, image transfer over the network (e.g., for websites). The WebP format has
metadata, animation, etc.) with other formats as well. This document describes feature parity (color profile, metadata, animation etc) with other formats as
the structure of a WebP file. well. This document describes the structure of a WebP file.
The WebP container (that is, the RIFF container for WebP) allows feature support The WebP container (i.e., RIFF container for WebP) allows feature support over
over and above the basic use case of WebP (that is, a file containing a single and above the basic use case of WebP (i.e., a file containing a single image
image encoded as a VP8 key frame). The WebP container provides additional encoded as a VP8 key frame). The WebP container provides additional support
support for: 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, that is, an alpha channel. * **Transparency.** An image may have transparency, i.e., an alpha channel.
* **Color Profile.** An image may have an embedded ICC profile as described * **Color Profile.** An image may have an embedded ICC profile as described
by the [International Color Consortium][iccspec]. by the [International Color Consortium][iccspec].
@ -46,21 +46,24 @@ support for:
* **Animation.** An image may have multiple frames with pauses between them, * **Animation.** An image may have multiple frames with pauses between them,
making it an animation. making it an animation.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][] document are to be interpreted as described in [RFC 2119][].
when, and only when, they appear in all capitals, as shown here.
Bit numbering in chunk diagrams starts at `0` for the most significant bit 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][].
Terminology & Basics **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.
A WebP file contains either a still image (that is, an encoded matrix of pixels) Terminology &amp; Basics
------------------------
A WebP file contains either a still image (i.e., an encoded matrix of pixels)
or an [animation](#animation). Optionally, it can also contain transparency or an [animation](#animation). Optionally, it can also contain transparency
information, color profile and metadata. We refer to the matrix of pixels as the information, color profile and metadata. In case we need to refer only to the
_canvas_ of the image. matrix of pixels, we will call it the _canvas_ of the image.
Below are additional terms used throughout this document: Below are additional terms used throughout this document:
@ -84,25 +87,18 @@ _uint32_
_FourCC_ _FourCC_
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four : A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and ASCII characters in little-endian order.
'AAAA' (0x41414141) are treated as different _FourCCs_.
_1-based_ _1-based_
: An unsigned integer field storing values offset by `-1`, for example, such a : An unsigned integer field storing values offset by `-1`. e.g., Such a field
field would store value _25_ as _24_. would store value _25_ as _24_.
_ChunkHeader('ABCD')_
: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
chunks, where 'ABCD' is the FourCC for the chunk. This element's size is 8
bytes.
RIFF File Format 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:
@ -114,7 +110,7 @@ The basic element of a RIFF file is a _chunk_. It consists of:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Chunk Size | | Chunk Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Chunk Payload : | Chunk Payload |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk FourCC: 32 bits Chunk FourCC: 32 bits
@ -123,13 +119,19 @@ Chunk FourCC: 32 bits
Chunk Size: 32 bits (_uint32_) Chunk Size: 32 bits (_uint32_)
: The size of the chunk in bytes, not including this field, the chunk : The size of the chunk not including this field, the chunk identifier or
identifier or padding. padding.
Chunk Payload: _Chunk Size_ bytes Chunk Payload: _Chunk Size_ bytes
: The data payload. If _Chunk Size_ is odd, a single padding byte -- that MUST : The data payload. If _Chunk Size_ is odd, a single padding byte -- that
be `0` to conform with RIFF -- is added. SHOULD be `0` -- is added.
_ChunkHeader('ABCD')_
: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
chunks, where 'ABCD' is the FourCC for the chunk. This element's
size is 8 bytes.
**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard **Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
chunks that apply to any RIFF file format, while FourCCs specific to a file chunks that apply to any RIFF file format, while FourCCs specific to a file
@ -165,11 +167,9 @@ File Size: 32 bits (_uint32_)
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
in the header is the total size of the chunks that follow plus `4` bytes for in the header is the total size of the chunks that follow plus `4` bytes for
the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
specified by _File Size_. Readers MAY parse such files, ignoring the trailing of any chunk is even, the size given by the RIFF header is also even. The
data. As the size of any chunk is even, the size given by the RIFF header is contents of individual chunks will be described in the following sections.
also even. The contents of individual chunks are described in the following
sections.
Simple File Format (Lossy) Simple File Format (Lossy)
@ -184,11 +184,9 @@ Simple WebP (lossy) file format:
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) | | WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: VP8 chunk : | VP8 chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 chunk: VP8 chunk:
@ -197,24 +195,20 @@ VP8 chunk:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8 ') | | ChunkHeader('VP8 ') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: VP8 data : | VP8 data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 data: _Chunk Size_ bytes VP8 data: _Chunk Size_ bytes
: VP8 bitstream data. : VP8 bitstream data.
Note the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
The VP8 bitstream format specification can be found at [VP8 Data Format and The VP8 bitstream format specification can be found at [VP8 Data Format and
Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
width and height. That is assumed to be the width and height of the canvas. width and height. That is assumed to be the width and height of the canvas.
The VP8 specification describes how to decode the image into Y'CbCr format. To The VP8 specification describes how to decode the image into Y'CbCr
convert to RGB, Rec. 601 SHOULD be used. Applications MAY use another format. To convert to RGB, Rec. 601 SHOULD be used.
conversion method, but visual results may differ among decoders.
Simple File Format (Lossless) Simple File Format (Lossless)
@ -231,11 +225,9 @@ Simple WebP (lossless) file format:
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) | | WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: VP8L chunk : | VP8L chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L chunk: VP8L chunk:
@ -244,9 +236,8 @@ VP8L chunk:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8L') | | ChunkHeader('VP8L') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: VP8L data : | VP8L data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L data: _Chunk Size_ bytes VP8L data: _Chunk Size_ bytes
@ -274,11 +265,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). * An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_
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:
@ -292,7 +283,7 @@ details about frames can be found in the [Animation](#animation) section.
All chunks SHOULD be placed in the same order as listed above. If a chunk All chunks SHOULD be placed in the same order as listed above. If a chunk
appears in the wrong place, the file is invalid, but readers MAY parse the appears in the wrong place, the file is invalid, but readers MAY parse the
file, ignoring the chunks that are out of order. file, ignoring the chunks that come too late.
**Rationale:** Setting the order of chunks should allow quicker file **Rationale:** Setting the order of chunks should allow quicker file
parsing. For example, if an 'ALPH' chunk does not appear in its required parsing. For example, if an 'ALPH' chunk does not appear in its required
@ -306,12 +297,9 @@ Extended WebP file header:
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| WebP file header (12 bytes) | | WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8X') | | ChunkHeader('VP8X') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|R| Reserved | |Rsv|I|L|E|X|A|R| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -322,7 +310,7 @@ Extended WebP file header:
Reserved (Rsv): 2 bits Reserved (Rsv): 2 bits
: MUST be `0`. Readers MUST ignore this field. : SHOULD be `0`.
ICC profile (I): 1 bit ICC profile (I): 1 bit
@ -333,9 +321,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
@ -348,25 +336,25 @@ Animation (A): 1 bit
Reserved (R): 1 bit Reserved (R): 1 bit
: MUST be `0`. Readers MUST ignore this field. : SHOULD be `0`.
Reserved: 24 bits Reserved: 24 bits
: MUST be `0`. Readers MUST ignore this field. : SHOULD be `0`.
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`.
Future specifications may add more fields. Unknown fields MUST be ignored. Future specifications MAY add more fields.
### Chunks ### Chunks
@ -384,7 +372,6 @@ animation.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANIM') | | ChunkHeader('ANIM') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Background Color | | Background Color |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -400,8 +387,8 @@ Background Color: 32 bits (_uint32_)
**Note**: **Note**:
* Background color MAY contain a non-opaque alpha value, even if the _Alpha_ * Background color MAY contain a transparency value (alpha), even if the
flag in [VP8X chunk](#extended_header) is unset. _Alpha_ flag in [VP8X chunk](#extended_header) is unset.
* Viewer applications SHOULD treat the background color value as a hint, and * Viewer applications SHOULD treat the background color value as a hint, and
are not required to use it. are not required to use it.
@ -414,8 +401,8 @@ Loop Count: 16 bits (_uint16_)
: The number of times to loop the animation. `0` means infinitely. : The number of times to loop the animation. `0` means infinitely.
This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set. This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
If the _Animation_ flag is not set and this chunk is present, it MUST be If the _Animation_ flag is not set and this chunk is present, it
ignored. SHOULD be ignored.
ANMF chunk: ANMF chunk:
@ -426,7 +413,6 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ANMF') | | ChunkHeader('ANMF') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame X | ... | Frame X | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -436,37 +422,36 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Duration | Reserved |B|D| | Frame Duration | Reserved |B|D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Frame Data : | Frame Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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_)
: The time to wait before displaying the next frame, in 1 millisecond units. : The time to wait before displaying the next frame, in 1 millisecond units.
Note the interpretation of frame duration of 0 (and often <= 10) is In particular, frame duration of 0 is useful when one wants to update
implementation defined. Many tools and browsers assign a minimum duration multiple areas of the canvas at once during the animation.
similar to GIF.
Reserved: 6 bits Reserved: 6 bits
: MUST be `0`. Readers MUST ignore this field. : SHOULD be 0.
Blending method (B): 1 bit Blending method (B): 1 bit
@ -511,8 +496,7 @@ Disposal method (D): 1 bit
if blend.A = 0 then if blend.A = 0 then
blend.RGB = 0 blend.RGB = 0
else else
blend.RGB = blend.RGB = (src.RGB * src.A +
(src.RGB * src.A +
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
~~~~~ ~~~~~
@ -540,23 +524,22 @@ _padded_ chunks as described by the [RIFF file format](#riff-file-format).
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ALPH') | | ChunkHeader('ALPH') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv| P | F | C | Alpha Bitstream... | |Rsv| P | F | C | Alpha Bitstream... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Reserved (Rsv): 2 bits Reserved (Rsv): 2 bits
: MUST be `0`. Readers MUST ignore this field. : SHOULD be `0`.
Pre-processing (P): 2 bits Pre-processing (P): 2 bits
: These _informative_ bits are used to signal the pre-processing that has : These INFORMATIVE bits are used to signal the pre-processing that has
been performed during compression. The decoder can use this information to been performed during compression. The decoder can use this information to
for example, dither the values or smooth the gradients prior to display. e.g. dither the values or smooth the gradients prior to display.
* `0`: No pre-processing. * `0`: no pre-processing
* `1`: Level reduction. * `1`: level reduction
Filtering method (F): 2 bits Filtering method (F): 2 bits
@ -589,14 +572,14 @@ where `clip(v)` is equal to:
* v otherwise * v otherwise
The final value is derived by adding the decompressed value `X` to the The final value is derived by adding the decompressed value `X` to the
predictor and using modulo-256 arithmetic to wrap the \[256..511\] range predictor and using modulo-256 arithmetic to wrap the \[256-511\] range
into the \[0..255\] one: into the \[0-255\] one:
`alpha = (predictor + X) % 256` `alpha = (predictor + X) % 256`
There are special cases for the left-most and top-most pixel positions: There are special cases for left-most and top-most pixel positions:
* The top-left value at location (0, 0) uses 0 as predictor value. Otherwise, * Top-left value at location (0,0) uses 0 as predictor value. Otherwise,
* For horizontal or gradient filtering methods, the left-most pixels at * For horizontal or gradient filtering methods, the left-most pixels at
location (0, y) are predicted using the location (0, y-1) just above. location (0, y) are predicted using the location (0, y-1) just above.
* For vertical or gradient filtering methods, the top-most pixels at * For vertical or gradient filtering methods, the top-most pixels at
@ -658,15 +641,14 @@ The formats of VP8 and VP8L chunks are as described in sections
[Simple File Format (Lossy)](#simple-file-format-lossy) [Simple File Format (Lossy)](#simple-file-format-lossy)
and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively. and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively.
#### Color Profile #### Color profile
0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('ICCP') | | ChunkHeader('ICCP') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Color Profile : | Color Profile |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Color Profile: _Chunk Size_ bytes Color Profile: _Chunk Size_ bytes
@ -686,7 +668,8 @@ If this chunk is not present, sRGB SHOULD be assumed.
Metadata can be stored in 'EXIF' or 'XMP ' chunks. Metadata can be stored in 'EXIF' or 'XMP ' chunks.
There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there
are more such chunks, readers MAY ignore all except the first one. are more such chunks, readers MAY ignore all except the first one. Also, a file
may possibly contain both 'EXIF' and 'XMP ' chunks.
The chunks are defined as follows: The chunks are defined as follows:
@ -696,14 +679,13 @@ EXIF chunk:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('EXIF') | | 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:
@ -711,21 +693,18 @@ XMP chunk:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('XMP ') | | ChunkHeader('XMP ') |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: XMP Metadata : | XMP Metadata |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
XMP Metadata: _Chunk Size_ bytes XMP Metadata: _Chunk Size_ bytes
: Image metadata in XMP format. : image metadata in XMP format.
Note the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
Additional guidance about handling metadata can be found in the 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 #### Unknown Chunks _\[status: experimental\]_
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
@ -744,42 +723,21 @@ A file MAY contain unknown chunks:
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks). original order (unless they specifically intend to modify these chunks).
### Assembling the Canvas From Frames ### Assembling the Canvas from frames
Here we provide an overview of how a reader MUST assemble a canvas in the case Here we provide an overview of how a reader should assemble a canvas in the
of an animated image. case of an animated image. The notation _VP8X.field_ means the field in the
'VP8X' chunk with the same description.
The process begins with creating a canvas using the dimensions given in the Displaying an _animated image_ canvas MUST be equivalent to the following
'VP8X' chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus pseudocode:
One + 1` pixels high. The `Loop Count` field from the 'ANIM' chunk controls how
many times the animation process is repeated. This is `Loop Count - 1` for
non-zero `Loop Count` values or infinitely if `Loop Count` is zero.
At the beginning of each loop iteration the canvas is filled using the
background color from the 'ANIM' chunk or an application defined color.
'ANMF' chunks contain individual frames given in display order. Before rendering
each frame, the previous frame's `Disposal method` is applied.
The rendering of the decoded frame begins at the Cartesian coordinates (`2 *
Frame X`, `2 * Frame Y`) using the top-left corner of the canvas as the origin.
`Frame Width Minus One + 1` pixels wide by `Frame Height Minus One + 1` pixels
high are rendered onto the canvas using the `Blending method`.
The canvas is displayed for `Frame Duration` milliseconds. This continues until
all frames given by 'ANMF' chunks have been displayed. A new loop iteration is
then begun or the canvas is left in its final state if all iterations have been
completed.
The following pseudocode illustrates the rendering process. The notation
_VP8X.field_ means the field in the 'VP8X' chunk with the same description.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasAnimation assert VP8X.flags.hasAnimation
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
background color ANIM.background_color. background color ANIM.background_color.
loop_count ← ANIM.loopCount loop_count ← ANIM.loopCount
dispose_method ← Dispose to background color dispose_method ← ANIM.disposeMethod
if loop_count == 0: if loop_count == 0:
loop_count = ∞ loop_count = ∞
frame_params ← nil frame_params ← nil
@ -803,14 +761,11 @@ for loop = 0..loop_count - 1
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L": else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Frame Data' earlier assert bitstream subchunks not found in 'Frame Data' earlier
frame_params.bitstream = bitstream_data frame_params.bitstream = bitstream_data
render frame with frame_params.alpha and frame_params.bitstream render frame with frame_params.alpha and frame_params.bitstream on
on canvas with top-left corner at (frame_params.frameX, canvas with top-left corner at (frame_params.frameX,
frame_params.frameY), using blending method frame_params.frameY), using dispose method dispose_method.
frame_params.blendingMethod.
canvas contains the decoded image. canvas contains the decoded image.
Show the contents of the canvas for Show the contents of the canvas for frame_params.frameDuration * 1ms.
frame_params.frameDuration * 1ms.
dispose_method = frame_params.disposeMethod
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -846,7 +801,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
@ -859,10 +814,9 @@ RIFF/WEBP
+- EXIF (metadata) +- EXIF (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[vp8spec]: https://datatracker.ietf.org/doc/html/rfc6386 [vp8spec]: http://tools.ietf.org/html/rfc6386
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt [webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
[iccspec]: https://www.color.org/icc_specs2.xalter [iccspec]: http://www.color.org/icc_specs2.xalter
[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf [metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166 [rfc 1166]: http://tools.ietf.org/html/rfc1166
[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119 [rfc 2119]: http://tools.ietf.org/html/rfc2119
[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,3 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
################################################################################ ################################################################################
@ -28,7 +26,8 @@ LOCAL_SRC_FILES := \
cwebp.c \ cwebp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpdemux webp LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webp
LOCAL_MODULE := cwebp LOCAL_MODULE := cwebp
@ -43,7 +42,9 @@ LOCAL_SRC_FILES := \
dwebp.c \ dwebp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webpdemux webp LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webp
LOCAL_MODULE := dwebp LOCAL_MODULE := dwebp
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
@ -57,6 +58,7 @@ LOCAL_SRC_FILES := \
webpmux.c \ webpmux.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp
LOCAL_MODULE := webpmux_example LOCAL_MODULE := webpmux_example
@ -72,25 +74,9 @@ LOCAL_SRC_FILES := \
img2webp.c \ img2webp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webpdemux \ LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
webp LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webp
LOCAL_MODULE := img2webp_example LOCAL_MODULE := img2webp_example
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
################################################################################
# webpinfo
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
webpinfo.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imageio_util webp
LOCAL_MODULE := webpinfo_example
include $(BUILD_EXECUTABLE)
endif # NDK_ROOT

View File

@ -1,11 +1,8 @@
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
bin_PROGRAMS = bin_PROGRAMS = dwebp cwebp
if BUILD_DEMUX
bin_PROGRAMS += dwebp cwebp
endif
if BUILD_ANIMDIFF if BUILD_ANIMDIFF
noinst_PROGRAMS = anim_diff anim_dump noinst_PROGRAMS = anim_diff
endif endif
if BUILD_GIF2WEBP if BUILD_GIF2WEBP
bin_PROGRAMS += gif2webp bin_PROGRAMS += gif2webp
@ -13,53 +10,34 @@ endif
if BUILD_IMG2WEBP if BUILD_IMG2WEBP
bin_PROGRAMS += img2webp bin_PROGRAMS += img2webp
endif endif
if BUILD_MUX if WANT_MUX
bin_PROGRAMS += webpmux bin_PROGRAMS += webpmux
endif endif
if BUILD_VWEBP if BUILD_VWEBP
bin_PROGRAMS += vwebp bin_PROGRAMS += vwebp
endif endif
if BUILD_WEBPINFO
bin_PROGRAMS += webpinfo
endif
noinst_LTLIBRARIES = libexample_util.la noinst_LTLIBRARIES = libexample_util.la
libexample_util_la_SOURCES = example_util.c example_util.h libexample_util_la_SOURCES = example_util.c example_util.h
libexample_util_la_LIBADD = ../src/libwebp.la libexample_util_la_LIBADD = ../src/libwebp.la
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h gifdec.c gifdec.h anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
anim_diff_LDADD = anim_diff_LDADD = ../src/demux/libwebpdemux.la
anim_diff_LDADD += ../src/demux/libwebpdemux.la anim_diff_LDADD += libexample_util.la ../imageio/libimageio_util.la
anim_diff_LDADD += libexample_util.la
anim_diff_LDADD += ../imageio/libimageio_util.la
anim_diff_LDADD += $(GIF_LIBS) -lm anim_diff_LDADD += $(GIF_LIBS) -lm
anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h gifdec.c gifdec.h
anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES)
anim_dump_CPPFLAGS += $(GIF_INCLUDES)
anim_dump_LDADD =
anim_dump_LDADD += ../src/demux/libwebpdemux.la
anim_dump_LDADD += libexample_util.la
anim_dump_LDADD += ../imageio/libimageio_util.la
anim_dump_LDADD += ../imageio/libimageenc.la
anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm
cwebp_SOURCES = cwebp.c stopwatch.h cwebp_SOURCES = cwebp.c stopwatch.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir) cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
cwebp_LDADD = cwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
cwebp_LDADD += libexample_util.la cwebp_LDADD += ../imageio/libimagedec.la ../src/libwebp.la
cwebp_LDADD += ../imageio/libimageio_util.la
cwebp_LDADD += ../imageio/libimagedec.la
cwebp_LDADD += ../src/libwebp.la
cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
dwebp_SOURCES = dwebp.c stopwatch.h dwebp_SOURCES = dwebp.c stopwatch.h
dwebp_CPPFLAGS = $(AM_CPPFLAGS) dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
dwebp_LDADD = dwebp_LDADD = libexample_util.la
dwebp_LDADD += libexample_util.la
dwebp_LDADD += ../imageio/libimagedec.la dwebp_LDADD += ../imageio/libimagedec.la
dwebp_LDADD += ../imageio/libimageenc.la dwebp_LDADD += ../imageio/libimageenc.la
dwebp_LDADD += ../imageio/libimageio_util.la dwebp_LDADD += ../imageio/libimageio_util.la
@ -67,53 +45,31 @@ dwebp_LDADD += ../src/libwebp.la
dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS) dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS)
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
gif2webp_LDADD = gif2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
gif2webp_LDADD += libexample_util.la gif2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la $(GIF_LIBS)
gif2webp_LDADD += ../imageio/libimageio_util.la
gif2webp_LDADD += ../src/mux/libwebpmux.la
gif2webp_LDADD += ../src/libwebp.la
gif2webp_LDADD += $(GIF_LIBS)
vwebp_SOURCES = vwebp.c vwebp_SOURCES = vwebp.c
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(GL_INCLUDES) vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
vwebp_LDADD = vwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
vwebp_LDADD += libexample_util.la vwebp_LDADD += ../src/demux/libwebpdemux.la $(GL_LIBS)
vwebp_LDADD += ../imageio/libimageio_util.la
vwebp_LDADD += ../src/demux/libwebpdemux.la
vwebp_LDADD += $(GL_LIBS)
webpmux_SOURCES = webpmux.c webpmux_SOURCES = webpmux.c
webpmux_CPPFLAGS = $(AM_CPPFLAGS) webpmux_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
webpmux_LDADD = webpmux_LDADD = libexample_util.la ../imageio/libimageio_util.la
webpmux_LDADD += libexample_util.la webpmux_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
webpmux_LDADD += ../imageio/libimageio_util.la
webpmux_LDADD += ../src/mux/libwebpmux.la
webpmux_LDADD += ../src/libwebp.la
img2webp_SOURCES = img2webp.c img2webp_SOURCES = img2webp.c
img2webp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir) img2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
img2webp_LDADD = img2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
img2webp_LDADD += libexample_util.la
img2webp_LDADD += ../imageio/libimageio_util.la
img2webp_LDADD += ../imageio/libimagedec.la img2webp_LDADD += ../imageio/libimagedec.la
img2webp_LDADD += ../src/mux/libwebpmux.la img2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
img2webp_LDADD += ../src/libwebp.la
img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
webpinfo_SOURCES = webpinfo.c
webpinfo_CPPFLAGS = $(AM_CPPFLAGS)
webpinfo_LDADD =
webpinfo_LDADD += libexample_util.la
webpinfo_LDADD += ../imageio/libimageio_util.la
webpinfo_LDADD += ../src/libwebp.la
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
anim_diff_LDADD += ../src/libwebpdecoder.la anim_diff_LDADD += ../src/libwebpdecoder.la
anim_dump_LDADD += ../src/libwebpdecoder.la
vwebp_LDADD += ../src/libwebpdecoder.la vwebp_LDADD += ../src/libwebpdecoder.la
else else
anim_diff_LDADD += ../src/libwebp.la anim_diff_LDADD += ../src/libwebp.la
anim_dump_LDADD += ../src/libwebp.la
vwebp_LDADD += ../src/libwebp.la vwebp_LDADD += ../src/libwebp.la
endif endif

View File

@ -20,8 +20,6 @@
#include <string.h> // for 'strcmp'. #include <string.h> // for 'strcmp'.
#include "./anim_util.h" #include "./anim_util.h"
#include "./example_util.h"
#include "./unicode.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -145,18 +143,8 @@ static int CompareAnimatedImagePair(const AnimatedImage* const img1,
if (!ok) return 0; // These are fatal failures, can't proceed. if (!ok) return 0; // These are fatal failures, can't proceed.
if (is_multi_frame_image) { // Checks relevant for multi-frame images only. if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
int max_loop_count_workaround = 0; ok = CompareValues(img1->loop_count, img2->loop_count,
// Transcodes to webp increase the gif loop count by 1 for compatibility. "Loop count mismatch") && ok;
// When the gif has the maximum value the webp value will be off by one.
if ((img1->format == ANIM_GIF && img1->loop_count == 65536 &&
img2->format == ANIM_WEBP && img2->loop_count == 65535) ||
(img1->format == ANIM_WEBP && img1->loop_count == 65535 &&
img2->format == ANIM_GIF && img2->loop_count == 65536)) {
max_loop_count_workaround = 1;
}
ok = (max_loop_count_workaround ||
CompareValues(img1->loop_count, img2->loop_count,
"Loop count mismatch")) && ok;
ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor, ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor,
premultiply) && ok; premultiply) && ok;
} }
@ -199,11 +187,11 @@ static void Help(void) {
printf(" -min_psnr <float> ... minimum per-frame PSNR\n"); printf(" -min_psnr <float> ... minimum per-frame PSNR\n");
printf(" -raw_comparison ..... if this flag is not used, RGB is\n"); printf(" -raw_comparison ..... if this flag is not used, RGB is\n");
printf(" premultiplied before comparison\n"); printf(" premultiplied before comparison\n");
printf(" -max_diff <int> ..... maximum allowed difference per channel\n" #ifdef WEBP_EXPERIMENTAL_FEATURES
" between corresponding pixels in subsequent\n" printf(" -max_diff <int> ..... maximum allowed difference per channel "
" between corresponding pixels in subsequent"
" frames\n"); " frames\n");
printf(" -h .................. this help\n"); #endif
printf(" -version ............ print version number and exit\n");
} }
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
@ -219,49 +207,56 @@ int main(int argc, const char* argv[]) {
const char* files[2] = { NULL, NULL }; const char* files[2] = { NULL, NULL };
AnimatedImage images[2]; AnimatedImage images[2];
INIT_WARGV(argc, argv); if (argc < 3) {
Help();
return -1;
}
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-dump_frames")) { if (!strcmp(argv[c], "-dump_frames")) {
if (c < argc - 1) { if (c < argc - 1) {
dump_frames = 1; dump_frames = 1;
dump_folder = (const char*)GET_WARGV(argv, ++c); dump_folder = argv[++c];
} else { } else {
parse_error = 1; parse_error = 1;
} }
} else if (!strcmp(argv[c], "-min_psnr")) { } else if (!strcmp(argv[c], "-min_psnr")) {
if (c < argc - 1) { if (c < argc - 1) {
min_psnr = ExUtilGetFloat(argv[++c], &parse_error); const char* const v = argv[++c];
char* end = NULL;
const double d = strtod(v, &end);
if (end == v) {
parse_error = 1;
fprintf(stderr, "Error! '%s' is not a floating point number.\n", v);
}
min_psnr = d;
} else { } else {
parse_error = 1; parse_error = 1;
} }
} else if (!strcmp(argv[c], "-raw_comparison")) { } else if (!strcmp(argv[c], "-raw_comparison")) {
premultiply = 0; premultiply = 0;
#ifdef WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-max_diff")) { } else if (!strcmp(argv[c], "-max_diff")) {
if (c < argc - 1) { if (c < argc - 1) {
max_diff = ExUtilGetInt(argv[++c], 0, &parse_error); const char* const v = argv[++c];
char* end = NULL;
const int n = (int)strtol(v, &end, 10);
if (end == v) {
parse_error = 1;
fprintf(stderr, "Error! '%s' is not an integer.\n", v);
}
max_diff = n;
} else { } else {
parse_error = 1; parse_error = 1;
} }
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { #endif
Help();
FREE_WARGV_AND_RETURN(0);
} else if (!strcmp(argv[c], "-version")) {
int dec_version, demux_version;
GetAnimatedImageVersions(&dec_version, &demux_version);
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
(dec_version >> 0) & 0xff,
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
(demux_version >> 0) & 0xff);
FREE_WARGV_AND_RETURN(0);
} else { } else {
if (!got_input1) { if (!got_input1) {
files[0] = (const char*)GET_WARGV(argv, c); files[0] = argv[c];
got_input1 = 1; got_input1 = 1;
} else if (!got_input2) { } else if (!got_input2) {
files[1] = (const char*)GET_WARGV(argv, c); files[1] = argv[c];
got_input2 = 1; got_input2 = 1;
} else { } else {
parse_error = 1; parse_error = 1;
@ -269,30 +264,23 @@ int main(int argc, const char* argv[]) {
} }
if (parse_error) { if (parse_error) {
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
} }
if (argc < 3) {
Help();
FREE_WARGV_AND_RETURN(-1);
}
if (!got_input2) { if (!got_input2) {
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
if (dump_frames) { if (dump_frames) {
WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder); printf("Dumping decoded frames in: %s\n", dump_folder);
} }
memset(images, 0, sizeof(images)); memset(images, 0, sizeof(images));
for (i = 0; i < 2; ++i) { for (i = 0; i < 2; ++i) {
WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]); printf("Decoding file: %s\n", files[i]);
if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) { if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) {
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", fprintf(stderr, "Error decoding file: %s\n Aborting.\n", files[i]);
(const W_CHAR*)files[i]);
return_code = -2; return_code = -2;
goto End; goto End;
} else { } else {
@ -302,16 +290,14 @@ int main(int argc, const char* argv[]) {
if (!CompareAnimatedImagePair(&images[0], &images[1], if (!CompareAnimatedImagePair(&images[0], &images[1],
premultiply, min_psnr)) { premultiply, min_psnr)) {
WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0], fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]);
(const W_CHAR*)files[1]);
return_code = -3; return_code = -3;
} else { } else {
WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0], printf("\nFiles %s and %s are identical.\n", files[0], files[1]);
(const W_CHAR*)files[1]);
return_code = 0; return_code = 0;
} }
End: End:
ClearAnimatedImage(&images[0]); ClearAnimatedImage(&images[0]);
ClearAnimatedImage(&images[1]); ClearAnimatedImage(&images[1]);
FREE_WARGV_AND_RETURN(return_code); return return_code;
} }

View File

@ -1,121 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Decodes an animated WebP file and dumps the decoded frames as PNG or TIFF.
//
// Author: Skal (pascal.massimino@gmail.com)
#include <stdio.h>
#include <string.h> // for 'strcmp'.
#include "./anim_util.h"
#include "webp/decode.h"
#include "../imageio/image_enc.h"
#include "./unicode.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
static void Help(void) {
printf("Usage: anim_dump [options] files...\n");
printf("\nOptions:\n");
printf(" -folder <string> .... dump folder (default: '.')\n");
printf(" -prefix <string> .... prefix for dumped frames "
"(default: 'dump_')\n");
printf(" -tiff ............... save frames as TIFF\n");
printf(" -pam ................ save frames as PAM\n");
printf(" -h .................. this help\n");
printf(" -version ............ print version number and exit\n");
}
int main(int argc, const char* argv[]) {
int error = 0;
const W_CHAR* dump_folder = TO_W_CHAR(".");
const W_CHAR* prefix = TO_W_CHAR("dump_");
const W_CHAR* suffix = TO_W_CHAR("png");
WebPOutputFileFormat format = PNG;
int c;
INIT_WARGV(argc, argv);
if (argc < 2) {
Help();
FREE_WARGV_AND_RETURN(-1);
}
for (c = 1; !error && c < argc; ++c) {
if (!strcmp(argv[c], "-folder")) {
if (c + 1 == argc) {
fprintf(stderr, "missing argument after option '%s'\n", argv[c]);
error = 1;
break;
}
dump_folder = GET_WARGV(argv, ++c);
} else if (!strcmp(argv[c], "-prefix")) {
if (c + 1 == argc) {
fprintf(stderr, "missing argument after option '%s'\n", argv[c]);
error = 1;
break;
}
prefix = GET_WARGV(argv, ++c);
} else if (!strcmp(argv[c], "-tiff")) {
format = TIFF;
suffix = TO_W_CHAR("tiff");
} else if (!strcmp(argv[c], "-pam")) {
format = PAM;
suffix = TO_W_CHAR("pam");
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
} else if (!strcmp(argv[c], "-version")) {
int dec_version, demux_version;
GetAnimatedImageVersions(&dec_version, &demux_version);
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
(dec_version >> 0) & 0xff,
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
(demux_version >> 0) & 0xff);
FREE_WARGV_AND_RETURN(0);
} else {
uint32_t i;
AnimatedImage image;
const W_CHAR* const file = GET_WARGV(argv, c);
memset(&image, 0, sizeof(image));
WPRINTF("Decoding file: %s as %s/%sxxxx.%s\n",
file, dump_folder, prefix, suffix);
if (!ReadAnimatedImage((const char*)file, &image, 0, NULL)) {
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", file);
error = 1;
break;
}
for (i = 0; !error && i < image.num_frames; ++i) {
W_CHAR out_file[1024];
WebPDecBuffer buffer;
WebPInitDecBuffer(&buffer);
buffer.colorspace = MODE_RGBA;
buffer.is_external_memory = 1;
buffer.width = image.canvas_width;
buffer.height = image.canvas_height;
buffer.u.RGBA.rgba = image.frames[i].rgba;
buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t);
buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height;
WSNPRINTF(out_file, sizeof(out_file), "%s/%s%.4d.%s",
dump_folder, prefix, i, suffix);
if (!WebPSaveImage(&buffer, format, (const char*)out_file)) {
WFPRINTF(stderr, "Error while saving image '%s'\n", out_file);
error = 1;
}
WebPFreeDecBuffer(&buffer);
}
ClearAnimatedImage(&image);
}
}
FREE_WARGV_AND_RETURN(error ? 1 : 0);
}

View File

@ -16,16 +16,13 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#if defined(WEBP_HAVE_GIF) #ifdef WEBP_HAVE_GIF
#include <gif_lib.h> #include <gif_lib.h>
#endif #endif
#include "webp/format_constants.h" #include "webp/format_constants.h"
#include "webp/decode.h" #include "webp/decode.h"
#include "webp/demux.h" #include "webp/demux.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "./gifdec.h"
#include "./unicode.h"
#include "./unicode_gif.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -36,13 +33,11 @@ static const int kNumChannels = 4;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Common utilities. // Common utilities.
#if defined(WEBP_HAVE_GIF)
// Returns true if the frame covers the full canvas. // Returns true if the frame covers the full canvas.
static int IsFullFrame(int width, int height, static int IsFullFrame(int width, int height,
int canvas_width, int canvas_height) { int canvas_width, int canvas_height) {
return (width == canvas_width && height == canvas_height); return (width == canvas_width && height == canvas_height);
} }
#endif // WEBP_HAVE_GIF
static int CheckSizeForOverflow(uint64_t size) { static int CheckSizeForOverflow(uint64_t size) {
return (size == (size_t)size); return (size == (size_t)size);
@ -60,15 +55,15 @@ static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
!CheckSizeForOverflow(total_frame_size)) { !CheckSizeForOverflow(total_frame_size)) {
return 0; return 0;
} }
mem = (uint8_t*)WebPMalloc((size_t)total_size); mem = (uint8_t*)malloc((size_t)total_size);
frames = (DecodedFrame*)WebPMalloc((size_t)total_frame_size); frames = (DecodedFrame*)malloc((size_t)total_frame_size);
if (mem == NULL || frames == NULL) { if (mem == NULL || frames == NULL) {
WebPFree(mem); free(mem);
WebPFree(frames); free(frames);
return 0; return 0;
} }
WebPFree(image->raw_mem); free(image->raw_mem);
image->num_frames = num_frames; image->num_frames = num_frames;
image->frames = frames; image->frames = frames;
for (i = 0; i < num_frames; ++i) { for (i = 0; i < num_frames; ++i) {
@ -82,15 +77,14 @@ static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
void ClearAnimatedImage(AnimatedImage* const image) { void ClearAnimatedImage(AnimatedImage* const image) {
if (image != NULL) { if (image != NULL) {
WebPFree(image->raw_mem); free(image->raw_mem);
WebPFree(image->frames); free(image->frames);
image->num_frames = 0; image->num_frames = 0;
image->frames = NULL; image->frames = NULL;
image->raw_mem = NULL; image->raw_mem = NULL;
} }
} }
#if defined(WEBP_HAVE_GIF)
// Clear the canvas to transparent. // Clear the canvas to transparent.
static void ZeroFillCanvas(uint8_t* rgba, static void ZeroFillCanvas(uint8_t* rgba,
uint32_t canvas_width, uint32_t canvas_height) { uint32_t canvas_width, uint32_t canvas_height) {
@ -132,7 +126,6 @@ static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride,
dst += stride; dst += stride;
} }
} }
#endif // WEBP_HAVE_GIF
// Canonicalize all transparent pixels to transparent black to aid comparison. // Canonicalize all transparent pixels to transparent black to aid comparison.
static void CleanupTransparentPixels(uint32_t* rgba, static void CleanupTransparentPixels(uint32_t* rgba,
@ -154,42 +147,40 @@ static int DumpFrame(const char filename[], const char dump_folder[],
int ok = 0; int ok = 0;
size_t max_len; size_t max_len;
int y; int y;
const W_CHAR* base_name = NULL; const char* base_name = NULL;
W_CHAR* file_name = NULL; char* file_name = NULL;
FILE* f = NULL; FILE* f = NULL;
const char* row; const char* row;
if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR("."); base_name = strrchr(filename, '/');
base_name = (base_name == NULL) ? filename : base_name + 1;
base_name = WSTRRCHR(filename, '/'); max_len = strlen(dump_folder) + 1 + strlen(base_name)
base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1;
max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name)
+ strlen("_frame_") + strlen(".pam") + 8; + strlen("_frame_") + strlen(".pam") + 8;
file_name = (W_CHAR*)WebPMalloc(max_len * sizeof(*file_name)); file_name = (char*)malloc(max_len * sizeof(*file_name));
if (file_name == NULL) goto End; if (file_name == NULL) goto End;
if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam", if (snprintf(file_name, max_len, "%s/%s_frame_%d.pam",
(const W_CHAR*)dump_folder, base_name, frame_num) < 0) { dump_folder, base_name, frame_num) < 0) {
fprintf(stderr, "Error while generating file name\n"); fprintf(stderr, "Error while generating file name\n");
goto End; goto End;
} }
f = WFOPEN(file_name, "wb"); f = fopen(file_name, "wb");
if (f == NULL) { if (f == NULL) {
WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name); fprintf(stderr, "Error opening file for writing: %s\n", file_name);
ok = 0; ok = 0;
goto End; goto End;
} }
if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n" if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n"
"DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", "DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
canvas_width, canvas_height) < 0) { canvas_width, canvas_height) < 0) {
WFPRINTF(stderr, "Write error for file %s\n", file_name); fprintf(stderr, "Write error for file %s\n", file_name);
goto End; goto End;
} }
row = (const char*)rgba; row = (const char*)rgba;
for (y = 0; y < canvas_height; ++y) { for (y = 0; y < canvas_height; ++y) {
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) { if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
WFPRINTF(stderr, "Error writing to file: %s\n", file_name); fprintf(stderr, "Error writing to file: %s\n", file_name);
goto End; goto End;
} }
row += canvas_width * kNumChannels; row += canvas_width * kNumChannels;
@ -197,7 +188,7 @@ static int DumpFrame(const char filename[], const char dump_folder[],
ok = 1; ok = 1;
End: End:
if (f != NULL) fclose(f); if (f != NULL) fclose(f);
WebPFree(file_name); free(file_name);
return ok; return ok;
} }
@ -209,7 +200,7 @@ static int IsWebP(const WebPData* const webp_data) {
return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0); return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0);
} }
// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct. // Read animated WebP bitstream 'file_str' into 'AnimatedImage' struct.
static int ReadAnimatedWebP(const char filename[], static int ReadAnimatedWebP(const char filename[],
const WebPData* const webp_data, const WebPData* const webp_data,
AnimatedImage* const image, int dump_frames, AnimatedImage* const image, int dump_frames,
@ -225,7 +216,7 @@ static int ReadAnimatedWebP(const char filename[],
dec = WebPAnimDecoderNew(webp_data, NULL); dec = WebPAnimDecoderNew(webp_data, NULL);
if (dec == NULL) { if (dec == NULL) {
WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename); fprintf(stderr, "Error parsing image: %s\n", filename);
goto End; goto End;
} }
@ -241,7 +232,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)) goto End; if (!AllocateFrames(image, anim_info.frame_count)) return 0;
// Decode frames. // Decode frames.
while (WebPAnimDecoderHasMoreFrames(dec)) { while (WebPAnimDecoderHasMoreFrames(dec)) {
@ -278,7 +269,6 @@ static int ReadAnimatedWebP(const char filename[],
prev_frame_timestamp = timestamp; prev_frame_timestamp = timestamp;
} }
ok = dump_ok; ok = dump_ok;
if (ok) image->format = ANIM_WEBP;
End: End:
WebPAnimDecoderDelete(dec); WebPAnimDecoderDelete(dec);
@ -288,7 +278,7 @@ static int ReadAnimatedWebP(const char filename[],
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// GIF Decoding. // GIF Decoding.
#if defined(WEBP_HAVE_GIF) #ifdef WEBP_HAVE_GIF
// Returns true if this is a valid GIF bitstream. // Returns true if this is a valid GIF bitstream.
static int IsGIF(const WebPData* const data) { static int IsGIF(const WebPData* const data) {
@ -373,6 +363,26 @@ static int DGifSavedExtensionToGCB(GifFileType* GifFile, int ImageIndex,
#define DGifCloseFile(a, b) DGifCloseFile(a) #define DGifCloseFile(a, b) DGifCloseFile(a)
#endif #endif
static void GIFDisplayError(const GifFileType* const gif, int gif_error) {
// libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
#if LOCAL_GIF_PREREQ(4, 2)
#if LOCAL_GIF_PREREQ(5, 0)
const char* error_str =
GifErrorString((gif == NULL) ? gif_error : gif->Error);
#else
const char* error_str = GifErrorString();
(void)gif;
#endif
if (error_str == NULL) error_str = "Unknown error";
fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str);
#else
(void)gif;
fprintf(stderr, "GIFLib Error %d: ", gif_error);
PrintGifError();
fprintf(stderr, "\n");
#endif
}
static int IsKeyFrameGIF(const GifImageDesc* prev_desc, int prev_dispose, static int IsKeyFrameGIF(const GifImageDesc* prev_desc, int prev_dispose,
const DecodedFrame* const prev_frame, const DecodedFrame* const prev_frame,
int canvas_width, int canvas_height) { int canvas_width, int canvas_height) {
@ -405,7 +415,7 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
return 0xffffffff; // Invalid: assume white. return 0xffffffff; // Invalid: assume white.
} else { } else {
const GifColorType color = color_map->Colors[gif->SBackGroundColor]; const GifColorType color = color_map->Colors[gif->SBackGroundColor];
return (0xffu << 24) | return (0xff << 24) |
(color.Red << 16) | (color.Red << 16) |
(color.Green << 8) | (color.Green << 8) |
(color.Blue << 0); (color.Blue << 0);
@ -413,11 +423,6 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
} }
// Find appropriate app extension and get loop count from the next extension. // Find appropriate app extension and get loop count from the next extension.
// We use Chrome's interpretation of the 'loop_count' semantics:
// if not present -> loop once
// if present and loop_count == 0, return 0 ('infinite').
// if present and loop_count != 0, it's the number of *extra* loops
// so we need to return loop_count + 1 as total loop number.
static uint32_t GetLoopCountGIF(const GifFileType* const gif) { static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
int i; int i;
for (i = 0; i < gif->ImageCount; ++i) { for (i = 0; i < gif->ImageCount; ++i) {
@ -435,13 +440,12 @@ static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
if (signature_is_ok && if (signature_is_ok &&
eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 && eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 &&
eb2->Bytes[0] == 1) { eb2->Bytes[0] == 1) {
const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) + return ((uint32_t)(eb2->Bytes[2]) << 8) +
((uint32_t)(eb2->Bytes[1]) << 0); ((uint32_t)(eb2->Bytes[1]) << 0);
return (extra_loop > 0) ? extra_loop + 1 : 0;
} }
} }
} }
return 1; // Default. return 0; // Default.
} }
// Get duration of 'n'th frame in milliseconds. // Get duration of 'n'th frame in milliseconds.
@ -513,15 +517,15 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
int gif_error; int gif_error;
GifFileType* gif; GifFileType* gif;
gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL); gif = DGifOpenFileName(filename, NULL);
if (gif == NULL) { if (gif == NULL) {
WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename); fprintf(stderr, "Could not read file: %s.\n", filename);
return 0; return 0;
} }
gif_error = DGifSlurp(gif); gif_error = DGifSlurp(gif);
if (gif_error != GIF_OK) { if (gif_error != GIF_OK) {
WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename); fprintf(stderr, "Could not parse image: %s.\n", filename);
GIFDisplayError(gif, gif_error); GIFDisplayError(gif, gif_error);
DGifCloseFile(gif, NULL); DGifCloseFile(gif, NULL);
return 0; return 0;
@ -558,10 +562,7 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
} }
} }
// Allocate frames. // Allocate frames.
if (!AllocateFrames(image, frame_count)) { 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;
@ -580,9 +581,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
curr_frame = &image->frames[i]; curr_frame = &image->frames[i];
curr_rgba = curr_frame->rgba; curr_rgba = curr_frame->rgba;
curr_frame->duration = GetFrameDurationGIF(gif, i); curr_frame->duration = GetFrameDurationGIF(gif, i);
// Force frames with a small or no duration to 100ms to be consistent
// with web browsers and other transcoding tools (like gif2webp itself).
if (curr_frame->duration <= 10) curr_frame->duration = 100;
if (i == 0) { // Initialize as transparent. if (i == 0) { // Initialize as transparent.
curr_frame->is_key_frame = 1; curr_frame->is_key_frame = 1;
@ -674,7 +672,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
} }
} }
} }
image->format = ANIM_GIF;
DGifCloseFile(gif, NULL); DGifCloseFile(gif, NULL);
return 1; return 1;
} }
@ -710,7 +707,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
memset(image, 0, sizeof(*image)); memset(image, 0, sizeof(*image));
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) { if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename); fprintf(stderr, "Error reading file: %s\n", filename);
return 0; return 0;
} }
@ -720,9 +717,9 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
} else if (IsGIF(&webp_data)) { } else if (IsGIF(&webp_data)) {
ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder); ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder);
} else { } else {
WFPRINTF(stderr, fprintf(stderr,
"Unknown file type: %s. Supported file types are WebP and GIF\n", "Unknown file type: %s. Supported file types are WebP and GIF\n",
(const W_CHAR*)filename); filename);
ok = 0; ok = 0;
} }
if (!ok) ClearAnimatedImage(image); if (!ok) ClearAnimatedImage(image);
@ -774,9 +771,3 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
*psnr = 4.3429448 * log(255. * 255. / sse); *psnr = 4.3429448 * log(255. * 255. / sse);
} }
} }
void GetAnimatedImageVersions(int* const decoder_version,
int* const demux_version) {
*decoder_version = WebPGetDecoderVersion();
*demux_version = WebPGetDemuxVersion();
}

View File

@ -22,11 +22,6 @@
extern "C" { extern "C" {
#endif #endif
typedef enum {
ANIM_GIF,
ANIM_WEBP
} AnimatedFileFormat;
typedef struct { typedef struct {
uint8_t* rgba; // Decoded and reconstructed full frame. uint8_t* rgba; // Decoded and reconstructed full frame.
int duration; // Frame duration in milliseconds. int duration; // Frame duration in milliseconds.
@ -34,7 +29,6 @@ typedef struct {
} DecodedFrame; } DecodedFrame;
typedef struct { typedef struct {
AnimatedFileFormat format;
uint32_t canvas_width; uint32_t canvas_width;
uint32_t canvas_height; uint32_t canvas_height;
uint32_t bgcolor; uint32_t bgcolor;
@ -62,10 +56,6 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
uint32_t width, uint32_t height, int premultiply, uint32_t width, uint32_t height, int premultiply,
int* const max_diff, double* const psnr); int* const max_diff, double* const psnr);
// Return library versions used by anim_util.
void GetAnimatedImageVersions(int* const decoder_version,
int* const demux_version);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -12,7 +12,6 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -24,10 +23,7 @@
#include "../examples/example_util.h" #include "../examples/example_util.h"
#include "../imageio/image_dec.h" #include "../imageio/image_dec.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "../imageio/webpdec.h"
#include "./stopwatch.h" #include "./stopwatch.h"
#include "./unicode.h"
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h" #include "webp/encode.h"
#ifndef WEBP_DLL #ifndef WEBP_DLL
@ -92,10 +88,9 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
} }
} }
if (!ok) { if (!ok) {
WFPRINTF(stderr, "Error! Could not process file %s\n", fprintf(stderr, "Error! Could not process file %s\n", filename);
(const W_CHAR*)filename);
} }
WebPFree((void*)data); free((void*)data);
return ok; return ok;
} }
@ -119,10 +114,9 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
} }
End: End:
if (!ok) { if (!ok) {
WFPRINTF(stderr, "Error! Could not process file %s\n", fprintf(stderr, "Error! Could not process file %s\n", filename);
(const W_CHAR*)filename);
} }
WebPFree((void*)data); free((void*)data);
return ok; return ok;
} }
@ -131,8 +125,7 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
static void AllocExtraInfo(WebPPicture* const pic) { static void AllocExtraInfo(WebPPicture* const pic) {
const int mb_w = (pic->width + 15) / 16; const int mb_w = (pic->width + 15) / 16;
const int mb_h = (pic->height + 15) / 16; const int mb_h = (pic->height + 15) / 16;
pic->extra_info = pic->extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(*pic->extra_info));
(uint8_t*)WebPMalloc(mb_w * mb_h * sizeof(*pic->extra_info));
} }
static void PrintByteCount(const int bytes[4], int total_size, static void PrintByteCount(const int bytes[4], int total_size,
@ -147,11 +140,10 @@ static void PrintByteCount(const int bytes[4], int total_size,
fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size); fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size);
} }
static void PrintPercents(const int counts[4]) { static void PrintPercents(const int counts[4], int total) {
int s; int s;
const int total = counts[0] + counts[1] + counts[2] + counts[3];
for (s = 0; s < 4; ++s) { for (s = 0; s < 4; ++s) {
fprintf(stderr, "| %3d%%", (int)(100. * counts[s] / total + .5)); fprintf(stderr, "| %2d%%", 100 * counts[s] / total);
} }
fprintf(stderr, "| %7d\n", total); fprintf(stderr, "| %7d\n", total);
} }
@ -192,10 +184,9 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic,
if (short_output) { if (short_output) {
fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]); fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
} else { } else {
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); fprintf(stderr, "File: %s\n", file_name);
fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height); fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size, fprintf(stderr, "Output: %d bytes\n", stats->coded_size);
8.f * stats->coded_size / pic->width / pic->height);
PrintFullLosslessInfo(stats, "ARGB"); PrintFullLosslessInfo(stats, "ARGB");
} }
} }
@ -211,23 +202,20 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
const int num_i16 = stats->block_count[1]; const int num_i16 = stats->block_count[1];
const int num_skip = stats->block_count[2]; const int num_skip = stats->block_count[2];
const int total = num_i4 + num_i16; const int total = num_i4 + num_i16;
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); fprintf(stderr, "File: %s\n", file_name);
fprintf(stderr, "Dimension: %d x %d%s\n", fprintf(stderr, "Dimension: %d x %d%s\n",
pic->width, pic->height, pic->width, pic->height,
stats->alpha_data_size ? " (with alpha)" : ""); stats->alpha_data_size ? " (with alpha)" : "");
fprintf(stderr, "Output: " fprintf(stderr, "Output: "
"%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n" "%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n",
" (%.2f bpp)\n",
stats->coded_size, stats->coded_size,
stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3], stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3]);
8.f * stats->coded_size / pic->width / pic->height);
if (total > 0) { if (total > 0) {
int totals[4] = { 0, 0, 0, 0 }; int totals[4] = { 0, 0, 0, 0 };
fprintf(stderr, "block count: intra4: %6d (%.2f%%)\n" fprintf(stderr, "block count: intra4: %d\n"
" intra16: %6d (%.2f%%)\n" " intra16: %d (-> %.2f%%)\n",
" skipped: %6d (%.2f%%)\n", num_i4, num_i16, 100.f * num_i16 / total);
num_i4, 100.f * num_i4 / total, fprintf(stderr, " skipped block: %d (%.2f%%)\n",
num_i16, 100.f * num_i16 / total,
num_skip, 100.f * num_skip / total); num_skip, 100.f * num_skip / total);
fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n" fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
" mode-partition: %6d (%.1f%%)\n", " mode-partition: %6d (%.1f%%)\n",
@ -251,7 +239,7 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals); PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
} }
fprintf(stderr, " macroblocks: "); fprintf(stderr, " macroblocks: ");
PrintPercents(stats->segment_size); PrintPercents(stats->segment_size, total);
fprintf(stderr, " quantizer: "); fprintf(stderr, " quantizer: ");
PrintValues(stats->segment_quant); PrintValues(stats->segment_quant);
fprintf(stderr, " filter level: "); fprintf(stderr, " filter level: ");
@ -316,7 +304,7 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
const int alpha_height = const int alpha_height =
WebPPictureHasTransparency(picture) ? picture->height : 0; WebPPictureHasTransparency(picture) ? picture->height : 0;
const int height = picture->height + uv_height + alpha_height; const int height = picture->height + uv_height + alpha_height;
FILE* const f = WFOPEN(PGM_name, "wb"); FILE* const f = fopen(PGM_name, "wb");
if (f == NULL) return 0; if (f == NULL) return 0;
fprintf(f, "P5\n%d %d\n255\n", stride, height); fprintf(f, "P5\n%d %d\n255\n", stride, height);
for (y = 0; y < picture->height; ++y) { for (y = 0; y < picture->height; ++y) {
@ -475,9 +463,8 @@ static int WriteWebPWithMetadata(FILE* const out,
} else { } else {
const int is_lossless = !memcmp(webp, "VP8L", kTagSize); const int is_lossless = !memcmp(webp, "VP8L", kTagSize);
if (is_lossless) { if (is_lossless) {
// Presence of alpha is stored in the 37th bit (29th after the // Presence of alpha is stored in the 29th bit of VP8L data.
// signature) of VP8L data. if (webp[kChunkHeaderSize + 3] & (1 << 5)) flags |= kAlphaFlag;
if (webp[kChunkHeaderSize + 4] & (1 << 4)) flags |= kAlphaFlag;
} }
ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1); ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1);
ok = ok && WriteLE32(out, flags); ok = ok && WriteLE32(out, flags);
@ -499,11 +486,11 @@ static int WriteWebPWithMetadata(FILE* const out,
*metadata_written |= METADATA_XMP; *metadata_written |= METADATA_XMP;
} }
return ok; return ok;
} } else {
// No metadata, just write the original image file. // No metadata, just write the original image file.
return (fwrite(webp, webp_size, 1, out) == 1); return (fwrite(webp, webp_size, 1, out) == 1);
} }
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -528,7 +515,6 @@ static void HelpLong(void) {
printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n"); printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n");
printf("If input size (-s) for an image is not specified, it is\n" printf("If input size (-s) for an image is not specified, it is\n"
"assumed to be a PNG, JPEG, TIFF or WebP file.\n"); "assumed to be a PNG, JPEG, TIFF or WebP file.\n");
printf("Note: Animated PNG and WebP files are not supported.\n");
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
printf("Windows builds can take as input any of the files handled by WIC.\n"); printf("Windows builds can take as input any of the files handled by WIC.\n");
#endif #endif
@ -569,10 +555,8 @@ static void HelpLong(void) {
printf(" " printf(" "
"the first partition (0=no degradation ... 100=full)\n"); "the first partition (0=no degradation ... 100=full)\n");
printf(" -pass <int> ............ analysis pass number (1..10)\n"); printf(" -pass <int> ............ analysis pass number (1..10)\n");
printf(" -qrange <min> <max> .... specifies the permissible quality range\n"
" (default: 0 100)\n");
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n"); printf(" -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");
@ -592,8 +576,12 @@ static void HelpLong(void) {
" green=0xe0 and blue=0xd0\n"); " green=0xe0 and blue=0xd0\n");
printf(" -noalpha ............... discard any transparency information\n"); printf(" -noalpha ............... discard any transparency information\n");
printf(" -lossless .............. encode image losslessly, default=off\n"); printf(" -lossless .............. encode image losslessly, default=off\n");
printf(" -near_lossless <int> ... use near-lossless image preprocessing\n" printf(" -near_lossless <int> ... use near-lossless image\n"
" (0..100=off), default=100\n"); " preprocessing (0..100=off), "
"default=100\n");
#ifdef WEBP_EXPERIMENTAL_FEATURES /* not documented yet */
printf(" -delta_palette ......... use delta palettization\n");
#endif // WEBP_EXPERIMENTAL_FEATURES
printf(" -hint <string> ......... specify image characteristics hint,\n"); printf(" -hint <string> ......... specify image characteristics hint,\n");
printf(" one of: photo, picture or graph\n"); printf(" one of: photo, picture or graph\n");
@ -620,7 +608,6 @@ 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());
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -670,38 +657,35 @@ int main(int argc, const char* argv[]) {
WebPConfig config; WebPConfig config;
WebPAuxStats stats; WebPAuxStats stats;
WebPMemoryWriter memory_writer; WebPMemoryWriter memory_writer;
int use_memory_writer;
Metadata metadata; Metadata metadata;
Stopwatch stop_watch; Stopwatch stop_watch;
INIT_WARGV(argc, argv);
MetadataInit(&metadata); MetadataInit(&metadata);
WebPMemoryWriterInit(&memory_writer); WebPMemoryWriterInit(&memory_writer);
if (!WebPPictureInit(&picture) || if (!WebPPictureInit(&picture) ||
!WebPPictureInit(&original_picture) || !WebPPictureInit(&original_picture) ||
!WebPConfigInit(&config)) { !WebPConfigInit(&config)) {
fprintf(stderr, "Error! Version mismatch!\n"); fprintf(stderr, "Error! Version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
if (argc == 1) { if (argc == 1) {
HelpShort(); HelpShort();
FREE_WARGV_AND_RETURN(0); return 0;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
HelpShort(); HelpShort();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) { } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
HelpLong(); HelpLong();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-o") && c + 1 < argc) { } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = (const char*)GET_WARGV(argv, ++c); out_file = argv[++c];
} else if (!strcmp(argv[c], "-d") && c + 1 < argc) { } else if (!strcmp(argv[c], "-d") && c < argc - 1) {
dump_file = (const char*)GET_WARGV(argv, ++c); dump_file = argv[++c];
config.show_compressed = 1; config.show_compressed = 1;
} else if (!strcmp(argv[c], "-print_psnr")) { } else if (!strcmp(argv[c], "-print_psnr")) {
config.show_compressed = 1; config.show_compressed = 1;
@ -714,7 +698,7 @@ int main(int argc, const char* argv[]) {
print_distortion = 2; print_distortion = 2;
} else if (!strcmp(argv[c], "-short")) { } else if (!strcmp(argv[c], "-short")) {
++short_output; ++short_output;
} else if (!strcmp(argv[c], "-s") && c + 2 < argc) { } else if (!strcmp(argv[c], "-s") && c < argc - 2) {
picture.width = ExUtilGetInt(argv[++c], 0, &parse_error); picture.width = ExUtilGetInt(argv[++c], 0, &parse_error);
picture.height = ExUtilGetInt(argv[++c], 0, &parse_error); picture.height = ExUtilGetInt(argv[++c], 0, &parse_error);
if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 || if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 ||
@ -724,30 +708,30 @@ int main(int argc, const char* argv[]) {
picture.width, picture.height); picture.width, picture.height);
goto Error; goto Error;
} }
} else if (!strcmp(argv[c], "-m") && c + 1 < argc) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = ExUtilGetInt(argv[++c], 0, &parse_error); config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
use_lossless_preset = 0; // disable -z option use_lossless_preset = 0; // disable -z option
} else if (!strcmp(argv[c], "-q") && c + 1 < argc) { } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = ExUtilGetFloat(argv[++c], &parse_error); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
use_lossless_preset = 0; // disable -z option use_lossless_preset = 0; // disable -z option
} else if (!strcmp(argv[c], "-z") && c + 1 < argc) { } else if (!strcmp(argv[c], "-z") && c < argc - 1) {
lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error); lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error);
if (use_lossless_preset != 0) use_lossless_preset = 1; if (use_lossless_preset != 0) use_lossless_preset = 1;
} else if (!strcmp(argv[c], "-alpha_q") && c + 1 < argc) { } else if (!strcmp(argv[c], "-alpha_q") && c < argc - 1) {
config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error); config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-alpha_method") && c + 1 < argc) { } else if (!strcmp(argv[c], "-alpha_method") && c < argc - 1) {
config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error); config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-alpha_cleanup")) { } else if (!strcmp(argv[c], "-alpha_cleanup")) {
// This flag is obsolete, does opposite of -exact. // This flag is obsolete, does opposite of -exact.
config.exact = 0; config.exact = 0;
} else if (!strcmp(argv[c], "-exact")) { } else if (!strcmp(argv[c], "-exact")) {
config.exact = 1; config.exact = 1;
} else if (!strcmp(argv[c], "-blend_alpha") && c + 1 < argc) { } else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 1) {
blend_alpha = 1; blend_alpha = 1;
// background color is given in hex with an optional '0x' prefix // background color is given in hex with an optional '0x' prefix
background_color = ExUtilGetInt(argv[++c], 16, &parse_error); background_color = ExUtilGetInt(argv[++c], 16, &parse_error);
background_color = background_color & 0x00ffffffu; background_color = background_color & 0x00ffffffu;
} else if (!strcmp(argv[c], "-alpha_filter") && c + 1 < argc) { } else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) {
++c; ++c;
if (!strcmp(argv[c], "none")) { if (!strcmp(argv[c], "none")) {
config.alpha_filtering = 0; config.alpha_filtering = 0;
@ -763,10 +747,15 @@ int main(int argc, const char* argv[]) {
keep_alpha = 0; keep_alpha = 0;
} else if (!strcmp(argv[c], "-lossless")) { } else if (!strcmp(argv[c], "-lossless")) {
config.lossless = 1; config.lossless = 1;
} else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) { } else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error); config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
config.lossless = 1; // use near-lossless only with lossless config.lossless = 1; // use near-lossless only with lossless
} else if (!strcmp(argv[c], "-hint") && c + 1 < argc) { #ifdef WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-delta_palette")) {
config.use_delta_palette = 1;
config.lossless = 1; // delta-palette is for lossless only
#endif // WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
++c; ++c;
if (!strcmp(argv[c], "photo")) { if (!strcmp(argv[c], "photo")) {
config.image_hint = WEBP_HINT_PHOTO; config.image_hint = WEBP_HINT_PHOTO;
@ -778,13 +767,13 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]); fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]);
goto Error; goto Error;
} }
} else if (!strcmp(argv[c], "-size") && c + 1 < argc) { } else if (!strcmp(argv[c], "-size") && c < argc - 1) {
config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error); config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-psnr") && c + 1 < argc) { } else if (!strcmp(argv[c], "-psnr") && c < argc - 1) {
config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error); config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-sns") && c + 1 < argc) { } else if (!strcmp(argv[c], "-sns") && c < argc - 1) {
config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error); config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-f") && c + 1 < argc) { } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-af")) { } else if (!strcmp(argv[c], "-af")) {
config.autofilter = 1; config.autofilter = 1;
@ -798,32 +787,27 @@ int main(int argc, const char* argv[]) {
config.filter_type = 1; config.filter_type = 1;
} else if (!strcmp(argv[c], "-nostrong")) { } else if (!strcmp(argv[c], "-nostrong")) {
config.filter_type = 0; config.filter_type = 0;
} else if (!strcmp(argv[c], "-sharpness") && c + 1 < argc) { } else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error); config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-sharp_yuv")) { } else if (!strcmp(argv[c], "-sharp_yuv")) {
config.use_sharp_yuv = 1; config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-pass") && c + 1 < argc) { } else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
config.pass = ExUtilGetInt(argv[++c], 0, &parse_error); config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-qrange") && c + 2 < argc) { } else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
config.qmin = ExUtilGetInt(argv[++c], 0, &parse_error);
config.qmax = ExUtilGetInt(argv[++c], 0, &parse_error);
if (config.qmin < 0) config.qmin = 0;
if (config.qmax > 100) config.qmax = 100;
} else if (!strcmp(argv[c], "-pre") && c + 1 < argc) {
config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error); config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-segments") && c + 1 < argc) { } else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
config.segments = ExUtilGetInt(argv[++c], 0, &parse_error); config.segments = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-partition_limit") && c + 1 < argc) { } else if (!strcmp(argv[c], "-partition_limit") && c < argc - 1) {
config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error); config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-map") && c + 1 < argc) { } else if (!strcmp(argv[c], "-map") && c < argc - 1) {
picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error); picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-crop") && c + 4 < argc) { } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
crop = 1; crop = 1;
crop_x = ExUtilGetInt(argv[++c], 0, &parse_error); crop_x = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_y = ExUtilGetInt(argv[++c], 0, &parse_error); crop_y = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_w = ExUtilGetInt(argv[++c], 0, &parse_error); crop_w = ExUtilGetInt(argv[++c], 0, &parse_error);
crop_h = ExUtilGetInt(argv[++c], 0, &parse_error); crop_h = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-resize") && c + 2 < argc) { } else if (!strcmp(argv[c], "-resize") && c < argc - 2) {
resize_w = ExUtilGetInt(argv[++c], 0, &parse_error); resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
resize_h = ExUtilGetInt(argv[++c], 0, &parse_error); resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
#ifndef WEBP_DLL #ifndef WEBP_DLL
@ -832,18 +816,14 @@ int main(int argc, const char* argv[]) {
#endif #endif
} else if (!strcmp(argv[c], "-version")) { } else if (!strcmp(argv[c], "-version")) {
const int version = WebPGetEncoderVersion(); const int version = WebPGetEncoderVersion();
const int sharpyuv_version = SharpYuvGetVersion();
printf("%d.%d.%d\n", printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
printf("libsharpyuv: %d.%d.%d\n", return 0;
(sharpyuv_version >> 24) & 0xff, (sharpyuv_version >> 16) & 0xffff,
sharpyuv_version & 0xff);
FREE_WARGV_AND_RETURN(0);
} else if (!strcmp(argv[c], "-progress")) { } else if (!strcmp(argv[c], "-progress")) {
show_progress = 1; show_progress = 1;
} else if (!strcmp(argv[c], "-quiet")) { } else if (!strcmp(argv[c], "-quiet")) {
quiet = 1; quiet = 1;
} else if (!strcmp(argv[c], "-preset") && c + 1 < argc) { } else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
WebPPreset preset; WebPPreset preset;
++c; ++c;
if (!strcmp(argv[c], "default")) { if (!strcmp(argv[c], "default")) {
@ -866,7 +846,7 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error! Could initialize configuration with preset.\n"); fprintf(stderr, "Error! Could initialize configuration with preset.\n");
goto Error; goto Error;
} }
} else if (!strcmp(argv[c], "-metadata") && c + 1 < argc) { } else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
static const struct { static const struct {
const char* option; const char* option;
int flag; int flag;
@ -900,7 +880,8 @@ int main(int argc, const char* argv[]) {
if (i == kNumTokens) { if (i == kNumTokens) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start); (int)(token - start), start);
FREE_WARGV_AND_RETURN(-1); HelpLong();
return -1;
} }
start = token + 1; start = token + 1;
} }
@ -914,19 +895,19 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-v")) { } else if (!strcmp(argv[c], "-v")) {
verbose = 1; verbose = 1;
} else if (!strcmp(argv[c], "--")) { } else if (!strcmp(argv[c], "--")) {
if (c + 1 < argc) in_file = (const char*)GET_WARGV(argv, ++c); if (c < argc - 1) in_file = argv[++c];
break; break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
HelpLong(); HelpLong();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
in_file = (const char*)GET_WARGV(argv, c); in_file = argv[c];
} }
if (parse_error) { if (parse_error) {
HelpLong(); HelpLong();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
} }
if (in_file == NULL) { if (in_file == NULL) {
@ -976,8 +957,7 @@ int main(int argc, const char* argv[]) {
} }
if (!ReadPicture(in_file, &picture, keep_alpha, if (!ReadPicture(in_file, &picture, keep_alpha,
(keep_metadata == 0) ? NULL : &metadata)) { (keep_metadata == 0) ? NULL : &metadata)) {
WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n", fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
(const W_CHAR*)in_file);
goto Error; goto Error;
} }
picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL; picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
@ -990,41 +970,28 @@ int main(int argc, const char* argv[]) {
const double read_time = StopwatchReadAndReset(&stop_watch); const double read_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to read input: %.3fs\n", read_time); fprintf(stderr, "Time to read input: %.3fs\n", read_time);
} }
// The bitstream should be kept in memory when metadata must be appended
// before writing it to a file/stream, and/or when the near-losslessly encoded
// bitstream must be decoded for distortion computation (lossy will modify the
// 'picture' but not the lossless pipeline).
// Otherwise directly write the bitstream to a file.
use_memory_writer = (out_file != NULL && keep_metadata) ||
(!quiet && print_distortion >= 0 && config.lossless &&
config.near_lossless < 100);
// Open the output // Open the output
if (out_file != NULL) { if (out_file != NULL) {
const int use_stdout = !WSTRCMP(out_file, "-"); const int use_stdout = !strcmp(out_file, "-");
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb"); out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
if (out == NULL) { if (out == NULL) {
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
(const W_CHAR*)out_file);
goto Error; goto Error;
} else { } else {
if (!short_output && !quiet) { if (!short_output && !quiet) {
WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file); fprintf(stderr, "Saving file '%s'\n", out_file);
} }
} }
if (use_memory_writer) { if (keep_metadata == 0) {
picture.writer = WebPMemoryWrite;
picture.custom_ptr = (void*)&memory_writer;
} else {
picture.writer = MyWriter; picture.writer = MyWriter;
picture.custom_ptr = (void*)out; picture.custom_ptr = (void*)out;
} else {
picture.writer = WebPMemoryWrite;
picture.custom_ptr = (void*)&memory_writer;
} }
} else { } else {
out = NULL; out = NULL;
if (use_memory_writer) {
picture.writer = WebPMemoryWrite;
picture.custom_ptr = (void*)&memory_writer;
}
if (!quiet && !short_output) { if (!quiet && !short_output) {
fprintf(stderr, "No output file specified (no -o flag). Encoding will\n"); fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
fprintf(stderr, "be performed, but its results discarded.\n\n"); fprintf(stderr, "be performed, but its results discarded.\n\n");
@ -1047,53 +1014,10 @@ int main(int argc, const char* argv[]) {
} }
} }
if ((resize_w | resize_h) > 0) { if ((resize_w | resize_h) > 0) {
WebPPicture picture_no_alpha;
if (config.exact) {
// If -exact, we can't premultiply RGB by A otherwise RGB is lost if A=0.
// We rescale an opaque copy and assemble scaled A and non-premultiplied
// RGB channels. This is slower but it's a very uncommon use case. Color
// leak at sharp alpha edges is possible.
if (!WebPPictureCopy(&picture, &picture_no_alpha)) {
fprintf(stderr, "Error! Cannot copy temporary picture\n");
goto Error;
}
// We enforced picture.use_argb = 1 above. Now, remove the alpha values.
{
int x, y;
uint32_t* argb_no_alpha = picture_no_alpha.argb;
for (y = 0; y < picture_no_alpha.height; ++y) {
for (x = 0; x < picture_no_alpha.width; ++x) {
argb_no_alpha[x] |= 0xff000000; // Opaque copy.
}
argb_no_alpha += picture_no_alpha.argb_stride;
}
}
if (!WebPPictureRescale(&picture_no_alpha, resize_w, resize_h)) {
fprintf(stderr, "Error! Cannot resize temporary picture\n");
goto Error;
}
}
if (!WebPPictureRescale(&picture, resize_w, resize_h)) { if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
fprintf(stderr, "Error! Cannot resize picture\n"); fprintf(stderr, "Error! Cannot resize picture\n");
goto Error; goto Error;
} }
if (config.exact) { // Put back the alpha information.
int x, y;
uint32_t* argb_no_alpha = picture_no_alpha.argb;
uint32_t* argb = picture.argb;
for (y = 0; y < picture_no_alpha.height; ++y) {
for (x = 0; x < picture_no_alpha.width; ++x) {
argb[x] = (argb[x] & 0xff000000) | (argb_no_alpha[x] & 0x00ffffff);
}
argb_no_alpha += picture_no_alpha.argb_stride;
argb += picture.argb_stride;
}
WebPPictureFree(&picture_no_alpha);
}
} }
if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) { if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) {
const double preproc_time = StopwatchReadAndReset(&stop_watch); const double preproc_time = StopwatchReadAndReset(&stop_watch);
@ -1103,12 +1027,8 @@ int main(int argc, const char* argv[]) {
if (picture.extra_info_type > 0) { if (picture.extra_info_type > 0) {
AllocExtraInfo(&picture); AllocExtraInfo(&picture);
} }
// Save original picture for later comparison. Only for lossy as lossless does if (print_distortion >= 0) { // Save original picture for later comparison
// not modify 'picture' (even near-lossless). WebPPictureCopy(&picture, &original_picture);
if (print_distortion >= 0 && !config.lossless &&
!WebPPictureCopy(&picture, &original_picture)) {
fprintf(stderr, "Error! Cannot copy temporary picture\n");
goto Error;
} }
// Compress. // Compress.
@ -1126,75 +1046,43 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time); fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time);
} }
// Get the decompressed image for the lossless pipeline. // Write info
if (!quiet && print_distortion >= 0 && config.lossless) {
if (config.near_lossless == 100) {
// Pure lossless: image was not modified, make 'original_picture' a view
// of 'picture' by copying all members except the freeable pointers.
original_picture = picture;
original_picture.memory_ = original_picture.memory_argb_ = NULL;
} else {
// Decode the bitstream stored in 'memory_writer' to get the altered image
// to 'picture'; save the 'original_picture' beforehand.
assert(use_memory_writer);
original_picture = picture;
if (!WebPPictureInit(&picture)) { // Do not free 'picture'.
fprintf(stderr, "Error! Version mismatch!\n");
goto Error;
}
picture.use_argb = 1;
if (!ReadWebP(
memory_writer.mem, memory_writer.size, &picture,
/*keep_alpha=*/WebPPictureHasTransparency(&original_picture),
/*metadata=*/NULL)) {
fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n");
fprintf(stderr, "Error code: %d (%s)\n", picture.error_code,
kErrorMessages[picture.error_code]);
goto Error;
}
picture.stats = original_picture.stats;
}
original_picture.stats = NULL;
}
// Write the YUV planes to a PGM file. Only available for lossy.
if (dump_file) { if (dump_file) {
if (picture.use_argb) { if (picture.use_argb) {
fprintf(stderr, "Warning: can't dump file (-d option) " fprintf(stderr, "Warning: can't dump file (-d option) in lossless mode.");
"in lossless mode.\n");
} else if (!DumpPicture(&picture, dump_file)) { } else if (!DumpPicture(&picture, dump_file)) {
WFPRINTF(stderr, "Warning, couldn't dump picture %s\n", fprintf(stderr, "Warning, couldn't dump picture %s\n", dump_file);
(const W_CHAR*)dump_file);
} }
} }
if (use_memory_writer && out != NULL && if (keep_metadata != 0) {
!WriteWebPWithMetadata(out, &picture, &memory_writer, &metadata, if (out != NULL) {
keep_metadata, &metadata_written)) { if (!WriteWebPWithMetadata(out, &picture, &memory_writer,
fprintf(stderr, "Error writing WebP file!\n"); &metadata, keep_metadata, &metadata_written)) {
fprintf(stderr, "Error writing WebP file with metadata!\n");
goto Error; goto Error;
} }
} else { // output is disabled, just display the metadata stats.
if (out == NULL && keep_metadata) {
// output is disabled, just display the metadata stats.
const struct { const struct {
const MetadataPayload* const payload; const MetadataPayload* const payload;
int flag; int flag;
} *iter, info[] = {{&metadata.exif, METADATA_EXIF}, } *iter, info[] = {
{ &metadata.exif, METADATA_EXIF },
{ &metadata.iccp, METADATA_ICC }, { &metadata.iccp, METADATA_ICC },
{ &metadata.xmp, METADATA_XMP }, { &metadata.xmp, METADATA_XMP },
{NULL, 0}}; { NULL, 0 }
};
uint32_t unused1 = 0; uint32_t unused1 = 0;
uint64_t unused2 = 0; uint64_t unused2 = 0;
for (iter = info; iter->payload != NULL; ++iter) { for (iter = info; iter->payload != NULL; ++iter) {
if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag), if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
/*flag=*/0, &unused1, &unused2)) { 0, &unused1, &unused2)) {
metadata_written |= iter->flag; metadata_written |= iter->flag;
} }
} }
} }
}
if (!quiet) { if (!quiet) {
if (!short_output || print_distortion < 0) { if (!short_output || print_distortion < 0) {
@ -1231,7 +1119,7 @@ int main(int argc, const char* argv[]) {
Error: Error:
WebPMemoryWriterClear(&memory_writer); WebPMemoryWriterClear(&memory_writer);
WebPFree(picture.extra_info); free(picture.extra_info);
MetadataFree(&metadata); MetadataFree(&metadata);
WebPPictureFree(&picture); WebPPictureFree(&picture);
WebPPictureFree(&original_picture); WebPPictureFree(&original_picture);
@ -1239,7 +1127,7 @@ int main(int argc, const char* argv[]) {
fclose(out); fclose(out);
} }
FREE_WARGV_AND_RETURN(return_value); return return_value;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -24,7 +24,6 @@
#include "../imageio/image_enc.h" #include "../imageio/image_enc.h"
#include "../imageio/webpdec.h" #include "../imageio/webpdec.h"
#include "./stopwatch.h" #include "./stopwatch.h"
#include "./unicode.h"
static int verbose = 0; static int verbose = 0;
static int quiet = 0; static int quiet = 0;
@ -43,7 +42,7 @@ extern void* VP8GetCPUInfo; // opaque forward declaration.
static int SaveOutput(const WebPDecBuffer* const buffer, static int SaveOutput(const WebPDecBuffer* const buffer,
WebPOutputFileFormat format, const char* const out_file) { WebPOutputFileFormat format, const char* const out_file) {
const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-"); const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
int ok = 1; int ok = 1;
Stopwatch stop_watch; Stopwatch stop_watch;
@ -57,7 +56,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
if (use_stdout) { if (use_stdout) {
fprintf(stderr, "Saved to stdout\n"); fprintf(stderr, "Saved to stdout\n");
} else { } else {
WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file); fprintf(stderr, "Saved file %s\n", out_file);
} }
} }
if (verbose) { if (verbose) {
@ -68,7 +67,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
if (use_stdout) { if (use_stdout) {
fprintf(stderr, "Error writing to stdout !!\n"); fprintf(stderr, "Error writing to stdout !!\n");
} else { } else {
WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file); fprintf(stderr, "Error writing file %s !!\n", out_file);
} }
} }
return ok; return ok;
@ -76,8 +75,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
static void Help(void) { static void Help(void) {
printf("Usage: dwebp in_file [options] [-o out_file]\n\n" printf("Usage: dwebp in_file [options] [-o out_file]\n\n"
"Decodes the WebP image file to PNG format [Default].\n" "Decodes the WebP image file to PNG format [Default]\n"
"Note: Animated WebP files are not supported.\n\n"
"Use following options to convert into alternate image formats:\n" "Use following options to convert into alternate image formats:\n"
" -pam ......... save the raw RGBA samples as a color PAM\n" " -pam ......... save the raw RGBA samples as a color PAM\n"
" -ppm ......... save the raw RGB samples as a color PPM\n" " -ppm ......... save the raw RGB samples as a color PPM\n"
@ -96,7 +94,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> ......... resize output (*after* any cropping)\n" " -resize <w> <h> ......... scale the 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"
@ -133,7 +131,7 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
format == RGB_565) ? 2 format == RGB_565) ? 2
: 4; : 4;
uint32_t stride = bpp * w + 7; // <- just for exercising uint32_t stride = bpp * w + 7; // <- just for exercising
external_buffer = (uint8_t*)WebPMalloc(stride * h); external_buffer = (uint8_t*)malloc(stride * h);
if (external_buffer == NULL) return NULL; if (external_buffer == NULL) return NULL;
output_buffer->u.RGBA.stride = stride; output_buffer->u.RGBA.stride = stride;
output_buffer->u.RGBA.size = stride * h; output_buffer->u.RGBA.size = stride * h;
@ -146,7 +144,7 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
uint32_t total_size = stride * h * (has_alpha ? 2 : 1) uint32_t total_size = stride * h * (has_alpha ? 2 : 1)
+ 2 * uv_stride * (h + 1) / 2; + 2 * uv_stride * (h + 1) / 2;
assert(format >= YUV && format <= YUVA); assert(format >= YUV && format <= YUVA);
external_buffer = (uint8_t*)WebPMalloc(total_size); external_buffer = (uint8_t*)malloc(total_size);
if (external_buffer == NULL) return NULL; if (external_buffer == NULL) return NULL;
tmp = external_buffer; tmp = external_buffer;
output_buffer->u.YUVA.y = tmp; output_buffer->u.YUVA.y = tmp;
@ -193,20 +191,18 @@ int main(int argc, const char* argv[]) {
int incremental = 0; int incremental = 0;
int c; int c;
INIT_WARGV(argc, argv);
if (!WebPInitDecoderConfig(&config)) { if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-o") && c < argc - 1) { } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = (const char*)GET_WARGV(argv, ++c); out_file = argv[++c];
} else if (!strcmp(argv[c], "-alpha")) { } else if (!strcmp(argv[c], "-alpha")) {
format = ALPHA_PLANE_ONLY; format = ALPHA_PLANE_ONLY;
} else if (!strcmp(argv[c], "-nofancy")) { } else if (!strcmp(argv[c], "-nofancy")) {
@ -227,7 +223,7 @@ int main(int argc, const char* argv[]) {
const int version = WebPGetDecoderVersion(); const int version = WebPGetDecoderVersion();
printf("%d.%d.%d\n", printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-pgm")) { } else if (!strcmp(argv[c], "-pgm")) {
format = PGM; format = PGM;
} else if (!strcmp(argv[c], "-yuv")) { } else if (!strcmp(argv[c], "-yuv")) {
@ -288,26 +284,26 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-incremental")) { } else if (!strcmp(argv[c], "-incremental")) {
incremental = 1; incremental = 1;
} else if (!strcmp(argv[c], "--")) { } else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c); if (c < argc - 1) in_file = argv[++c];
break; break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
fprintf(stderr, "Unknown option '%s'\n", argv[c]); fprintf(stderr, "Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
in_file = (const char*)GET_WARGV(argv, c); in_file = argv[c];
} }
if (parse_error) { if (parse_error) {
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
} }
if (in_file == NULL) { if (in_file == NULL) {
fprintf(stderr, "missing input file!!\n"); fprintf(stderr, "missing input file!!\n");
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
if (quiet) verbose = 0; if (quiet) verbose = 0;
@ -316,7 +312,7 @@ int main(int argc, const char* argv[]) {
VP8StatusCode status = VP8_STATUS_OK; VP8StatusCode status = VP8_STATUS_OK;
size_t data_size = 0; size_t data_size = 0;
if (!LoadWebP(in_file, &data, &data_size, bitstream)) { if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
FREE_WARGV_AND_RETURN(-1); return -1;
} }
switch (format) { switch (format) {
@ -336,8 +332,9 @@ int main(int argc, const char* argv[]) {
case BMP: case BMP:
output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
break; break;
case TIFF: case TIFF: // note: force pre-multiplied alpha
output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; output_buffer->colorspace =
bitstream->has_alpha ? MODE_rgbA : MODE_RGB;
break; break;
case PGM: case PGM:
case RAW_YUV: case RAW_YUV:
@ -393,18 +390,18 @@ int main(int argc, const char* argv[]) {
if (out_file != NULL) { if (out_file != NULL) {
if (!quiet) { if (!quiet) {
WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file); fprintf(stderr, "Decoded %s. Dimensions: %d x %d %s. Format: %s. "
fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n", "Now saving...\n",
output_buffer->width, output_buffer->height, in_file, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "", bitstream->has_alpha ? " (with alpha)" : "",
kFormatType[bitstream->format]); kFormatType[bitstream->format]);
} }
ok = SaveOutput(output_buffer, format, out_file); ok = SaveOutput(output_buffer, format, out_file);
} else { } else {
if (!quiet) { if (!quiet) {
WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file); fprintf(stderr, "File %s can be decoded "
fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n", "(dimensions: %d x %d %s. Format: %s).\n",
output_buffer->width, output_buffer->height, in_file, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "", bitstream->has_alpha ? " (with alpha)" : "",
kFormatType[bitstream->format]); kFormatType[bitstream->format]);
fprintf(stderr, "Nothing written; " fprintf(stderr, "Nothing written; "
@ -413,9 +410,9 @@ int main(int argc, const char* argv[]) {
} }
Exit: Exit:
WebPFreeDecBuffer(output_buffer); WebPFreeDecBuffer(output_buffer);
WebPFree((void*)external_buffer); free((void*)external_buffer);
WebPFree((void*)data); free((void*)data);
FREE_WARGV_AND_RETURN(ok ? 0 : -1); return ok ? 0 : -1;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -12,14 +12,10 @@
#include "./example_util.h" #include "./example_util.h"
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/mux_types.h"
#include "../imageio/imageio_util.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// String parsing // String parsing
@ -60,80 +56,3 @@ float ExUtilGetFloat(const char* const v, int* const error) {
} }
return f; return f;
} }
//------------------------------------------------------------------------------
static void ResetCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args) {
assert(args != NULL);
args->argc_ = argc;
args->argv_ = argv;
args->own_argv_ = 0;
WebPDataInit(&args->argv_data_);
}
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) {
if (args != NULL) {
if (args->own_argv_) {
WebPFree((void*)args->argv_);
WebPDataClear(&args->argv_data_);
}
ResetCommandLineArguments(0, NULL, args);
}
}
#define MAX_ARGC 16384
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args) {
if (args == NULL || argv == NULL) return 0;
ResetCommandLineArguments(argc, argv, args);
if (argc == 1 && argv[0][0] != '-') {
char* cur;
const char sep[] = " \t\r\n\f\v";
#if defined(_WIN32) && defined(_UNICODE)
fprintf(stderr,
"Error: Reading arguments from a file is a feature unavailable "
"with Unicode binaries.\n");
return 0;
#endif
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) {
return 0;
}
args->own_argv_ = 1;
args->argv_ = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_));
if (args->argv_ == NULL) {
ExUtilDeleteCommandLineArguments(args);
return 0;
}
argc = 0;
for (cur = strtok((char*)args->argv_data_.bytes, sep);
cur != NULL;
cur = strtok(NULL, sep)) {
if (argc == MAX_ARGC) {
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC);
ExUtilDeleteCommandLineArguments(args);
return 0;
}
assert(strlen(cur) != 0);
args->argv_[argc++] = cur;
}
args->argc_ = argc;
}
return 1;
}
//------------------------------------------------------------------------------
int ExUtilReadFileToWebPData(const char* const filename,
WebPData* const webp_data) {
const uint8_t* data;
size_t size;
if (webp_data == NULL) return 0;
if (!ImgIoUtilReadFile(filename, &data, &size)) return 0;
webp_data->bytes = data;
webp_data->size = size;
return 1;
}

View File

@ -14,7 +14,6 @@
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_ #define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#include "webp/types.h" #include "webp/types.h"
#include "webp/mux_types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -36,33 +35,6 @@ float ExUtilGetFloat(const char* const v, int* const error);
// actually parsed is returned, or -1 if an error occurred. // actually parsed is returned, or -1 if an error occurred.
int ExUtilGetInts(const char* v, int base, int max_output, int output[]); int ExUtilGetInts(const char* v, int base, int max_output, int output[]);
// Reads a file named 'filename' into a WebPData structure. The content of
// webp_data is overwritten. Returns false in case of error.
int ExUtilReadFileToWebPData(const char* const filename,
WebPData* const webp_data);
//------------------------------------------------------------------------------
// Command-line arguments
typedef struct {
int argc_;
const char** argv_;
WebPData argv_data_;
int own_argv_;
} CommandLineArguments;
// Initializes the structure from the command-line parameters. If there is
// only one parameter and it does not start with a '-', then it is assumed to
// be a file name. This file will be read and tokenized into command-line
// arguments. The content of 'args' is overwritten.
// Returns false in case of error (memory allocation failure, non
// existing file, too many arguments, ...).
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args);
// Deallocate all memory and reset 'args'.
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -23,22 +23,12 @@
#ifdef WEBP_HAVE_GIF #ifdef WEBP_HAVE_GIF
#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <gif_lib.h> #include <gif_lib.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "webp/mux.h" #include "webp/mux.h"
#include "../examples/example_util.h" #include "../examples/example_util.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "./gifdec.h" #include "./gifdec.h"
#include "./unicode.h"
#include "./unicode_gif.h"
#if !defined(STDIN_FILENO)
#define STDIN_FILENO 0
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -82,10 +72,8 @@ static void Help(void) {
printf(" -metadata <string> ..... comma separated list of metadata to\n"); printf(" -metadata <string> ..... comma separated list of metadata to\n");
printf(" "); printf(" ");
printf("copy from the input to the output if present\n"); printf("copy from the input to the output if present\n");
printf(" "); printf(" "
printf("Valid values: all, none, icc, xmp (default)\n"); "Valid values: all, none, icc, xmp (default)\n");
printf(" -loop_compatibility .... use compatibility mode for Chrome\n");
printf(" version prior to M62 (inclusive)\n");
printf(" -mt .................... use multi-threading if available\n"); printf(" -mt .................... use multi-threading if available\n");
printf("\n"); printf("\n");
printf(" -version ............... print version number and exit\n"); printf(" -version ............... print version number and exit\n");
@ -101,7 +89,8 @@ int main(int argc, const char* argv[]) {
int gif_error = GIF_ERROR; int gif_error = GIF_ERROR;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int ok = 0; int ok = 0;
const W_CHAR* in_file = NULL, *out_file = NULL; const char *in_file = NULL, *out_file = NULL;
FILE* out = NULL;
GifFileType* gif = NULL; GifFileType* gif = NULL;
int frame_duration = 0; int frame_duration = 0;
int frame_timestamp = 0; int frame_timestamp = 0;
@ -115,7 +104,7 @@ int main(int argc, const char* argv[]) {
WebPAnimEncoderOptions enc_options; WebPAnimEncoderOptions enc_options;
WebPConfig config; WebPConfig config;
int frame_number = 0; // Whether we are processing the first frame. int is_first_frame = 1; // Whether we are processing the first frame.
int done; int done;
int c; int c;
int quiet = 0; int quiet = 0;
@ -126,21 +115,18 @@ int main(int argc, const char* argv[]) {
int stored_icc = 0; // Whether we have already stored an ICC profile. int stored_icc = 0; // Whether we have already stored an ICC profile.
WebPData xmp_data; WebPData xmp_data;
int stored_xmp = 0; // Whether we have already stored an XMP profile. int stored_xmp = 0; // Whether we have already stored an XMP profile.
int loop_count = 0; // default: infinite int loop_count = 0;
int stored_loop_count = 0; // Whether we have found an explicit loop count. int stored_loop_count = 0; // Whether we have found an explicit loop count.
int loop_compatibility = 0;
WebPMux* mux = NULL; WebPMux* mux = NULL;
int default_kmin = 1; // Whether to use default kmin value. int default_kmin = 1; // Whether to use default kmin value.
int default_kmax = 1; int default_kmax = 1;
INIT_WARGV(argc, argv);
if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) || if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) ||
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) || !WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
!WebPPictureInit(&prev_canvas)) { !WebPPictureInit(&prev_canvas)) {
fprintf(stderr, "Error! Version mismatch!\n"); fprintf(stderr, "Error! Version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
config.lossless = 1; // Use lossless compression by default. config.lossless = 1; // Use lossless compression by default.
@ -150,23 +136,21 @@ int main(int argc, const char* argv[]) {
if (argc == 1) { if (argc == 1) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-o") && c < argc - 1) { } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = GET_WARGV(argv, ++c); out_file = argv[++c];
} else if (!strcmp(argv[c], "-lossy")) { } else if (!strcmp(argv[c], "-lossy")) {
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-mixed")) { } else if (!strcmp(argv[c], "-mixed")) {
enc_options.allow_mixed = 1; enc_options.allow_mixed = 1;
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-loop_compatibility")) {
loop_compatibility = 1;
} else if (!strcmp(argv[c], "-q") && c < argc - 1) { } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = ExUtilGetFloat(argv[++c], &parse_error); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
@ -216,7 +200,7 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start); (int)(token - start), start);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
start = token + 1; start = token + 1;
} }
@ -229,7 +213,7 @@ int main(int argc, const char* argv[]) {
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff, enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff); (mux_version >> 8) & 0xff, mux_version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-quiet")) { } else if (!strcmp(argv[c], "-quiet")) {
quiet = 1; quiet = 1;
enc_options.verbose = 0; enc_options.verbose = 0;
@ -237,19 +221,19 @@ int main(int argc, const char* argv[]) {
verbose = 1; verbose = 1;
enc_options.verbose = 1; enc_options.verbose = 1;
} else if (!strcmp(argv[c], "--")) { } else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = GET_WARGV(argv, ++c); if (c < argc - 1) in_file = argv[++c];
break; break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
in_file = GET_WARGV(argv, c); in_file = argv[c];
} }
if (parse_error) { if (parse_error) {
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
} }
@ -273,7 +257,11 @@ int main(int argc, const char* argv[]) {
} }
// Start the decoder object // Start the decoder object
gif = DGifOpenFileUnicode(in_file, &gif_error); #if LOCAL_GIF_PREREQ(5,0)
gif = DGifOpenFileName(in_file, &gif_error);
#else
gif = DGifOpenFileName(in_file);
#endif
if (gif == NULL) goto End; if (gif == NULL) goto End;
// Loop over GIF images // Loop over GIF images
@ -289,7 +277,7 @@ int main(int argc, const char* argv[]) {
if (!DGifGetImageDesc(gif)) goto End; if (!DGifGetImageDesc(gif)) goto End;
if (frame_number == 0) { if (is_first_frame) {
if (verbose) { if (verbose) {
printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight); printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight);
} }
@ -314,11 +302,8 @@ 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);
if (!(WebPPictureCopy(&frame, &curr_canvas) && 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,
@ -334,6 +319,7 @@ int main(int argc, const char* argv[]) {
"a memory error.\n"); "a memory error.\n");
goto End; goto End;
} }
is_first_frame = 0;
} }
// Some even more broken GIF can have sub-rect with zero width/height. // Some even more broken GIF can have sub-rect with zero width/height.
@ -350,25 +336,13 @@ int main(int argc, const char* argv[]) {
GIFBlendFrames(&frame, &gif_rect, &curr_canvas); GIFBlendFrames(&frame, &gif_rect, &curr_canvas);
if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) { if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) {
fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number, fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
WebPAnimEncoderGetError(enc));
goto End;
} else {
++frame_number;
} }
// Update canvases. // Update canvases.
GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas); GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas);
GIFCopyPixels(&curr_canvas, &prev_canvas); GIFCopyPixels(&curr_canvas, &prev_canvas);
// Force frames with a small or no duration to 100ms to be consistent
// with web browsers and other transcoding tools. This also avoids
// incorrect durations between frames when padding frames are
// discarded.
if (frame_duration <= 10) {
frame_duration = 100;
}
// Update timestamp (for next frame). // Update timestamp (for next frame).
frame_timestamp += frame_duration; frame_timestamp += frame_duration;
@ -412,7 +386,7 @@ int main(int argc, const char* argv[]) {
if (verbose) { if (verbose) {
fprintf(stderr, "Loop count: %d\n", loop_count); fprintf(stderr, "Loop count: %d\n", loop_count);
} }
stored_loop_count = loop_compatibility ? (loop_count != 0) : 1; stored_loop_count = (loop_count != 0);
} else { // An extension containing metadata. } else { // An extension containing metadata.
// We only store the first encountered chunk of each type, and // We only store the first encountered chunk of each type, and
// only if requested by the user. // only if requested by the user.
@ -468,25 +442,6 @@ 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 (frame_number == 1) {
loop_count = 0;
} else if (!loop_compatibility) {
if (!stored_loop_count) {
// if no loop-count element is seen, the default is '1' (loop-once)
// and we need to signal it explicitly in WebP. Note however that
// in case there's a single frame, we still don't need to store it.
if (frame_number > 1) {
stored_loop_count = 1;
loop_count = 1;
}
} else if (loop_count > 0 && loop_count < 65535) {
// adapt GIF's semantic to WebP's (except in the infinite-loop case)
loop_count += 1;
}
}
// loop_count of 0 is the default (infinite), so no need to signal it
if (loop_count == 0) stored_loop_count = 0;
if (stored_loop_count || stored_icc || stored_xmp) { if (stored_loop_count || stored_icc || stored_xmp) {
// Re-mux to add loop count and/or metadata as needed. // Re-mux to add loop count and/or metadata as needed.
@ -547,20 +502,14 @@ int main(int argc, const char* argv[]) {
} }
if (out_file != NULL) { if (out_file != NULL) {
if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes, if (!ImgIoUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
webp_data.size)) { fprintf(stderr, "Error writing output file: %s\n", out_file);
WFPRINTF(stderr, "Error writing output file: %s\n", out_file);
goto End; goto End;
} }
if (!quiet) { if (!quiet) {
if (!WSTRCMP(out_file, "-")) { fprintf(stderr, "Saved output file (%d bytes): %s\n",
fprintf(stderr, "Saved %d bytes to STDIO\n",
(int)webp_data.size);
} else {
WFPRINTF(stderr, "Saved output file (%d bytes): %s\n",
(int)webp_data.size, out_file); (int)webp_data.size, out_file);
} }
}
} else { } else {
if (!quiet) { if (!quiet) {
fprintf(stderr, "Nothing written; use -o flag to save the result " fprintf(stderr, "Nothing written; use -o flag to save the result "
@ -581,6 +530,7 @@ int main(int argc, const char* argv[]) {
WebPPictureFree(&curr_canvas); WebPPictureFree(&curr_canvas);
WebPPictureFree(&prev_canvas); WebPPictureFree(&prev_canvas);
WebPAnimEncoderDelete(enc); WebPAnimEncoderDelete(enc);
if (out != NULL && out_file != NULL) fclose(out);
if (gif_error != GIF_OK) { if (gif_error != GIF_OK) {
GIFDisplayError(gif, gif_error); GIFDisplayError(gif, gif_error);
@ -593,7 +543,7 @@ int main(int argc, const char* argv[]) {
#endif #endif
} }
FREE_WARGV_AND_RETURN(!ok); return !ok;
} }
#else // !WEBP_HAVE_GIF #else // !WEBP_HAVE_GIF

View File

@ -28,17 +28,11 @@
#define GIF_DISPOSE_SHIFT 2 #define GIF_DISPOSE_SHIFT 2
// from utils/utils.h // from utils/utils.h
#ifdef __cplusplus
extern "C" {
#endif
extern void WebPCopyPlane(const uint8_t* src, int src_stride, extern void WebPCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, uint8_t* dst, int dst_stride,
int width, int height); int width, int height);
extern void WebPCopyPixels(const WebPPicture* const src, extern void WebPCopyPixels(const WebPPicture* const src,
WebPPicture* const dst); WebPPicture* const dst);
#ifdef __cplusplus
}
#endif
void GIFGetBackgroundColor(const ColorMapObject* const color_map, void GIFGetBackgroundColor(const ColorMapObject* const color_map,
int bgcolor_index, int transparent_index, int bgcolor_index, int transparent_index,
@ -137,7 +131,7 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
} }
dst = sub_image.argb; dst = sub_image.argb;
tmp = (uint8_t*)WebPMalloc(rect.width * sizeof(*tmp)); tmp = (uint8_t*)malloc(rect.width * sizeof(*tmp));
if (tmp == NULL) goto End; if (tmp == NULL) goto End;
if (image_desc->Interlace) { // Interlaced image. if (image_desc->Interlace) { // Interlaced image.
@ -168,7 +162,7 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
End: End:
if (!ok) picture->error_code = sub_image.error_code; if (!ok) picture->error_code = sub_image.error_code;
WebPPictureFree(&sub_image); WebPPictureFree(&sub_image);
WebPFree(tmp); free(tmp);
return ok; return ok;
} }

View File

@ -27,8 +27,6 @@
#include "../imageio/image_dec.h" #include "../imageio/image_dec.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "./stopwatch.h" #include "./stopwatch.h"
#include "./unicode.h"
#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h" #include "webp/encode.h"
#include "webp/mux.h" #include "webp/mux.h"
@ -36,25 +34,20 @@
static void Help(void) { static void Help(void) {
printf("Usage:\n\n"); printf("Usage:\n\n");
printf(" img2webp [file_options] [[frame_options] frame_file]..."); printf(" img2webp [file-level options] [image files...] "
printf(" [-o webp_file]\n\n"); "[per-frame options...]\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");
printf(" -min_size ............ minimize size\n"); printf(" -min_size ............ minimize size\n");
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -kmax <int> .......... maximum number of frame between key-frames\n" printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
" (0=only keyframes)\n"); " (0=only keyframes)\n");
printf(" -kmin <int> .......... minimum number of frame between key-frames\n" printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
" (0=disable key-frames altogether)\n"); " (0=disable key-frames altogether)\n");
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n"); printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
printf(" -near_lossless <int> . use near-lossless image preprocessing\n"
" (0..100=off), default=100\n");
printf(" -sharp_yuv ........... use sharper (and slower) RGB->YUV "
"conversion\n "
"(lossy only)\n");
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -v ................... verbose mode\n"); printf(" -v ................... verbose mode\n");
printf(" -h ................... this help\n"); printf(" -h ................... this help\n");
printf(" -version ............. print version number and exit\n");
printf("\n"); printf("\n");
printf("Per-frame options (only used for subsequent images input):\n"); printf("Per-frame options (only used for subsequent images input):\n");
@ -67,12 +60,6 @@ static void Help(void) {
printf("\n"); printf("\n");
printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n" printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n"
" -d 80 in2.tiff -o out.webp\n"); " -d 80 in2.tiff -o out.webp\n");
printf("\nNote: if a single file name is passed as the argument, the "
"arguments will be\n");
printf("tokenized from this file. The file name must not start with "
"the character '-'.\n");
printf("\nSupported input formats:\n %s\n",
WebPGetEnabledInputFileFormats());
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -91,7 +78,7 @@ static int ReadImage(const char filename[], WebPPicture* const pic) {
if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0; if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0;
reader = WebPGuessImageReader(data, data_size); reader = WebPGuessImageReader(data, data_size);
ok = reader(data, data_size, pic, 1, NULL); ok = reader(data, data_size, pic, 1, NULL);
WebPFree((void*)data); free((void*)data);
return ok; return ok;
} }
@ -130,13 +117,14 @@ static int SetLoopCount(int loop_count, WebPData* const webp_data) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int main(int argc, const char* argv[]) { int main(int argc, char* argv[]) {
const char* output = NULL; const char* output = NULL;
WebPAnimEncoder* enc = NULL; WebPAnimEncoder* enc = NULL;
int verbose = 0; int verbose = 0;
int pic_num = 0; int pic_num = 0;
int duration = 100; int duration = 100;
int timestamp_ms = 0; int timestamp_ms = 0;
int ok = 1;
int loop_count = 0; int loop_count = 0;
int width = 0, height = 0; int width = 0, height = 0;
WebPAnimEncoderOptions anim_config; WebPAnimEncoderOptions anim_config;
@ -145,33 +133,22 @@ int main(int argc, const char* argv[]) {
WebPData webp_data; WebPData webp_data;
int c; int c;
int have_input = 0; int have_input = 0;
CommandLineArguments cmd_args;
int ok;
INIT_WARGV(argc, argv);
ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
if (!ok) FREE_WARGV_AND_RETURN(1);
argc = cmd_args.argc_;
argv = cmd_args.argv_;
WebPDataInit(&webp_data); WebPDataInit(&webp_data);
if (!WebPAnimEncoderOptionsInit(&anim_config) || if (!WebPAnimEncoderOptionsInit(&anim_config) ||
!WebPConfigInit(&config) || !WebPConfigInit(&config) ||
!WebPPictureInit(&pic)) { !WebPPictureInit(&pic)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
ok = 0; return 1;
goto End;
} }
// 1st pass of option parsing // 1st pass of option parsing
for (c = 0; ok && c < argc; ++c) { for (c = 1; ok && c < argc; ++c) {
if (argv[c][0] == '-') { if (argv[c][0] == '-') {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-o") && c + 1 < argc) { if (!strcmp(argv[c], "-o") && c + 1 < argc) {
argv[c] = NULL; argv[c] = NULL;
output = (const char*)GET_WARGV_SHIFTED(argv, ++c); output = argv[++c];
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) { } else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
argv[c] = NULL; argv[c] = NULL;
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
@ -190,27 +167,11 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-mixed")) { } else if (!strcmp(argv[c], "-mixed")) {
anim_config.allow_mixed = 1; anim_config.allow_mixed = 1;
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) {
argv[c] = NULL;
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-sharp_yuv")) {
config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-v")) { } else if (!strcmp(argv[c], "-v")) {
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();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
const int sharpyuv_version = SharpYuvGetVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
printf("libsharpyuv: %d.%d.%d\n", (sharpyuv_version >> 24) & 0xff,
(sharpyuv_version >> 16) & 0xffff, sharpyuv_version & 0xff);
goto End;
} else { } else {
continue; continue;
} }
@ -223,13 +184,13 @@ int main(int argc, const char* argv[]) {
} }
if (!have_input) { if (!have_input) {
fprintf(stderr, "No input file(s) for generating animation!\n"); fprintf(stderr, "No input file(s) for generating animation!\n");
goto End; return 0;
} }
// image-reading pass // image-reading pass
pic_num = 0; pic_num = 0;
config.lossless = 1; config.lossless = 1;
for (c = 0; ok && c < argc; ++c) { for (c = 1; ok && c < argc; ++c) {
if (argv[c] == NULL) continue; if (argv[c] == NULL) continue;
if (argv[c][0] == '-') { // parse local options if (argv[c][0] == '-') { // parse local options
int parse_error = 0; int parse_error = 0;
@ -266,7 +227,7 @@ int main(int argc, const char* argv[]) {
// read next input image // read next input image
pic.use_argb = 1; pic.use_argb = 1;
ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic); ok = ReadImage(argv[c], &pic);
if (!ok) goto End; if (!ok) goto End;
if (enc == NULL) { if (enc == NULL) {
@ -298,8 +259,8 @@ int main(int argc, const char* argv[]) {
if (!ok) goto End; if (!ok) goto End;
if (verbose) { if (verbose) {
WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n", fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n",
pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c)); pic_num, timestamp_ms, argv[c]);
} }
timestamp_ms += duration; timestamp_ms += duration;
++pic_num; ++pic_num;
@ -323,7 +284,7 @@ int main(int argc, const char* argv[]) {
if (ok) { if (ok) {
if (output != NULL) { if (output != NULL) {
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size); ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
if (ok) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)output); if (ok) fprintf(stderr, "output file: %s ", output);
} else { } else {
fprintf(stderr, "[no output file specified] "); fprintf(stderr, "[no output file specified] ");
} }
@ -333,7 +294,7 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "[%d frames, %u bytes].\n", fprintf(stderr, "[%d frames, %u bytes].\n",
pic_num, (unsigned int)webp_data.size); pic_num, (unsigned int)webp_data.size);
} }
WebPDataClear(&webp_data); WebPDataClear(&webp_data);
ExUtilDeleteCommandLineArguments(&cmd_args); return ok ? 0 : 1;
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
} }

View File

@ -60,4 +60,4 @@ static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif // WEBP_EXAMPLES_STOPWATCH_H_ #endif /* WEBP_EXAMPLES_STOPWATCH_H_ */

View File

@ -1,116 +0,0 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Unicode support for Windows. The main idea is to maintain an array of Unicode
// arguments (wargv) and use it only for file paths. The regular argv is used
// for everything else.
//
// Author: Yannis Guyon (yguyon@google.com)
#ifndef WEBP_EXAMPLES_UNICODE_H_
#define WEBP_EXAMPLES_UNICODE_H_
#include <stdio.h>
#if defined(_WIN32) && defined(_UNICODE)
// wchar_t is used instead of TCHAR because we only perform additional work when
// Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t.
#include <fcntl.h>
#include <io.h>
#include <wchar.h>
#include <windows.h>
#include <shellapi.h>
// Create a wchar_t array containing Unicode parameters.
#define INIT_WARGV(ARGC, ARGV) \
int wargc; \
const W_CHAR** const wargv = \
(const W_CHAR**)CommandLineToArgvW(GetCommandLineW(), &wargc); \
do { \
if (wargv == NULL || wargc != (ARGC)) { \
fprintf(stderr, "Error: Unable to get Unicode arguments.\n"); \
FREE_WARGV_AND_RETURN(-1); \
} \
} while (0)
// Use this to get a Unicode argument (e.g. file path).
#define GET_WARGV(UNUSED, C) wargv[C]
// For cases where argv is shifted by one compared to wargv.
#define GET_WARGV_SHIFTED(UNUSED, C) wargv[(C) + 1]
#define GET_WARGV_OR_NULL() wargv
// Release resources. LocalFree() is needed after CommandLineToArgvW().
#define FREE_WARGV() LOCAL_FREE((W_CHAR** const)wargv)
#define LOCAL_FREE(WARGV) \
do { \
if ((WARGV) != NULL) LocalFree(WARGV); \
} while (0)
#define W_CHAR wchar_t // WCHAR without underscore might already be defined.
#define TO_W_CHAR(STR) (L##STR)
#define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT))
#define WFPRINTF(STREAM, STR, ...) \
do { \
int prev_mode; \
fflush(STREAM); \
prev_mode = _setmode(_fileno(STREAM), _O_U8TEXT); \
fwprintf(STREAM, TO_W_CHAR(STR), __VA_ARGS__); \
fflush(STREAM); \
(void)_setmode(_fileno(STREAM), prev_mode); \
} while (0)
#define WPRINTF(STR, ...) WFPRINTF(stdout, STR, __VA_ARGS__)
#define WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME)
#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
#define WSTRRCHR(FILENAME, STR) wcsrchr((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
#define WSNPRINTF(A, B, STR, ...) _snwprintf(A, B, TO_W_CHAR(STR), __VA_ARGS__)
#else
#include <string.h>
// Unicode file paths work as is on Unix platforms, and no extra work is done on
// Windows either if Unicode is disabled.
#define INIT_WARGV(ARGC, ARGV)
#define GET_WARGV(ARGV, C) (ARGV)[C]
#define GET_WARGV_SHIFTED(ARGV, C) (ARGV)[C]
#define GET_WARGV_OR_NULL() NULL
#define FREE_WARGV()
#define LOCAL_FREE(WARGV)
#define W_CHAR char
#define TO_W_CHAR(STR) (STR)
#define WFOPEN(ARG, OPT) fopen(ARG, OPT)
#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__)
#define WFPRINTF(STREAM, STR, ...) fprintf(STREAM, STR, __VA_ARGS__)
#define WSTRLEN(FILENAME) strlen(FILENAME)
#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR)
#define WSTRRCHR(FILENAME, STR) strrchr(FILENAME, STR)
#define WSNPRINTF(A, B, STR, ...) snprintf(A, B, STR, __VA_ARGS__)
#endif // defined(_WIN32) && defined(_UNICODE)
// Don't forget to free wargv before returning (e.g. from main).
#define FREE_WARGV_AND_RETURN(VALUE) \
do { \
FREE_WARGV(); \
return (VALUE); \
} while (0)
#endif // WEBP_EXAMPLES_UNICODE_H_

View File

@ -1,76 +0,0 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// giflib doesn't have a Unicode DGifOpenFileName(). Let's make one.
//
// Author: Yannis Guyon (yguyon@google.com)
#ifndef WEBP_EXAMPLES_UNICODE_GIF_H_
#define WEBP_EXAMPLES_UNICODE_GIF_H_
#include "./unicode.h"
#ifdef HAVE_CONFIG_H
#include "webp/config.h" // For WEBP_HAVE_GIF
#endif
#if defined(WEBP_HAVE_GIF)
#ifdef _WIN32
#include <fcntl.h> // Not standard, needed for _topen and flags.
#include <io.h>
#endif
#include <gif_lib.h>
#include <string.h>
#include "./gifdec.h"
#if !defined(STDIN_FILENO)
#define STDIN_FILENO 0
#endif
static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) {
if (!WSTRCMP(file_name, "-")) {
#if LOCAL_GIF_PREREQ(5, 0)
return DGifOpenFileHandle(STDIN_FILENO, error);
#else
(void)error;
return DGifOpenFileHandle(STDIN_FILENO);
#endif
}
#if defined(_WIN32) && defined(_UNICODE)
{
int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY);
if (file_handle == -1) {
if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED;
return NULL;
}
#if LOCAL_GIF_PREREQ(5, 0)
return DGifOpenFileHandle(file_handle, error);
#else
return DGifOpenFileHandle(file_handle);
#endif
}
#else
#if LOCAL_GIF_PREREQ(5, 0)
return DGifOpenFileName(file_name, error);
#else
return DGifOpenFileName(file_name);
#endif
#endif // defined(_WIN32) && defined(_UNICODE)
// DGifCloseFile() is called later.
}
#endif // defined(WEBP_HAVE_GIF)
#endif // WEBP_EXAMPLES_UNICODE_GIF_H_

View File

@ -42,7 +42,6 @@
#include "../examples/example_util.h" #include "../examples/example_util.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "./unicode.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -57,7 +56,6 @@ static struct {
int print_info; int print_info;
int only_deltas; int only_deltas;
int use_color_profile; int use_color_profile;
int draw_anim_background_color;
int canvas_width, canvas_height; int canvas_width, canvas_height;
int loop_count; int loop_count;
@ -207,11 +205,6 @@ static void decode_callback(int what) {
} }
} }
duration = curr->duration; duration = curr->duration;
// Behavior copied from Chrome, cf:
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/
// platform/graphics/DeferredImageDecoder.cpp?
// rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246
if (duration <= 10) duration = 100;
} }
if (!Decode()) { if (!Decode()) {
kParams.decoding_error = 1; kParams.decoding_error = 1;
@ -227,9 +220,6 @@ static void decode_callback(int what) {
// Callbacks // Callbacks
static void HandleKey(unsigned char key, int pos_x, int pos_y) { static void HandleKey(unsigned char key, int pos_x, int pos_y) {
// Note: rescaling the window or toggling some features during an animation
// generates visual artifacts. This is not fixed because refreshing the frame
// may require rendering the whole animation from start till current frame.
(void)pos_x; (void)pos_x;
(void)pos_y; (void)pos_y;
if (key == 'q' || key == 'Q' || key == 27 /* Esc */) { if (key == 'q' || key == 'Q' || key == 27 /* Esc */) {
@ -257,12 +247,10 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
glutPostRedisplay(); glutPostRedisplay();
} }
} }
} else if (key == 'b') {
kParams.draw_anim_background_color = 1 - kParams.draw_anim_background_color;
if (!kParams.has_animation) ClearPreviousFrame();
glutPostRedisplay();
} else if (key == 'i') { } else if (key == 'i') {
kParams.print_info = 1 - kParams.print_info; kParams.print_info = 1 - kParams.print_info;
// TODO(skal): handle refresh of animation's last-frame too. It's quite
// more involved though (need to save the previous frame).
if (!kParams.has_animation) ClearPreviousFrame(); if (!kParams.has_animation) ClearPreviousFrame();
glutPostRedisplay(); glutPostRedisplay();
} else if (key == 'd') { } else if (key == 'd') {
@ -272,8 +260,8 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
} }
static void HandleReshape(int width, int height) { static void HandleReshape(int width, int height) {
// Note: reshape doesn't preserve aspect ratio, and might // TODO(skal): should we preserve aspect ratio?
// be handling larger-than-screen pictures incorrectly. // Also: handle larger-than-screen pictures correctly.
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
@ -292,21 +280,8 @@ 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) / 255.f;
} }
static void DrawCheckerBoard(void) { static void DrawCheckerBoard(void) {
@ -329,43 +304,6 @@ static void DrawCheckerBoard(void) {
glPopMatrix(); glPopMatrix();
} }
static void DrawBackground(void) {
// Whole window cleared with clear color, checkerboard rendered on top of it.
glClear(GL_COLOR_BUFFER_BIT);
DrawCheckerBoard();
// ANIM background color rendered (blend) on top. Default is white for still
// images (without ANIM chunk). glClear() can't be used for that (no blend).
if (kParams.draw_anim_background_color) {
glPushMatrix();
glLoadIdentity();
glColor4f(GetColorf(kParams.bg_color, 16), // BGRA from spec
GetColorf(kParams.bg_color, 8),
GetColorf(kParams.bg_color, 0),
GetColorf(kParams.bg_color, 24));
glRecti(-1, -1, +1, +1);
glPopMatrix();
}
}
// Draw background in a scissored rectangle.
static void DrawBackgroundScissored(int window_x, int window_y, int frame_w,
int frame_h) {
// Only update the requested area, not the whole canvas.
window_x = window_x * kParams.viewport_width / kParams.canvas_width;
window_y = window_y * kParams.viewport_height / kParams.canvas_height;
frame_w = frame_w * kParams.viewport_width / kParams.canvas_width;
frame_h = frame_h * kParams.viewport_height / kParams.canvas_height;
// glScissor() takes window coordinates (0,0 at bottom left).
window_y = kParams.viewport_height - window_y - frame_h;
glEnable(GL_SCISSOR_TEST);
glScissor(window_x, window_y, frame_w, frame_h);
DrawBackground();
glDisable(GL_SCISSOR_TEST);
}
static void HandleDisplay(void) { static void HandleDisplay(void) {
const WebPDecBuffer* const pic = kParams.pic; const WebPDecBuffer* const pic = kParams.pic;
const WebPIterator* const curr = &kParams.curr_frame; const WebPIterator* const curr = &kParams.curr_frame;
@ -382,21 +320,38 @@ static void HandleDisplay(void) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
if (kParams.only_deltas) { if (kParams.only_deltas) {
DrawBackground(); DrawCheckerBoard();
} else { } else if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
// The rectangle of the previous frame might be different than the current curr->blend_method == WEBP_MUX_NO_BLEND) {
// frame, so we may need to DrawBackgroundScissored for both. // glScissor() takes window coordinates (0,0 at bottom left).
int window_x, window_y;
int frame_w, frame_h;
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
// Clear the previous frame rectangle. // Clear the previous frame rectangle.
DrawBackgroundScissored(prev->x_offset, prev->y_offset, prev->width, window_x = prev->x_offset;
prev->height); window_y = kParams.canvas_height - prev->y_offset - prev->height;
} frame_w = prev->width;
if (curr->blend_method == WEBP_MUX_NO_BLEND) { frame_h = prev->height;
} else { // curr->blend_method == WEBP_MUX_NO_BLEND.
// We simulate no-blending behavior by first clearing the current frame // We simulate no-blending behavior by first clearing the current frame
// rectangle and then alpha-blending against it. // rectangle (to a checker-board) and then alpha-blending against it.
DrawBackgroundScissored(curr->x_offset, curr->y_offset, curr->width, window_x = curr->x_offset;
curr->height); window_y = kParams.canvas_height - curr->y_offset - curr->height;
frame_w = curr->width;
frame_h = curr->height;
} }
glEnable(GL_SCISSOR_TEST);
// Only update the requested area, not the whole canvas.
window_x = window_x * kParams.viewport_width / kParams.canvas_width;
window_y = window_y * kParams.viewport_height / kParams.canvas_height;
frame_w = frame_w * kParams.viewport_width / kParams.canvas_width;
frame_h = frame_h * kParams.viewport_height / kParams.canvas_height;
glScissor(window_x, window_y, frame_w, frame_h);
glClear(GL_COLOR_BUFFER_BIT); // use clear color
DrawCheckerBoard();
glDisable(GL_SCISSOR_TEST);
} }
*prev = *curr; *prev = *curr;
@ -409,7 +364,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);
PrintStringW(kParams.file_name); PrintString(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);
@ -423,36 +378,13 @@ static void HandleDisplay(void) {
} }
} }
glPopMatrix(); glPopMatrix();
#if defined(__APPLE__) || defined(_WIN32)
glFlush(); glFlush();
#else
glutSwapBuffers();
#endif
} }
static void StartDisplay(void) { static void StartDisplay(void) {
int width = kParams.canvas_width; const int width = kParams.canvas_width;
int height = kParams.canvas_height; const int height = kParams.canvas_height;
int screen_width, screen_height;
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
// partially displayed with animated webp + alpha.
#if defined(__APPLE__) || defined(_WIN32)
glutInitDisplayMode(GLUT_RGBA); glutInitDisplayMode(GLUT_RGBA);
#else
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
#endif
screen_width = glutGet(GLUT_SCREEN_WIDTH);
screen_height = glutGet(GLUT_SCREEN_HEIGHT);
if (width > screen_width || height > screen_height) {
if (width > screen_width) {
height = (height * screen_width + width - 1) / width;
width = screen_width;
}
if (height > screen_height) {
width = (width * screen_height + height - 1) / height;
height = screen_height;
}
}
glutInitWindowSize(width, height); glutInitWindowSize(width, height);
glutCreateWindow("WebP viewer"); glutCreateWindow("WebP viewer");
glutDisplayFunc(HandleDisplay); glutDisplayFunc(HandleDisplay);
@ -461,16 +393,19 @@ static void StartDisplay(void) {
glutKeyboardFunc(HandleKey); glutKeyboardFunc(HandleKey);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glClearColor(0, 0, 0, 0); // window will be cleared to black (no blend) glClearColor(GetColorf(kParams.bg_color, 0),
DrawBackground(); GetColorf(kParams.bg_color, 8),
GetColorf(kParams.bg_color, 16),
GetColorf(kParams.bg_color, 24));
glClear(GL_COLOR_BUFFER_BIT);
DrawCheckerBoard();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main // Main
static void Help(void) { static void Help(void) {
printf( printf("Usage: vwebp in_file [options]\n\n"
"Usage: vwebp in_file [options]\n\n"
"Decodes the WebP image file and visualize it using OpenGL\n" "Decodes the WebP image file and visualize it using OpenGL\n"
"Options are:\n" "Options are:\n"
" -version ..... print version number and exit\n" " -version ..... print version number and exit\n"
@ -479,17 +414,16 @@ static void Help(void) {
" -nofilter .... disable in-loop filtering\n" " -nofilter .... disable in-loop filtering\n"
" -dither <int> dithering strength (0..100), default=50\n" " -dither <int> dithering strength (0..100), default=50\n"
" -noalphadither disable alpha plane dithering\n" " -noalphadither disable alpha plane dithering\n"
" -usebgcolor .. display background color\n"
" -mt .......... use multi-threading\n" " -mt .......... use multi-threading\n"
" -info ........ print info\n" " -info ........ print info\n"
" -h ........... this help message\n" " -h ........... this help message\n"
"\n" "\n"
"Keyboard shortcuts:\n" "Keyboard shortcuts:\n"
" 'c' ................ toggle use of color profile\n" " 'c' ................ toggle use of color profile\n"
" 'b' ................ toggle background color display\n"
" 'i' ................ overlay file information\n" " 'i' ................ overlay file information\n"
" 'd' ................ disable blending & disposal (debug)\n" " 'd' ................ disable blending & disposal (debug)\n"
" 'q' / 'Q' / ESC .... quit\n"); " 'q' / 'Q' / ESC .... quit\n"
);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -497,23 +431,19 @@ int main(int argc, char* argv[]) {
WebPDecoderConfig* const config = &kParams.config; WebPDecoderConfig* const config = &kParams.config;
WebPIterator* const curr = &kParams.curr_frame; WebPIterator* const curr = &kParams.curr_frame;
INIT_WARGV(argc, argv);
if (!WebPInitDecoderConfig(config)) { if (!WebPInitDecoderConfig(config)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
config->options.dithering_strength = 50; config->options.dithering_strength = 50;
config->options.alpha_dithering_strength = 100; config->options.alpha_dithering_strength = 100;
kParams.use_color_profile = 1; kParams.use_color_profile = 1;
// Background color hidden by default to see transparent areas.
kParams.draw_anim_background_color = 0;
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-noicc")) { } else if (!strcmp(argv[c], "-noicc")) {
kParams.use_color_profile = 0; kParams.use_color_profile = 0;
} else if (!strcmp(argv[c], "-nofancy")) { } else if (!strcmp(argv[c], "-nofancy")) {
@ -522,8 +452,6 @@ int main(int argc, char* argv[]) {
config->options.bypass_filtering = 1; config->options.bypass_filtering = 1;
} else if (!strcmp(argv[c], "-noalphadither")) { } else if (!strcmp(argv[c], "-noalphadither")) {
config->options.alpha_dithering_strength = 0; config->options.alpha_dithering_strength = 0;
} else if (!strcmp(argv[c], "-usebgcolor")) {
kParams.draw_anim_background_color = 1;
} else if (!strcmp(argv[c], "-dither") && c + 1 < argc) { } else if (!strcmp(argv[c], "-dither") && c + 1 < argc) {
config->options.dithering_strength = config->options.dithering_strength =
ExUtilGetInt(argv[++c], 0, &parse_error); ExUtilGetInt(argv[++c], 0, &parse_error);
@ -536,30 +464,30 @@ int main(int argc, char* argv[]) {
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
dec_version & 0xff, (dmux_version >> 16) & 0xff, dec_version & 0xff, (dmux_version >> 16) & 0xff,
(dmux_version >> 8) & 0xff, dmux_version & 0xff); (dmux_version >> 8) & 0xff, dmux_version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-mt")) { } else if (!strcmp(argv[c], "-mt")) {
config->options.use_threads = 1; config->options.use_threads = 1;
} else if (!strcmp(argv[c], "--")) { } else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c); if (c < argc - 1) kParams.file_name = argv[++c];
break; break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]); printf("Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
kParams.file_name = (const char*)GET_WARGV(argv, c); kParams.file_name = argv[c];
} }
if (parse_error) { if (parse_error) {
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
} }
if (kParams.file_name == NULL) { if (kParams.file_name == NULL) {
printf("missing input file!!\n"); printf("missing input file!!\n");
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} }
if (!ImgIoUtilReadFile(kParams.file_name, if (!ImgIoUtilReadFile(kParams.file_name,
@ -634,11 +562,11 @@ int main(int argc, char* argv[]) {
// Should only be reached when using FREEGLUT: // Should only be reached when using FREEGLUT:
ClearParams(); ClearParams();
FREE_WARGV_AND_RETURN(0); return 0;
Error: Error:
ClearParams(); ClearParams();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
#else // !WEBP_HAVE_GL #else // !WEBP_HAVE_GL

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
webpmux -set loop 1 in.webp -o out_looped.webp
Extract relevant data from WebP container file: Extract relevant data from WebP container file:
webpmux -get frame n in.webp -o out_frame.webp webpmux -get frame n in.webp -o out_frame.webp
@ -48,7 +47,6 @@
webpmux -info in.webp webpmux -info in.webp
webpmux [ -h | -help ] webpmux [ -h | -help ]
webpmux -version webpmux -version
webpmux argument_file_name
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -63,7 +61,6 @@
#include "webp/mux.h" #include "webp/mux.h"
#include "../examples/example_util.h" #include "../examples/example_util.h"
#include "../imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "./unicode.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Config object to parse command-line arguments. // Config object to parse command-line arguments.
@ -98,8 +95,6 @@ typedef enum {
FEATURE_ICCP, FEATURE_ICCP,
FEATURE_ANMF, FEATURE_ANMF,
FEATURE_DURATION, FEATURE_DURATION,
FEATURE_LOOP,
FEATURE_BGCOLOR,
LAST_FEATURE LAST_FEATURE
} FeatureType; } FeatureType;
@ -113,26 +108,28 @@ static const char* const kDescriptions[LAST_FEATURE] = {
}; };
typedef struct { typedef struct {
CommandLineArguments cmd_args_;
ActionType action_type_;
const char* input_;
const char* output_;
FeatureType type_; FeatureType type_;
FeatureArg* args_; FeatureArg* args_;
int arg_count_; int arg_count_;
} Config; } Feature;
typedef struct {
ActionType action_type_;
const char* input_;
const char* output_;
Feature feature_;
} WebPMuxConfig;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helper functions. // Helper functions.
static int CountOccurrences(const CommandLineArguments* const args, static int CountOccurrences(const char* arglist[], int list_length,
const char* const arg) { const char* arg) {
int i; int i;
int num_occurences = 0; int num_occurences = 0;
for (i = 0; i < args->argc_; ++i) { for (i = 0; i < list_length; ++i) {
if (!strcmp(args->argv_[i], arg)) { if (!strcmp(arglist[i], arg)) {
++num_occurences; ++num_occurences;
} }
} }
@ -304,7 +301,6 @@ static void PrintHelp(void) {
printf(" webpmux -info INPUT\n"); printf(" webpmux -info INPUT\n");
printf(" webpmux [-h|-help]\n"); printf(" webpmux [-h|-help]\n");
printf(" webpmux -version\n"); printf(" webpmux -version\n");
printf(" webpmux argument_file_name\n");
printf("\n"); printf("\n");
printf("GET_OPTIONS:\n"); printf("GET_OPTIONS:\n");
@ -316,9 +312,7 @@ static void PrintHelp(void) {
printf("\n"); printf("\n");
printf("SET_OPTIONS:\n"); printf("SET_OPTIONS:\n");
printf(" Set color profile/metadata/parameters:\n"); printf(" Set color profile/metadata:\n");
printf(" loop LOOP_COUNT set the loop count\n");
printf(" bgcolor BACKGROUND_COLOR set the animation background color\n");
printf(" icc file.icc set ICC profile\n"); printf(" icc file.icc set ICC profile\n");
printf(" exif file.exif set EXIF metadata\n"); printf(" exif file.exif set EXIF metadata\n");
printf(" xmp file.xmp set XMP metadata\n"); printf(" xmp file.xmp set XMP metadata\n");
@ -329,7 +323,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 all frames\n"); printf(" duration set duration for each 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");
@ -348,7 +342,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");
@ -375,10 +369,6 @@ static void PrintHelp(void) {
printf("\nNote: The nature of EXIF, XMP and ICC data is not checked"); printf("\nNote: The nature of EXIF, XMP and ICC data is not checked");
printf(" and is assumed to be\nvalid.\n"); printf(" and is assumed to be\nvalid.\n");
printf("\nNote: if a single file name is passed as the argument, the "
"arguments will be\n");
printf("tokenized from this file. The file name must not start with "
"the character '-'.\n");
} }
static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) { static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
@ -389,32 +379,40 @@ static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
} }
} }
static int ReadFileToWebPData(const char* const filename,
WebPData* const webp_data) {
const uint8_t* data;
size_t size;
if (!ImgIoUtilReadFile(filename, &data, &size)) return 0;
webp_data->bytes = data;
webp_data->size = size;
return 1;
}
static int CreateMux(const char* const filename, WebPMux** mux) { static int CreateMux(const char* const filename, WebPMux** mux) {
WebPData bitstream; WebPData bitstream;
assert(mux != NULL); assert(mux != NULL);
if (!ExUtilReadFileToWebPData(filename, &bitstream)) return 0; if (!ReadFileToWebPData(filename, &bitstream)) return 0;
*mux = WebPMuxCreate(&bitstream, 1); *mux = WebPMuxCreate(&bitstream, 1);
WebPDataClear(&bitstream); free((void*)bitstream.bytes);
if (*mux != NULL) return 1; if (*mux != NULL) return 1;
WFPRINTF(stderr, "Failed to create mux object from file %s.\n", fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
(const W_CHAR*)filename);
return 0; return 0;
} }
static int WriteData(const char* filename, const WebPData* const webpdata) { static int WriteData(const char* filename, const WebPData* const webpdata) {
int ok = 0; int ok = 0;
FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb") FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb")
: ImgIoUtilSetBinaryMode(stdout); : ImgIoUtilSetBinaryMode(stdout);
if (fout == NULL) { if (fout == NULL) {
WFPRINTF(stderr, "Error opening output WebP file %s!\n", fprintf(stderr, "Error opening output WebP file %s!\n", filename);
(const W_CHAR*)filename);
return 0; return 0;
} }
if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) { if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) {
WFPRINTF(stderr, "Error writing file %s!\n", (const W_CHAR*)filename); fprintf(stderr, "Error writing file %s!\n", filename);
} else { } else {
WFPRINTF(stderr, "Saved file %s (%d bytes)\n", fprintf(stderr, "Saved file %s (%d bytes)\n",
(const W_CHAR*)filename, (int)webpdata->size); filename, (int)webpdata->size);
ok = 1; ok = 1;
} }
if (fout != stdout) fclose(fout); if (fout != stdout) fclose(fout);
@ -460,8 +458,7 @@ 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 DuplicateMuxHeader().", ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
End);
} }
} }
} }
@ -475,11 +472,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, unused; int dispose_method, dummy;
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, &unused); &plus_minus, &blend_method, &dummy);
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
@ -498,7 +495,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
WarnAboutOddOffset(info); WarnAboutOddOffset(info);
// Note: The validity of the following conversion is checked by // Note: The sanity of the following conversion is checked by
// WebPMuxPushFrame(). // WebPMuxPushFrame().
info->dispose_method = (WebPMuxAnimDispose)dispose_method; info->dispose_method = (WebPMuxAnimDispose)dispose_method;
@ -520,10 +517,9 @@ static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Clean-up. // Clean-up.
static void DeleteConfig(Config* const config) { static void DeleteConfig(WebPMuxConfig* config) {
if (config != NULL) { if (config != NULL) {
free(config->args_); free(config->feature_.args_);
ExUtilDeleteCommandLineArguments(&config->cmd_args_);
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
} }
} }
@ -535,7 +531,7 @@ static void DeleteConfig(Config* const config) {
// Returns 1 on valid, 0 otherwise. // Returns 1 on valid, 0 otherwise.
// Also fills up num_feature_args to be number of feature arguments given. // Also fills up num_feature_args to be number of feature arguments given.
// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5). // (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
static int ValidateCommandLine(const CommandLineArguments* const cmd_args, static int ValidateCommandLine(int argc, const char* argv[],
int* num_feature_args) { int* num_feature_args) {
int num_frame_args; int num_frame_args;
int num_loop_args; int num_loop_args;
@ -547,27 +543,27 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
*num_feature_args = 0; *num_feature_args = 0;
// Simple checks. // Simple checks.
if (CountOccurrences(cmd_args, "-get") > 1) { if (CountOccurrences(argv, argc, "-get") > 1) {
ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-set") > 1) { if (CountOccurrences(argv, argc, "-set") > 1) {
ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-strip") > 1) { if (CountOccurrences(argv, argc, "-strip") > 1) {
ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-info") > 1) { if (CountOccurrences(argv, argc, "-info") > 1) {
ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-o") > 1) { if (CountOccurrences(argv, argc, "-o") > 1) {
ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
} }
// Compound checks. // Compound checks.
num_frame_args = CountOccurrences(cmd_args, "-frame"); num_frame_args = CountOccurrences(argv, argc, "-frame");
num_loop_args = CountOccurrences(cmd_args, "-loop"); num_loop_args = CountOccurrences(argv, argc, "-loop");
num_bgcolor_args = CountOccurrences(cmd_args, "-bgcolor"); num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
num_durations_args = CountOccurrences(cmd_args, "-duration"); num_durations_args = CountOccurrences(argv, argc, "-duration");
if (num_loop_args > 1) { if (num_loop_args > 1) {
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
@ -602,38 +598,31 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION) #define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE) #define FEATURETYPE_IS_NIL (feature->type_ == NIL_FEATURE)
#define CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL) \ #define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
if (argc < i + (NUM)) { \ if (argc < i + (NUM)) { \
fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \ fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
goto LABEL; \ goto LABEL; \
} }
#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \ #define CHECK_NUM_ARGS_NOT_EQUAL(NUM, LABEL) \
if (argc > i + (NUM)) { \ if (argc != i + (NUM)) { \
fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \ fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
goto LABEL; \ goto LABEL; \
} }
#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \
CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
// Parses command-line arguments to fill up config object. Also performs some // Parses command-line arguments to fill up config object. Also performs some
// semantic checks. unicode_argv contains wchar_t arguments or is null. // semantic checks.
static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) { static int ParseCommandLine(int argc, const char* argv[],
WebPMuxConfig* config) {
int i = 0; int i = 0;
int feature_arg_index = 0; int feature_arg_index = 0;
int ok = 1; int ok = 1;
int argc = config->cmd_args_.argc_;
const char* const* argv = config->cmd_args_.argv_;
// Unicode file paths will be used if available.
const char* const* wargv =
(unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv;
while (i < argc) { while (i < argc) {
FeatureArg* const arg = &config->args_[feature_arg_index]; Feature* const feature = &config->feature_;
FeatureArg* const arg = &feature->args_[feature_arg_index];
if (argv[i][0] == '-') { // One of the action types or output. if (argv[i][0] == '-') { // One of the action types or output.
if (!strcmp(argv[i], "-set")) { if (!strcmp(argv[i], "-set")) {
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
@ -643,14 +632,14 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
} }
++i; ++i;
} else if (!strcmp(argv[i], "-duration")) { } else if (!strcmp(argv[i], "-duration")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) { if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
config->action_type_ = ACTION_DURATION; config->action_type_ = ACTION_DURATION;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_DURATION) {
config->type_ = FEATURE_DURATION; feature->type_ = FEATURE_DURATION;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -667,37 +656,37 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
} else if (!strcmp(argv[i], "-strip")) { } else if (!strcmp(argv[i], "-strip")) {
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
config->action_type_ = ACTION_STRIP; config->action_type_ = ACTION_STRIP;
config->arg_count_ = 0; feature->arg_count_ = 0;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
++i; ++i;
} else if (!strcmp(argv[i], "-frame")) { } else if (!strcmp(argv[i], "-frame")) {
CHECK_NUM_ARGS_AT_LEAST(3, ErrParse); CHECK_NUM_ARGS_LESS(3, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
config->action_type_ = ACTION_SET; config->action_type_ = ACTION_SET;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF; feature->type_ = FEATURE_ANMF;
} else { } else {
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_ = wargv[i + 1]; arg->filename_ = argv[i + 1];
arg->params_ = argv[i + 2]; arg->params_ = argv[i + 2];
++feature_arg_index; ++feature_arg_index;
i += 3; i += 3;
} else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) { } else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
config->action_type_ = ACTION_SET; config->action_type_ = ACTION_SET;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF; feature->type_ = FEATURE_ANMF;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -707,36 +696,34 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
} else if (!strcmp(argv[i], "-o")) { } else if (!strcmp(argv[i], "-o")) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
config->output_ = wargv[i + 1]; config->output_ = argv[i + 1];
i += 2; i += 2;
} else if (!strcmp(argv[i], "-info")) { } else if (!strcmp(argv[i], "-info")) {
CHECK_NUM_ARGS_EXACTLY(2, ErrParse); CHECK_NUM_ARGS_NOT_EQUAL(2, ErrParse);
if (config->action_type_ != NIL_ACTION) { if (config->action_type_ != NIL_ACTION) {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} else { } else {
config->action_type_ = ACTION_INFO; config->action_type_ = ACTION_INFO;
config->arg_count_ = 0; feature->arg_count_ = 0;
config->input_ = wargv[i + 1]; config->input_ = argv[i + 1];
} }
i += 2; i += 2;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) { } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
PrintHelp(); PrintHelp();
DeleteConfig(config); DeleteConfig(config);
LOCAL_FREE((W_CHAR** const)unicode_argv);
exit(0); exit(0);
} else if (!strcmp(argv[i], "-version")) { } else if (!strcmp(argv[i], "-version")) {
const int version = WebPGetMuxVersion(); const int version = WebPGetMuxVersion();
printf("%d.%d.%d\n", printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
DeleteConfig(config); DeleteConfig(config);
LOCAL_FREE((W_CHAR** const)unicode_argv);
exit(0); exit(0);
} else if (!strcmp(argv[i], "--")) { } else if (!strcmp(argv[i], "--")) {
if (i < argc - 1) { if (i < argc - 1) {
++i; ++i;
if (config->input_ == NULL) { if (config->input_ == NULL) {
config->input_ = wargv[i]; config->input_ = argv[i];
} else { } else {
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
argv[i], ErrParse); argv[i], ErrParse);
@ -754,14 +741,14 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") || if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
!strcmp(argv[i], "xmp")) { !strcmp(argv[i], "xmp")) {
if (FEATURETYPE_IS_NIL) { if (FEATURETYPE_IS_NIL) {
config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP : feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP; (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
if (config->action_type_ == ACTION_SET) { if (config->action_type_ == ACTION_SET) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
arg->filename_ = wargv[i + 1]; arg->filename_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
} else { } else {
@ -769,28 +756,14 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
} }
} else if (!strcmp(argv[i], "frame") && } else if (!strcmp(argv[i], "frame") &&
(config->action_type_ == ACTION_GET)) { (config->action_type_ == ACTION_GET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
config->type_ = FEATURE_ANMF; feature->type_ = FEATURE_ANMF;
arg->params_ = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "loop") &&
(config->action_type_ == ACTION_SET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->type_ = FEATURE_LOOP;
arg->params_ = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "bgcolor") &&
(config->action_type_ == ACTION_SET)) {
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
config->type_ = FEATURE_BGCOLOR;
arg->params_ = argv[i + 1]; arg->params_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
} else { // Assume input file. } else { // Assume input file.
if (config->input_ == NULL) { if (config->input_ == NULL) {
config->input_ = wargv[i]; config->input_ = argv[i];
} else { } else {
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
argv[i], ErrParse); argv[i], ErrParse);
@ -804,8 +777,9 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
} }
// Additional checks after config is filled. // Additional checks after config is filled.
static int ValidateConfig(Config* const config) { static int ValidateConfig(WebPMuxConfig* config) {
int ok = 1; int ok = 1;
Feature* const feature = &config->feature_;
// Action. // Action.
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
@ -821,7 +795,7 @@ static int ValidateConfig(Config* const config) {
if (config->input_ == NULL) { if (config->input_ == NULL) {
if (config->action_type_ != ACTION_SET) { if (config->action_type_ != ACTION_SET) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} else if (config->type_ != FEATURE_ANMF) { } else if (feature->type_ != FEATURE_ANMF) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} }
} }
@ -836,29 +810,28 @@ static int ValidateConfig(Config* const config) {
} }
// Create config object from command-line arguments. // Create config object from command-line arguments.
static int InitializeConfig(int argc, const char* argv[], Config* const config, static int InitializeConfig(int argc, const char* argv[],
const W_CHAR** const unicode_argv) { WebPMuxConfig* config) {
int num_feature_args = 0; int num_feature_args = 0;
int ok; int ok = 1;
assert(config != NULL);
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args_);
if (!ok) return 0;
// Validate command-line arguments. // Validate command-line arguments.
if (!ValidateCommandLine(&config->cmd_args_, &num_feature_args)) { if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
} }
config->arg_count_ = num_feature_args; config->feature_.arg_count_ = num_feature_args;
config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_)); config->feature_.args_ =
if (config->args_ == NULL) { (FeatureArg*)calloc(num_feature_args, sizeof(*config->feature_.args_));
if (config->feature_.args_ == NULL) {
ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1); ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
} }
// Parse command-line. // Parse command-line.
if (!ParseCommandLine(config, unicode_argv) || !ValidateConfig(config)) { if (!ParseCommandLine(argc, argv, config) || !ValidateConfig(config)) {
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
} }
@ -868,14 +841,13 @@ static int InitializeConfig(int argc, const char* argv[], Config* const config,
#undef ACTION_IS_NIL #undef ACTION_IS_NIL
#undef FEATURETYPE_IS_NIL #undef FEATURETYPE_IS_NIL
#undef CHECK_NUM_ARGS_AT_LEAST #undef CHECK_NUM_ARGS_LESS
#undef CHECK_NUM_ARGS_AT_MOST #undef CHECK_NUM_ARGS_MORE
#undef CHECK_NUM_ARGS_EXACTLY
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Processing. // Processing.
static int GetFrame(const WebPMux* mux, const Config* config) { static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
WebPMux* mux_single = NULL; WebPMux* mux_single = NULL;
int num = 0; int num = 0;
@ -885,7 +857,7 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
WebPMuxFrameInfo info; WebPMuxFrameInfo info;
WebPDataInit(&info.bitstream); WebPDataInit(&info.bitstream);
num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error); num = ExUtilGetInt(config->feature_.args_[0].params_, 10, &parse_error);
if (num < 0) { if (num < 0) {
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
} }
@ -919,17 +891,18 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
} }
// Read and process config. // Read and process config.
static int Process(const Config* config) { static int Process(const WebPMuxConfig* config) {
WebPMux* mux = NULL; WebPMux* mux = NULL;
WebPData chunk; WebPData chunk;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int ok = 1; int ok = 1;
const Feature* const feature = &config->feature_;
switch (config->action_type_) { switch (config->action_type_) {
case ACTION_GET: { case ACTION_GET: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
switch (config->type_) { switch (feature->type_) {
case FEATURE_ANMF: case FEATURE_ANMF:
ok = GetFrame(mux, config); ok = GetFrame(mux, config);
break; break;
@ -937,10 +910,10 @@ static int Process(const Config* config) {
case FEATURE_ICCP: case FEATURE_ICCP:
case FEATURE_EXIF: case FEATURE_EXIF:
case FEATURE_XMP: case FEATURE_XMP:
err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk); err = WebPMuxGetChunk(mux, kFourccList[feature->type_], &chunk);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not get the %s.\n", ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
ok = WriteData(config->output_, &chunk); ok = WriteData(config->output_, &chunk);
break; break;
@ -952,7 +925,7 @@ static int Process(const Config* config) {
break; break;
} }
case ACTION_SET: { case ACTION_SET: {
switch (config->type_) { switch (feature->type_) {
case FEATURE_ANMF: { case FEATURE_ANMF: {
int i; int i;
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 }; WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
@ -961,11 +934,11 @@ static int Process(const Config* config) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
} }
for (i = 0; i < config->arg_count_; ++i) { for (i = 0; i < feature->arg_count_; ++i) {
switch (config->args_[i].subtype_) { switch (feature->args_[i].subtype_) {
case SUBTYPE_BGCOLOR: { case SUBTYPE_BGCOLOR: {
uint32_t bgcolor; uint32_t bgcolor;
ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor); ok = ParseBgcolorArgs(feature->args_[i].params_, &bgcolor);
if (!ok) { if (!ok) {
ERROR_GOTO1("ERROR: Could not parse the background color \n", ERROR_GOTO1("ERROR: Could not parse the background color \n",
Err2); Err2);
@ -976,7 +949,7 @@ static int Process(const Config* config) {
case SUBTYPE_LOOP: { case SUBTYPE_LOOP: {
int parse_error = 0; int parse_error = 0;
const int loop_count = const int loop_count =
ExUtilGetInt(config->args_[i].params_, 10, &parse_error); ExUtilGetInt(feature->args_[i].params_, 10, &parse_error);
if (loop_count < 0 || loop_count > 65535) { if (loop_count < 0 || loop_count > 65535) {
// Note: This is only a 'necessary' condition for loop_count // Note: This is only a 'necessary' condition for loop_count
// to be valid. The 'sufficient' conditioned in checked in // to be valid. The 'sufficient' conditioned in checked in
@ -992,10 +965,10 @@ static int Process(const Config* config) {
case SUBTYPE_ANMF: { case SUBTYPE_ANMF: {
WebPMuxFrameInfo frame; WebPMuxFrameInfo frame;
frame.id = WEBP_CHUNK_ANMF; frame.id = WEBP_CHUNK_ANMF;
ok = ExUtilReadFileToWebPData(config->args_[i].filename_, ok = ReadFileToWebPData(feature->args_[i].filename_,
&frame.bitstream); &frame.bitstream);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ParseFrameArgs(config->args_[i].params_, &frame); ok = ParseFrameArgs(feature->args_[i].params_, &frame);
if (!ok) { if (!ok) {
WebPDataClear(&frame.bitstream); WebPDataClear(&frame.bitstream);
ERROR_GOTO1("ERROR: Could not parse frame properties.\n", ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
@ -1028,62 +1001,13 @@ static int Process(const Config* config) {
case FEATURE_XMP: { case FEATURE_XMP: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ExUtilReadFileToWebPData(config->args_[0].filename_, &chunk); ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk);
if (!ok) goto Err2; if (!ok) goto Err2;
err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1); err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1);
WebPDataClear(&chunk); free((void*)chunk.bytes);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not set the %s.\n", ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
}
break;
}
case FEATURE_LOOP: {
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
int parse_error = 0;
const int loop_count =
ExUtilGetInt(config->args_[0].params_, 10, &parse_error);
if (loop_count < 0 || loop_count > 65535 || parse_error) {
ERROR_GOTO1("ERROR: Loop count must be in the range 0 to 65535.\n",
Err2);
}
ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2;
ok = (WebPMuxGetAnimationParams(mux, &params) == WEBP_MUX_OK);
if (!ok) {
ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n",
Err2);
}
params.loop_count = loop_count;
err = WebPMuxSetAnimationParams(mux, &params);
ok = (err == WEBP_MUX_OK);
if (!ok) {
ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
ErrorString(err), Err2);
}
break;
}
case FEATURE_BGCOLOR: {
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
uint32_t bgcolor;
ok = ParseBgcolorArgs(config->args_[0].params_, &bgcolor);
if (!ok) {
ERROR_GOTO1("ERROR: Could not parse the background color.\n",
Err2);
}
ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2;
ok = (WebPMuxGetAnimationParams(mux, &params) == 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, &params);
ok = (err == WEBP_MUX_OK);
if (!ok) {
ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
ErrorString(err), Err2);
} }
break; break;
} }
@ -1114,16 +1038,16 @@ static int Process(const Config* config) {
int* durations = NULL; int* durations = NULL;
WebPMux* new_mux = DuplicateMuxHeader(mux); WebPMux* new_mux = DuplicateMuxHeader(mux);
if (new_mux == NULL) goto Err2; if (new_mux == NULL) goto Err2;
durations = (int*)WebPMalloc((size_t)num_frames * sizeof(*durations)); durations = (int*)malloc((size_t)num_frames * sizeof(*durations));
if (durations == NULL) goto Err2; if (durations == NULL) goto Err2;
for (i = 0; i < num_frames; ++i) durations[i] = -1; for (i = 0; i < num_frames; ++i) durations[i] = -1;
// Parse intervals to process. // Parse intervals to process.
for (i = 0; i < config->arg_count_; ++i) { for (i = 0; i < feature->arg_count_; ++i) {
int k; int k;
int args[3]; int args[3];
int duration, start, end; int duration, start, end;
const int nb_args = ExUtilGetInts(config->args_[i].params_, const int nb_args = ExUtilGetInts(feature->args_[i].params_,
10, 3, args); 10, 3, args);
ok = (nb_args >= 1); ok = (nb_args >= 1);
if (!ok) goto Err3; if (!ok) goto Err3;
@ -1172,7 +1096,7 @@ static int Process(const Config* config) {
new_mux = NULL; new_mux = NULL;
Err3: Err3:
WebPFree(durations); free(durations);
WebPMuxDelete(new_mux); WebPMuxDelete(new_mux);
if (!ok) goto Err2; if (!ok) goto Err2;
} }
@ -1181,12 +1105,12 @@ static int Process(const Config* config) {
case ACTION_STRIP: { case ACTION_STRIP: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF || if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF ||
config->type_ == FEATURE_XMP) { feature->type_ == FEATURE_XMP) {
err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]); err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n", ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
} else { } else {
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2); ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
@ -1216,19 +1140,15 @@ static int Process(const Config* config) {
// Main. // Main.
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
Config config; WebPMuxConfig config;
int ok; int ok = InitializeConfig(argc - 1, argv + 1, &config);
INIT_WARGV(argc, argv);
ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL());
if (ok) { if (ok) {
ok = Process(&config); ok = Process(&config);
} else { } else {
PrintHelp(); PrintHelp();
} }
DeleteConfig(&config); DeleteConfig(&config);
FREE_WARGV_AND_RETURN(!ok); return !ok;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -1,4 +1,3 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
noinst_LTLIBRARIES = libwebpextras.la noinst_LTLIBRARIES = libwebpextras.la
@ -12,33 +11,16 @@ libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
libwebpextras_la_LDFLAGS = -lm libwebpextras_la_LDFLAGS = -lm
libwebpextras_la_LIBADD = ../src/libwebp.la libwebpextras_la_LIBADD = ../src/libwebp.la
noinst_PROGRAMS = noinst_PROGRAMS = get_disto webp_quality
noinst_PROGRAMS += webp_quality
if BUILD_DEMUX
noinst_PROGRAMS += get_disto
endif
if BUILD_VWEBP_SDL
noinst_PROGRAMS += vwebp_sdl
endif
get_disto_SOURCES = get_disto.c get_disto_SOURCES = get_disto.c
get_disto_CPPFLAGS = $(AM_CPPFLAGS) get_disto_CPPFLAGS = $(AM_CPPFLAGS)
get_disto_LDADD = get_disto_LDADD = ../imageio/libimageio_util.la ../imageio/libimagedec.la
get_disto_LDADD += ../imageio/libimageio_util.la
get_disto_LDADD += ../imageio/libimagedec.la
get_disto_LDADD += ../src/libwebp.la get_disto_LDADD += ../src/libwebp.la
get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
webp_quality_SOURCES = webp_quality.c webp_quality_SOURCES = webp_quality.c
webp_quality_CPPFLAGS = $(AM_CPPFLAGS) webp_quality_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
webp_quality_LDADD = webp_quality_LDADD = ../imageio/libimageio_util.la
webp_quality_LDADD += ../imageio/libimageio_util.la
webp_quality_LDADD += libwebpextras.la webp_quality_LDADD += libwebpextras.la
webp_quality_LDADD += ../src/libwebp.la webp_quality_LDADD += ../src/libwebp.la
vwebp_sdl_SOURCES = vwebp_sdl.c webp_to_sdl.c webp_to_sdl.h
vwebp_sdl_CPPFLAGS = $(AM_CPPFLAGS) $(SDL_INCLUDES)
vwebp_sdl_LDADD =
vwebp_sdl_LDADD += ../imageio/libimageio_util.la
vwebp_sdl_LDADD += ../src/libwebp.la
vwebp_sdl_LDADD += $(SDL_LIBS)

View File

@ -10,16 +10,15 @@
// Additional WebP utilities. // Additional WebP utilities.
// //
#include "extras/extras.h" #include "./extras.h"
#include "webp/format_constants.h" #include "webp/format_constants.h"
#include "src/dsp/dsp.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#define XTRA_MAJ_VERSION 1 #define XTRA_MAJ_VERSION 0
#define XTRA_MIN_VERSION 3 #define XTRA_MIN_VERSION 1
#define XTRA_REV_VERSION 2 #define XTRA_REV_VERSION 0
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -49,16 +48,15 @@ int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) {
int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) { int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
int x, y; int x, y;
uint32_t* dst;
if (pic == NULL || rgb565 == NULL) return 0; if (pic == NULL || rgb565 == NULL) return 0;
pic->colorspace = WEBP_YUV420; pic->colorspace = WEBP_YUV420;
pic->use_argb = 1; pic->use_argb = 1;
if (!WebPPictureAlloc(pic)) return 0; if (!WebPPictureAlloc(pic)) return 0;
dst = pic->argb;
for (y = 0; y < pic->height; ++y) { for (y = 0; y < pic->height; ++y) {
const int width = pic->width; const int width = pic->width;
uint32_t* dst = pic->argb + y * pic->argb_stride;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1) #ifdef WEBP_SWAP_16BIT_CSP
const uint32_t rg = rgb565[2 * x + 1]; const uint32_t rg = rgb565[2 * x + 1];
const uint32_t gb = rgb565[2 * x + 0]; const uint32_t gb = rgb565[2 * x + 0];
#else #else
@ -72,26 +70,24 @@ int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
r = r | (r >> 5); r = r | (r >> 5);
g = g | (g >> 6); g = g | (g >> 6);
b = b | (b >> 5); b = b | (b >> 5);
dst[x] = (0xffu << 24) | (r << 16) | (g << 8) | b; dst[x] = (r << 16) | (g << 8) | b;
} }
rgb565 += 2 * width; rgb565 += 2 * width;
dst += pic->argb_stride;
} }
return 1; return 1;
} }
int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) { int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
int x, y; int x, y;
uint32_t* dst;
if (pic == NULL || rgb4444 == NULL) return 0; if (pic == NULL || rgb4444 == NULL) return 0;
pic->colorspace = WEBP_YUV420; pic->colorspace = WEBP_YUV420;
pic->use_argb = 1; pic->use_argb = 1;
if (!WebPPictureAlloc(pic)) return 0; if (!WebPPictureAlloc(pic)) return 0;
dst = pic->argb;
for (y = 0; y < pic->height; ++y) { for (y = 0; y < pic->height; ++y) {
const int width = pic->width; const int width = pic->width;
uint32_t* dst = pic->argb + y * pic->argb_stride;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1) #ifdef WEBP_SWAP_16BIT_CSP
const uint32_t rg = rgb4444[2 * x + 1]; const uint32_t rg = rgb4444[2 * x + 1];
const uint32_t ba = rgb4444[2 * x + 0]; const uint32_t ba = rgb4444[2 * x + 0];
#else #else
@ -110,7 +106,6 @@ int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
dst[x] = (a << 24) | (r << 16) | (g << 8) | b; dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
} }
rgb4444 += 2 * width; rgb4444 += 2 * width;
dst += pic->argb_stride;
} }
return 1; return 1;
} }
@ -145,18 +140,3 @@ int WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int WebPUnmultiplyARGB(WebPPicture* pic) {
int y;
uint32_t* dst;
if (pic == NULL || pic->use_argb != 1 || pic->argb == NULL) return 0;
WebPInitAlphaProcessing();
dst = pic->argb;
for (y = 0; y < pic->height; ++y) {
WebPMultARGBRow(dst, pic->width, /*inverse=*/1);
dst += pic->argb_stride;
}
return 1;
}
//------------------------------------------------------------------------------

View File

@ -19,45 +19,38 @@ extern "C" {
#include "webp/encode.h" #include "webp/encode.h"
#define WEBP_EXTRAS_ABI_VERSION 0x0002 // MAJOR(8b) + MINOR(8b) #define WEBP_EXTRAS_ABI_VERSION 0x0001 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Returns the version number of the extras library, packed in hexadecimal using // Returns the version number of the extras library, packed in hexadecimal using
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. // 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
WEBP_EXTERN int WebPGetExtrasVersion(void); WEBP_EXTERN(int) WebPGetExtrasVersion(void);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Ad-hoc colorspace importers. // Ad-hoc colorspace importers.
// Import luma sample (gray scale image) into 'picture'. The 'picture' // Import luma sample (gray scale image) into 'picture'. The 'picture'
// width and height must be set prior to calling this function. // width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportGray(const uint8_t* gray, WebPPicture* picture); WEBP_EXTERN(int) WebPImportGray(const uint8_t* gray, WebPPicture* picture);
// Import rgb sample in RGB565 packed format into 'picture'. The 'picture' // Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
// width and height must be set prior to calling this function. // width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic); WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture' // Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
// width and height must be set prior to calling this function. // width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic); WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
// Import a color mapped image. The number of colors is less or equal to // Import a color mapped image. The number of colors is less or equal to
// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any, // MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any,
// will be discarded. Returns 'false' in case of error, or if indexed[] contains // will be discarded. Returns 'false' in case of error, or if indexed[] contains
// invalid indices. // invalid indices.
WEBP_EXTERN int WEBP_EXTERN(int)
WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride, WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
const uint32_t palette[], int palette_size, const uint32_t palette[], int palette_size,
WebPPicture* pic); WebPPicture* pic);
// Convert the ARGB content of 'pic' from associated to unassociated.
// 'pic' can be for instance the result of calling of some WebPPictureImportXXX
// functions, with pic->use_argb set to 'true'. It is assumed (and not checked)
// that the pre-multiplied r/g/b values as less or equal than the alpha value.
// Return false in case of error (invalid parameter, ...).
WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Parse a bitstream, search for VP8 (lossy) header and report a // Parse a bitstream, search for VP8 (lossy) header and report a
@ -66,7 +59,7 @@ WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic);
// Otherwise (lossy bitstream), the returned value is in the range [0..100]. // Otherwise (lossy bitstream), the returned value is in the range [0..100].
// Any error (invalid bitstream, animated WebP, incomplete header, etc.) // Any error (invalid bitstream, animated WebP, incomplete header, etc.)
// will return a value of -1. // will return a value of -1.
WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size); WEBP_EXTERN(int) VP8EstimateQuality(const uint8_t* const data, size_t size);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -74,4 +67,4 @@ WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_EXTRAS_EXTRAS_H_ #endif /* WEBP_EXTRAS_EXTRAS_H_ */

View File

@ -24,9 +24,8 @@
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "imageio/image_dec.h" #include "../imageio/image_dec.h"
#include "imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "../examples/unicode.h"
static size_t ReadPicture(const char* const filename, WebPPicture* const pic, static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
int keep_alpha) { int keep_alpha) {
@ -49,8 +48,7 @@ static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
End: End:
if (!ok) { if (!ok) {
WFPRINTF(stderr, "Error! Could not process file %s\n", fprintf(stderr, "Error! Could not process file %s\n", filename);
(const W_CHAR*)filename);
} }
free((void*)data); free((void*)data);
return ok ? data_size : 0; return ok ? data_size : 0;
@ -223,8 +221,7 @@ 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"
"\nSupported input formats:\n %s\n", " Also handles PNG, JPG and TIFF files, in addition to WebP.\n");
WebPGetEnabledInputFileFormats());
} }
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
@ -242,11 +239,9 @@ int main(int argc, const char* argv[]) {
const char* name2 = NULL; const char* name2 = NULL;
const char* output = NULL; const char* output = NULL;
INIT_WARGV(argc, argv);
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) { if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
fprintf(stderr, "Can't init pictures\n"); fprintf(stderr, "Can't init pictures\n");
FREE_WARGV_AND_RETURN(1); return 1;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
@ -268,11 +263,11 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]); fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
goto End; goto End;
} }
output = (const char*)GET_WARGV(argv, c); output = argv[c];
} else if (name1 == NULL) { } else if (name1 == NULL) {
name1 = (const char*)GET_WARGV(argv, c); name1 = argv[c];
} else { } else {
name2 = (const char*)GET_WARGV(argv, c); name2 = argv[c];
} }
} }
if (help || name1 == NULL || name2 == NULL) { if (help || name1 == NULL || name2 == NULL) {
@ -283,7 +278,7 @@ int main(int argc, const char* argv[]) {
goto End; goto End;
} }
size1 = ReadPicture(name1, &pic1, 1); size1 = ReadPicture(name1, &pic1, 1);
size2 = ReadPicture(name2, &pic2, 1); size2 = ReadPicture(name1, &pic2, 1);
if (size1 == 0 || size2 == 0) goto End; if (size1 == 0 || size2 == 0) goto End;
if (!keep_alpha) { if (!keep_alpha) {
@ -295,10 +290,9 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Error while computing the distortion.\n"); fprintf(stderr, "Error while computing the distortion.\n");
goto End; goto End;
} }
printf("%u %.2f %.2f %.2f %.2f %.2f [ %.2f bpp ]\n", printf("%u %.2f %.2f %.2f %.2f %.2f\n",
(unsigned int)size1, (unsigned int)size1,
disto[4], disto[0], disto[1], disto[2], disto[3], disto[4], disto[0], disto[1], disto[2], disto[3]);
8.f * size1 / pic1.width / pic1.height);
if (output != NULL) { if (output != NULL) {
uint8_t* data = NULL; uint8_t* data = NULL;
@ -328,7 +322,6 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Can only compute the difference map in ARGB format.\n"); fprintf(stderr, "Can only compute the difference map in ARGB format.\n");
goto End; goto End;
} }
#if !defined(WEBP_REDUCE_CSP)
data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb, data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb,
pic1.width, pic1.height, pic1.width, pic1.height,
pic1.argb_stride * 4, pic1.argb_stride * 4,
@ -340,17 +333,11 @@ int main(int argc, const char* argv[]) {
ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1; ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
WebPFree(data); WebPFree(data);
if (ret) goto End; if (ret) goto End;
#else
(void)data;
(void)data_size;
fprintf(stderr, "Cannot save the difference map. Please recompile "
"without the WEBP_REDUCE_CSP flag.\n");
#endif // WEBP_REDUCE_CSP
} }
ret = 0; ret = 0;
End: End:
WebPPictureFree(&pic1); WebPPictureFree(&pic1);
WebPPictureFree(&pic2); WebPPictureFree(&pic2);
FREE_WARGV_AND_RETURN(ret); return ret;
} }

View File

@ -11,7 +11,7 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include "extras/extras.h" #include "./extras.h"
#include "webp/decode.h" #include "webp/decode.h"
#include <math.h> #include <math.h>
@ -73,7 +73,7 @@ int VP8EstimateQuality(const uint8_t* const data, size_t size) {
pos += 4; pos += 4;
bit_pos = pos * 8; bit_pos = pos * 8;
GET_BIT(2); // colorspace + clamp type GET_BIT(2); // color_space + clamp type
// Segment header // Segment header
if (GET_BIT(1)) { // use_segment_ if (GET_BIT(1)) { // use_segment_

View File

@ -1,101 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Simple SDL-based WebP file viewer.
// Does not support animation, just static images.
//
// Press 'q' to exit.
//
// Author: James Zern (jzern@google.com)
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#if defined(WEBP_HAVE_SDL)
#include "webp_to_sdl.h"
#include "webp/decode.h"
#include "imageio/imageio_util.h"
#include "../examples/unicode.h"
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
static void ProcessEvents(void) {
int done = 0;
SDL_Event event;
while (!done && SDL_WaitEvent(&event)) {
switch (event.type) {
case SDL_KEYUP:
switch (event.key.keysym.sym) {
case SDLK_q: done = 1; break;
default: break;
}
break;
default: break;
}
}
}
int main(int argc, char* argv[]) {
int c;
int ok = 0;
INIT_WARGV(argc, argv);
for (c = 1; c < argc; ++c) {
const char* file = NULL;
const uint8_t* webp = NULL;
size_t webp_size = 0;
if (!strcmp(argv[c], "-h")) {
printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]);
FREE_WARGV_AND_RETURN(0);
} else {
file = (const char*)GET_WARGV(argv, c);
}
if (file == NULL) continue;
if (!ImgIoUtilReadFile(file, &webp, &webp_size)) {
WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file);
goto Error;
}
if (webp_size != (size_t)(int)webp_size) {
free((void*)webp);
fprintf(stderr, "File too large.\n");
goto Error;
}
ok = WebPToSDL((const char*)webp, (int)webp_size);
free((void*)webp);
if (!ok) {
WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file);
goto Error;
}
ProcessEvents();
}
ok = 1;
Error:
SDL_Quit();
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
}
#else // !WEBP_HAVE_SDL
int main(int argc, const char* argv[]) {
fprintf(stderr, "SDL support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
}
#endif

View File

@ -11,32 +11,28 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "extras/extras.h" #include "./extras.h"
#include "imageio/imageio_util.h" #include "../imageio/imageio_util.h"
#include "../examples/unicode.h"
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
int c; int c;
int quiet = 0; int quiet = 0;
int ok = 1; int ok = 1;
INIT_WARGV(argc, argv);
for (c = 1; ok && c < argc; ++c) { for (c = 1; ok && c < argc; ++c) {
if (!strcmp(argv[c], "-quiet")) { if (!strcmp(argv[c], "-quiet")) {
quiet = 1; quiet = 1;
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) { } else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
printf("webp_quality [-h][-quiet] webp_files...\n"); printf("webp_quality [-h][-quiet] webp_files...\n");
FREE_WARGV_AND_RETURN(0); return 0;
} else { } else {
const char* const filename = (const char*)GET_WARGV(argv, c); const char* const filename = argv[c];
const uint8_t* data = NULL; const uint8_t* data = NULL;
size_t data_size = 0; size_t data_size = 0;
int q; int q;
ok = ImgIoUtilReadFile(filename, &data, &data_size); ok = ImgIoUtilReadFile(filename, &data, &data_size);
if (!ok) break; if (!ok) break;
q = VP8EstimateQuality(data, data_size); q = VP8EstimateQuality(data, data_size);
if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename); if (!quiet) printf("[%s] ", filename);
if (q < 0) { if (q < 0) {
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n"); fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
ok = 0; ok = 0;
@ -50,5 +46,5 @@ int main(int argc, const char* argv[]) {
free((void*)data); free((void*)data);
} }
} }
FREE_WARGV_AND_RETURN(ok ? 0 : 1); return ok ? 0 : 1;
} }

View File

@ -1,110 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Simple WebP-to-SDL wrapper. Useful for emscripten.
//
// Author: James Zern (jzern@google.com)
#ifdef HAVE_CONFIG_H
#include "src/webp/config.h"
#endif
#if defined(WEBP_HAVE_SDL)
#include "webp_to_sdl.h"
#include <stdio.h>
#include "src/webp/decode.h"
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
static int init_ok = 0;
int WebPToSDL(const char* data, unsigned int data_size) {
int ok = 0;
VP8StatusCode status;
WebPDecoderConfig config;
WebPBitstreamFeatures* const input = &config.input;
WebPDecBuffer* const output = &config.output;
SDL_Surface* screen = NULL;
SDL_Surface* surface = NULL;
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
return 0;
}
if (!init_ok) {
SDL_Init(SDL_INIT_VIDEO);
init_ok = 1;
}
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
if (status != VP8_STATUS_OK) goto Error;
screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
if (screen == NULL) {
fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
input->width, input->height);
goto Error;
}
surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
input->width, input->height, 32,
0x000000ffu, // R mask
0x0000ff00u, // G mask
0x00ff0000u, // B mask
0xff000000u); // A mask
if (surface == NULL) {
fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
input->width, input->height);
goto Error;
}
if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
output->colorspace = MODE_BGRA;
#else
output->colorspace = MODE_RGBA;
#endif
output->width = surface->w;
output->height = surface->h;
output->u.RGBA.rgba = surface->pixels;
output->u.RGBA.stride = surface->pitch;
output->u.RGBA.size = surface->pitch * surface->h;
output->is_external_memory = 1;
status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config);
if (status != VP8_STATUS_OK) {
fprintf(stderr, "Error decoding image (%d)\n", status);
goto Error;
}
if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
SDL_Flip(screen)) {
goto Error;
}
ok = 1;
Error:
SDL_FreeSurface(surface);
SDL_FreeSurface(screen);
WebPFreeDecBuffer(output);
return ok;
}
//------------------------------------------------------------------------------
#endif // WEBP_HAVE_SDL

View File

@ -1,22 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Simple WebP-to-SDL wrapper. Useful for emscripten.
//
// Author: James Zern (jzern@google.com)
#ifndef WEBP_EXTRAS_WEBP_TO_SDL_H_
#define WEBP_EXTRAS_WEBP_TO_SDL_H_
// Exports the method WebPToSDL(const char* data, int data_size) which decodes
// a WebP bitstream into an RGBA SDL surface.
// Return false on failure.
extern int WebPToSDL(const char* data, unsigned int data_size);
#endif // WEBP_EXTRAS_WEBP_TO_SDL_H_

Binary file not shown.

View File

@ -1,5 +1,6 @@
#Thu May 12 17:06:25 CEST 2016
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip

61
gradlew vendored
View File

@ -1,20 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env bash
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
@ -44,7 +28,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -125,8 +109,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin or MSYS, switch paths to Windows format before running java # For Cygwin, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
@ -154,30 +138,27 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=`expr $i + 1` i=$((i+1))
done done
case $i in case $i in
0) set -- ;; (0) set -- ;;
1) set -- "$args0" ;; (1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;; (2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;; (3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
save () { function splitJvmOpts() {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done JVM_OPTS=("$@")
echo " "
} }
APP_ARGS=`save "$@"` eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, following the shell quoting and substitution rules exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

24
gradlew.bat vendored
View File

@ -1,19 +1,3 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -30,7 +14,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS=
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
@ -65,6 +49,7 @@ goto fail
@rem Get command-line arguments, handling Windows variants @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
@ -75,6 +60,11 @@ set _SKIP=2
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute :execute
@rem Setup the command line @rem Setup the command line

View File

@ -1,5 +1,3 @@
# Ignore this file during non-NDK builds.
ifdef NDK_ROOT
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
################################################################################ ################################################################################
@ -27,7 +25,6 @@ LOCAL_SRC_FILES := \
jpegdec.c \ jpegdec.c \
metadata.c \ metadata.c \
pngdec.c \ pngdec.c \
pnmdec.c \
tiffdec.c \ tiffdec.c \
webpdec.c \ webpdec.c \
@ -54,4 +51,3 @@ LOCAL_STATIC_LIBRARIES := imageio_util
LOCAL_MODULE := imageenc LOCAL_MODULE := imageenc
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
endif # NDK_ROOT

View File

@ -1,32 +1,22 @@
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
noinst_LTLIBRARIES = noinst_LTLIBRARIES = libimageio_util.la libimagedec.la libimageenc.la
noinst_LTLIBRARIES += libimageio_util.la
if BUILD_DEMUX
noinst_LTLIBRARIES += libimagedec.la
endif
noinst_LTLIBRARIES += libimageenc.la
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += ../src/webp/decode.h noinst_HEADERS += ../src/webp/decode.h
noinst_HEADERS += ../src/webp/types.h noinst_HEADERS += ../src/webp/types.h
libimageio_util_la_SOURCES = libimageio_util_la_SOURCES = imageio_util.c imageio_util.h
libimageio_util_la_SOURCES += imageio_util.c imageio_util.h
libimagedec_la_SOURCES = libimagedec_la_SOURCES = image_dec.c image_dec.h
libimagedec_la_SOURCES += image_dec.c image_dec.h
libimagedec_la_SOURCES += jpegdec.c jpegdec.h libimagedec_la_SOURCES += jpegdec.c jpegdec.h
libimagedec_la_SOURCES += metadata.c metadata.h libimagedec_la_SOURCES += metadata.c metadata.h
libimagedec_la_SOURCES += pngdec.c pngdec.h libimagedec_la_SOURCES += pngdec.c pngdec.h
libimagedec_la_SOURCES += pnmdec.c pnmdec.h
libimagedec_la_SOURCES += tiffdec.c tiffdec.h libimagedec_la_SOURCES += tiffdec.c tiffdec.h
libimagedec_la_SOURCES += webpdec.c webpdec.h libimagedec_la_SOURCES += webpdec.c webpdec.h
libimagedec_la_SOURCES += wicdec.c wicdec.h libimagedec_la_SOURCES += wicdec.c wicdec.h
libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES) libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS) libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
libimagedec_la_LIBADD = ../src/demux/libwebpdemux.la
libimageenc_la_SOURCES = libimageenc_la_SOURCES = image_enc.c image_enc.h
libimageenc_la_SOURCES += image_enc.c image_enc.h
libimageenc_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES) libimageenc_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS) libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)

View File

@ -11,24 +11,6 @@
#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];
} }
@ -47,10 +29,6 @@ WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
format = WEBP_TIFF_FORMAT; format = WEBP_TIFF_FORMAT;
} else if (magic1 == 0x52494646 && magic2 == 0x57454250) { } else if (magic1 == 0x52494646 && magic2 == 0x57454250) {
format = WEBP_WEBP_FORMAT; format = WEBP_WEBP_FORMAT;
} else if (((magic1 >> 24) & 0xff) == 'P') {
const int type = (magic1 >> 16) & 0xff;
// we only support 'P5 -> P7' for now.
if (type >= '5' && type <= '7') format = WEBP_PNM_FORMAT;
} }
} }
return format; return format;
@ -73,7 +51,6 @@ WebPImageReader WebPGetImageReader(WebPInputFileFormat format) {
case WEBP_JPEG_FORMAT: return ReadJPEG; case WEBP_JPEG_FORMAT: return ReadJPEG;
case WEBP_TIFF_FORMAT: return ReadTIFF; case WEBP_TIFF_FORMAT: return ReadTIFF;
case WEBP_WEBP_FORMAT: return ReadWebP; case WEBP_WEBP_FORMAT: return ReadWebP;
case WEBP_PNM_FORMAT: return ReadPNM;
default: return FailReader; default: return FailReader;
} }
} }

View File

@ -23,7 +23,6 @@
#include "./metadata.h" #include "./metadata.h"
#include "./jpegdec.h" #include "./jpegdec.h"
#include "./pngdec.h" #include "./pngdec.h"
#include "./pnmdec.h"
#include "./tiffdec.h" #include "./tiffdec.h"
#include "./webpdec.h" #include "./webpdec.h"
#include "./wicdec.h" #include "./wicdec.h"
@ -37,13 +36,9 @@ typedef enum {
WEBP_JPEG_FORMAT, WEBP_JPEG_FORMAT,
WEBP_TIFF_FORMAT, WEBP_TIFF_FORMAT,
WEBP_WEBP_FORMAT, WEBP_WEBP_FORMAT,
WEBP_PNM_FORMAT,
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,

View File

@ -29,13 +29,11 @@
// code with COBJMACROS. // code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal() #include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h> #include <shlwapi.h>
#include <tchar.h>
#include <windows.h> #include <windows.h>
#include <wincodec.h> #include <wincodec.h>
#endif #endif
#include "./imageio_util.h" #include "./imageio_util.h"
#include "../examples/unicode.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// PNG // PNG
@ -63,12 +61,11 @@ static HRESULT CreateOutputStream(const char* out_file_name,
// Output to a memory buffer. This is freed when 'stream' is released. // Output to a memory buffer. This is freed when 'stream' is released.
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream)); IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
} else { } else {
IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name, IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
STGM_WRITE | STGM_CREATE, stream));
} }
if (FAILED(hr)) { if (FAILED(hr)) {
_ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"), fprintf(stderr, "Error opening output file %s (%08lx)\n",
(const LPTSTR)out_file_name, hr); out_file_name, hr);
} }
return hr; return hr;
} }
@ -155,14 +152,20 @@ 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 unused) { static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
(void)unused; // remove variable-unused warning (void)dummy; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1); longjmp(png_jmpbuf(png), 1);
} }
int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) { int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
png_bytep row = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
volatile png_structp png; volatile png_structp png;
volatile png_infop info; volatile png_infop info;
png_uint_32 y;
if (out_file == NULL || buffer == NULL) return 0; if (out_file == NULL || buffer == NULL) return 0;
@ -181,14 +184,6 @@ int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
return 0; return 0;
} }
png_init_io(png, out_file); png_init_io(png, out_file);
{
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
png_bytep row = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
uint32_t y;
png_set_IHDR(png, info, width, height, 8, png_set_IHDR(png, info, width, height, 8,
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB, has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
@ -198,7 +193,6 @@ int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
png_write_rows(png, &row, 1); png_write_rows(png, &row, 1);
row += stride; row += stride;
} }
}
png_write_end(png, info); png_write_end(png, info);
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info); png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
return 1; return 1;
@ -280,7 +274,7 @@ int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// BMP (see https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage) // BMP
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,11 +287,8 @@ 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;
@ -306,9 +297,8 @@ 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 image_size = bmp_stride * height; const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
const uint32_t total_size = image_size + header_size; uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
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;
@ -316,37 +306,30 @@ 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, header_size); // offset to pixel array PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
// bitmap info header // bitmap info header
PutLE32(bmp_header + 14, header_size - 14); // DIB header size PutLE32(bmp_header + 14, 40); // DIB header size
PutLE32(bmp_header + 18, width); // dimensions PutLE32(bmp_header + 18, width); // dimensions
PutLE32(bmp_header + 22, height); // no vertical flip PutLE32(bmp_header + 22, -(int)height); // 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, has_alpha ? 3 : 0); // BI_BITFIELDS or BI_RGB PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
PutLE32(bmp_header + 34, image_size); PutLE32(bmp_header + 34, 0); // image size (dummy)
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, header_size, 1, fout) != 1) { if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
return 0; return 0;
} }
// write pixel array, bottom to top // write pixel array
for (y = 0; y < height; ++y) { for (y = 0; y < height; ++y) {
const uint8_t* const src = &rgba[(uint64_t)(height - 1 - y) * stride]; if (fwrite(rgba, line_size, 1, fout) != 1) {
if (fwrite(src, line_size, 1, fout) != 1) {
return 0; return 0;
} }
// write padding zeroes // write padding zeroes
@ -356,11 +339,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
@ -378,8 +361,6 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const uint8_t* rgba = buffer->u.RGBA.rgba; const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride; const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3; const uint8_t bytes_per_px = has_alpha ? 4 : 3;
const uint8_t assoc_alpha =
WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
// For non-alpha case, we omit tag 0x152 (ExtraSamples). // For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1; : NUM_IFD_ENTRIES - 1;
@ -407,8 +388,7 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
EXTRA_DATA_OFFSET + 8, 0, 0, 0, EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch) 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
0x52, 0x01, 3, 0, 1, 0, 0, 0, 0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
assoc_alpha, 0, 0, 0, // 178: ExtraSamples: rgbA/RGBA
0, 0, 0, 0, // 190: IFD terminator 0, 0, 0, 0, // 190: IFD terminator
// EXTRA_DATA_OFFSET: // EXTRA_DATA_OFFSET:
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
@ -559,26 +539,22 @@ int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
// Generic top-level call // Generic top-level call
int WebPSaveImage(const WebPDecBuffer* const buffer, int WebPSaveImage(const WebPDecBuffer* const buffer,
WebPOutputFileFormat format, WebPOutputFileFormat format, const char* const out_file) {
const char* const out_file_name) {
FILE* fout = NULL; FILE* fout = NULL;
int needs_open_file = 1; int needs_open_file = 1;
const int use_stdout = const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
(out_file_name != NULL) && !WSTRCMP(out_file_name, "-");
int ok = 1; int ok = 1;
if (buffer == NULL || out_file_name == NULL) return 0; if (buffer == NULL || out_file == NULL) return 0;
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG); needs_open_file = (format != PNG);
#endif #endif
if (needs_open_file) { if (needs_open_file) {
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
: WFOPEN(out_file_name, "wb");
if (fout == NULL) { if (fout == NULL) {
WFPRINTF(stderr, "Error opening output file %s\n", fprintf(stderr, "Error opening output file %s\n", out_file);
(const W_CHAR*)out_file_name);
return 0; return 0;
} }
} }
@ -587,7 +563,7 @@ int WebPSaveImage(const WebPDecBuffer* const buffer,
format == RGBA || format == BGRA || format == ARGB || format == RGBA || format == BGRA || format == ARGB ||
format == rgbA || format == bgrA || format == Argb) { format == rgbA || format == bgrA || format == Argb) {
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
ok &= WebPWritePNG(out_file_name, use_stdout, buffer); ok &= WebPWritePNG(out_file, use_stdout, buffer);
#else #else
ok &= WebPWritePNG(fout, buffer); ok &= WebPWritePNG(fout, buffer);
#endif #endif

View File

@ -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: https://www.fourcc.org/yuv.php#IMC4. // See: http://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);

View File

@ -18,7 +18,6 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "../examples/unicode.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// File I/O // File I/O
@ -48,8 +47,7 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
while (!feof(stdin)) { while (!feof(stdin)) {
// We double the buffer size each time and read as much as possible. // We double the buffer size each time and read as much as possible.
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size; const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
// we allocate one extra byte for the \0 terminator void* const new_data = realloc(input, max_size + extra_size);
void* const new_data = realloc(input, max_size + extra_size + 1);
if (new_data == NULL) goto Error; if (new_data == NULL) goto Error;
input = (uint8_t*)new_data; input = (uint8_t*)new_data;
max_size += extra_size; max_size += extra_size;
@ -57,7 +55,6 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
if (size < max_size) break; if (size < max_size) break;
} }
if (ferror(stdin)) goto Error; if (ferror(stdin)) goto Error;
if (input != NULL) input[size] = '\0'; // convenient 0-terminator
*data = input; *data = input;
*data_size = size; *data_size = size;
return 1; return 1;
@ -71,10 +68,10 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
int ImgIoUtilReadFile(const char* const file_name, int ImgIoUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size) { const uint8_t** data, size_t* data_size) {
int ok; int ok;
uint8_t* file_data; void* file_data;
size_t file_size; size_t file_size;
FILE* in; FILE* in;
const int from_stdin = (file_name == NULL) || !WSTRCMP(file_name, "-"); const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size); if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
@ -82,52 +79,42 @@ int ImgIoUtilReadFile(const char* const file_name,
*data = NULL; *data = NULL;
*data_size = 0; *data_size = 0;
in = WFOPEN(file_name, "rb"); in = fopen(file_name, "rb");
if (in == NULL) { if (in == NULL) {
WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)file_name); fprintf(stderr, "cannot open input file '%s'\n", file_name);
return 0; return 0;
} }
fseek(in, 0, SEEK_END); fseek(in, 0, SEEK_END);
file_size = ftell(in); file_size = ftell(in);
fseek(in, 0, SEEK_SET); fseek(in, 0, SEEK_SET);
// we allocate one extra byte for the \0 terminator file_data = malloc(file_size);
file_data = (uint8_t*)WebPMalloc(file_size + 1); if (file_data == NULL) return 0;
if (file_data == NULL) {
fclose(in);
WFPRINTF(stderr, "memory allocation failure when reading file %s\n",
(const W_CHAR*)file_name);
return 0;
}
ok = (fread(file_data, file_size, 1, in) == 1); ok = (fread(file_data, file_size, 1, in) == 1);
fclose(in); fclose(in);
if (!ok) { if (!ok) {
WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n", fprintf(stderr, "Could not read %d bytes of data from file %s\n",
(int)file_size, (const W_CHAR*)file_name); (int)file_size, file_name);
WebPFree(file_data); free(file_data);
return 0; return 0;
} }
file_data[file_size] = '\0'; // convenient 0-terminator *data = (uint8_t*)file_data;
*data = file_data;
*data_size = file_size; *data_size = file_size;
return 1; return 1;
} }
// -----------------------------------------------------------------------------
int ImgIoUtilWriteFile(const char* const file_name, int ImgIoUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size) { const uint8_t* data, size_t data_size) {
int ok; int ok;
FILE* out; FILE* out;
const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-"); const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
if (data == NULL) { if (data == NULL) {
return 0; return 0;
} }
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb"); out = to_stdout ? stdout : fopen(file_name, "wb");
if (out == NULL) { if (out == NULL) {
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
(const W_CHAR*)file_name);
return 0; return 0;
} }
ok = (fwrite(data, data_size, 1, out) == 1); ok = (fwrite(data, data_size, 1, out) == 1);
@ -148,15 +135,9 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) { int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = stride * height; const uint64_t total_size = nmemb * size;
int ok = (total_size == (size_t)total_size); return (total_size == (size_t)total_size);
// check that 'stride' is representable as int:
ok = ok && ((uint64_t)(int)stride == stride);
#if defined(WEBP_MAX_IMAGE_SIZE)
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
#endif
return ok;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -29,10 +29,7 @@ FILE* ImgIoUtilSetBinaryMode(FILE* file);
// Allocates storage for entire file 'file_name' and returns contents and size // Allocates storage for entire file 'file_name' and returns contents and size
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
// be deleted using WebPFree(). // be deleted using free().
// Note: for convenience, the data will be null-terminated with an extra byte
// (not accounted for in *data_size), in case the file is text and intended
// to be used as a C-string.
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling // If 'file_name' is NULL or equal to "-", input is read from stdin by calling
// the function ImgIoUtilReadFromStdin(). // the function ImgIoUtilReadFromStdin().
int ImgIoUtilReadFile(const char* const file_name, int ImgIoUtilReadFile(const char* const file_name,
@ -54,8 +51,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Returns 0 in case of overflow, memory over-allocation or excessive dimension. // Returns 0 in case of overflow of nmemb * size.
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height); int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -206,7 +206,6 @@ struct my_error_mgr {
static void my_error_exit(j_common_ptr dinfo) { static void my_error_exit(j_common_ptr dinfo) {
struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err; struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
fprintf(stderr, "libjpeg error: ");
dinfo->err->output_message(dinfo); dinfo->err->output_message(dinfo);
longjmp(myerr->setjmp_buffer, 1); longjmp(myerr->setjmp_buffer, 1);
} }
@ -274,7 +273,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 safety memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
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;
@ -305,18 +304,18 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
if (stride != (int)stride || if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error; goto End;
} }
rgb = (uint8_t*)malloc((size_t)stride * height); rgb = (uint8_t*)malloc((size_t)stride * height);
if (rgb == NULL) { if (rgb == NULL) {
goto Error; goto End;
} }
buffer[0] = (JSAMPLE*)rgb; buffer[0] = (JSAMPLE*)rgb;
while (dinfo.output_scanline < dinfo.output_height) { while (dinfo.output_scanline < dinfo.output_height) {
if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) { if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) {
goto Error; goto End;
} }
buffer[0] += stride; buffer[0] += stride;
} }
@ -336,11 +335,7 @@ 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) { if (!ok) goto Error;
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);

View File

@ -18,9 +18,6 @@
#include <stdio.h> #include <stdio.h>
#ifdef WEBP_HAVE_PNG #ifdef WEBP_HAVE_PNG
#ifndef PNG_USER_MEM_SUPPORTED
#define PNG_USER_MEM_SUPPORTED // for png_create_read_struct_2
#endif
#include <png.h> #include <png.h>
#include <setjmp.h> // note: this must be included *after* png.h #include <setjmp.h> // note: this must be included *after* png.h
#include <stdlib.h> #include <stdlib.h>
@ -30,33 +27,11 @@
#include "./imageio_util.h" #include "./imageio_util.h"
#include "./metadata.h" #include "./metadata.h"
#define LOCAL_PNG_VERSION ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR)
#define LOCAL_PNG_PREREQ(maj, min) \
(LOCAL_PNG_VERSION >= (((maj) << 8) | (min)))
static void PNGAPI error_function(png_structp png, png_const_charp error) { static void PNGAPI error_function(png_structp png, png_const_charp error) {
if (error != NULL) fprintf(stderr, "libpng error: %s\n", error); if (error != NULL) fprintf(stderr, "libpng error: %s\n", error);
longjmp(png_jmpbuf(png), 1); longjmp(png_jmpbuf(png), 1);
} }
#if LOCAL_PNG_PREREQ(1,4)
typedef png_alloc_size_t LocalPngAllocSize;
#else
typedef png_size_t LocalPngAllocSize;
#endif
static png_voidp MallocFunc(png_structp png_ptr, LocalPngAllocSize size) {
(void)png_ptr;
if (size != (size_t)size) return NULL;
if (!ImgIoUtilCheckSizeArgumentsOverflow(size, 1)) return NULL;
return (png_voidp)malloc((size_t)size);
}
static void FreeFunc(png_structp png_ptr, png_voidp ptr) {
(void)png_ptr;
free(ptr);
}
// Converts the NULL terminated 'hexstring' which contains 2-byte character // Converts the NULL terminated 'hexstring' which contains 2-byte character
// representations of hex values to raw data. // representations of hex values to raw data.
// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, // 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs,
@ -133,7 +108,7 @@ static const struct {
MetadataPayload* const payload); MetadataPayload* const payload);
size_t storage_offset; size_t storage_offset;
} kPNGMetadataMap[] = { } kPNGMetadataMap[] = {
// https://exiftool.org/TagNames/PNG.html#TextualData // http://www.sno.phy.queensu.ca/~phil/exiftool/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) },
@ -196,10 +171,11 @@ static int ExtractMetadataFromPNG(png_structp png,
{ {
png_charp name; png_charp name;
int comp_type; int comp_type;
#if LOCAL_PNG_PREREQ(1,5) #if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \
png_bytep profile; ((1 << 8) | (5 << 0))
#else
png_charp profile; png_charp profile;
#else // >= libpng 1.5.0
png_bytep profile;
#endif #endif
png_uint_32 len; png_uint_32 len;
@ -209,6 +185,7 @@ static int ExtractMetadataFromPNG(png_structp png,
} }
} }
} }
return 1; return 1;
} }
@ -235,7 +212,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
volatile png_infop end_info = NULL; volatile png_infop end_info = NULL;
PNGReadContext context = { NULL, 0, 0 }; PNGReadContext context = { NULL, 0, 0 };
int color_type, bit_depth, interlaced; int color_type, bit_depth, interlaced;
int num_channels; int has_alpha;
int num_passes; int num_passes;
int p; int p;
volatile int ok = 0; volatile int ok = 0;
@ -248,8 +225,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
context.data = data; context.data = data;
context.data_size = data_size; context.data_size = data_size;
png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
NULL, MallocFunc, FreeFunc);
if (png == NULL) goto End; if (png == NULL) goto End;
png_set_error_fn(png, 0, error_function, NULL); png_set_error_fn(png, 0, error_function, NULL);
@ -259,15 +235,6 @@ 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
// internal limit (default: 8M), try to (reasonably) raise it.
if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
png_set_chunk_malloc_max(png, data_size);
}
#endif
info = png_create_info_struct(png); info = png_create_info_struct(png);
if (info == NULL) goto Error; if (info == NULL) goto Error;
end_info = png_create_info_struct(png); end_info = png_create_info_struct(png);
@ -293,30 +260,20 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
} }
if (png_get_valid(png, info, PNG_INFO_tRNS)) { if (png_get_valid(png, info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png); png_set_tRNS_to_alpha(png);
} has_alpha = 1;
} else {
// Apply gamma correction if needed. has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
{
double image_gamma = 1 / 2.2, screen_gamma = 2.2;
int srgb_intent;
if (png_get_sRGB(png, info, &srgb_intent) ||
png_get_gAMA(png, info, &image_gamma)) {
png_set_gamma(png, screen_gamma, image_gamma);
}
} }
if (!keep_alpha) { if (!keep_alpha) {
png_set_strip_alpha(png); png_set_strip_alpha(png);
has_alpha = 0;
} }
num_passes = png_set_interlace_handling(png); num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info); png_read_update_info(png, info);
num_channels = png_get_channels(png, info); stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
if (num_channels != 3 && num_channels != 4) {
goto Error;
}
stride = (int64_t)num_channels * width * sizeof(*rgb);
if (stride != (int)stride || if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error; goto Error;
@ -341,7 +298,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
pic->width = (int)width; pic->width = (int)width;
pic->height = (int)height; pic->height = (int)height;
ok = (num_channels == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride) ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride)
: WebPPictureImportRGB(pic, rgb, (int)stride); : WebPPictureImportRGB(pic, rgb, (int)stride);
if (!ok) { if (!ok) {

View File

@ -1,301 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// (limited) PNM decoder
#include "./pnmdec.h"
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h"
#include "./imageio_util.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
typedef enum {
WIDTH_FLAG = 1 << 0,
HEIGHT_FLAG = 1 << 1,
DEPTH_FLAG = 1 << 2,
MAXVAL_FLAG = 1 << 3,
TUPLE_FLAG = 1 << 4,
ALL_NEEDED_FLAGS = WIDTH_FLAG | HEIGHT_FLAG | DEPTH_FLAG | MAXVAL_FLAG
} PNMFlags;
typedef struct {
const uint8_t* data;
size_t data_size;
int width, height;
int bytes_per_px;
int depth; // 1 (grayscale), 2 (grayscale + alpha), 3 (rgb), 4 (rgba)
int max_value;
int type; // 5, 6 or 7
int seen_flags;
} PNMInfo;
// -----------------------------------------------------------------------------
// PNM decoding
#define MAX_LINE_SIZE 1024
static const size_t kMinPNMHeaderSize = 3;
static size_t ReadLine(const uint8_t* const data, size_t off, size_t data_size,
char out[MAX_LINE_SIZE + 1], size_t* const out_size) {
size_t i = 0;
*out_size = 0;
redo:
for (i = 0; i < MAX_LINE_SIZE && off < data_size; ++i) {
out[i] = data[off++];
if (out[i] == '\n') break;
}
if (off < data_size) {
if (i == 0) goto redo; // empty line
if (out[0] == '#') goto redo; // skip comment
}
out[i] = 0; // safety sentinel
*out_size = i;
return off;
}
static size_t FlagError(const char flag[]) {
fprintf(stderr, "PAM header error: flags '%s' already seen.\n", flag);
return 0;
}
// inspired from http://netpbm.sourceforge.net/doc/pam.html
static size_t ReadPAMFields(PNMInfo* const info, size_t off) {
char out[MAX_LINE_SIZE + 1];
size_t out_size;
int tmp;
int expected_depth = -1;
assert(info != NULL);
while (1) {
off = ReadLine(info->data, off, info->data_size, out, &out_size);
if (off == 0) return 0;
if (sscanf(out, "WIDTH %d", &tmp) == 1) {
if (info->seen_flags & WIDTH_FLAG) return FlagError("WIDTH");
info->seen_flags |= WIDTH_FLAG;
info->width = tmp;
} else if (sscanf(out, "HEIGHT %d", &tmp) == 1) {
if (info->seen_flags & HEIGHT_FLAG) return FlagError("HEIGHT");
info->seen_flags |= HEIGHT_FLAG;
info->height = tmp;
} else if (sscanf(out, "DEPTH %d", &tmp) == 1) {
if (info->seen_flags & DEPTH_FLAG) return FlagError("DEPTH");
info->seen_flags |= DEPTH_FLAG;
info->depth = tmp;
} else if (sscanf(out, "MAXVAL %d", &tmp) == 1) {
if (info->seen_flags & MAXVAL_FLAG) return FlagError("MAXVAL");
info->seen_flags |= MAXVAL_FLAG;
info->max_value = tmp;
} else if (!strcmp(out, "TUPLTYPE RGB_ALPHA")) {
expected_depth = 4;
info->seen_flags |= TUPLE_FLAG;
} else if (!strcmp(out, "TUPLTYPE RGB")) {
expected_depth = 3;
info->seen_flags |= TUPLE_FLAG;
} else if (!strcmp(out, "TUPLTYPE GRAYSCALE_ALPHA")) {
expected_depth = 2;
info->seen_flags |= TUPLE_FLAG;
} else if (!strcmp(out, "TUPLTYPE GRAYSCALE")) {
expected_depth = 1;
info->seen_flags |= TUPLE_FLAG;
} else if (!strcmp(out, "ENDHDR")) {
break;
} else {
static const char kEllipsis[] = " ...";
const size_t kLen = strlen(kEllipsis) + 1; // +1 = trailing \0
int i;
if (out_size > 20) snprintf(out + 20 - kLen, kLen, kEllipsis);
for (i = 0; i < (int)strlen(out); ++i) {
// isprint() might trigger a "char-subscripts" warning if given a char.
if (!isprint((int)out[i])) out[i] = ' ';
}
fprintf(stderr, "PAM header error: unrecognized entry [%s]\n", out);
return 0;
}
}
if (!(info->seen_flags & ALL_NEEDED_FLAGS)) {
fprintf(stderr, "PAM header error: missing tags%s%s%s%s\n",
(info->seen_flags & WIDTH_FLAG) ? "" : " WIDTH",
(info->seen_flags & HEIGHT_FLAG) ? "" : " HEIGHT",
(info->seen_flags & DEPTH_FLAG) ? "" : " DEPTH",
(info->seen_flags & MAXVAL_FLAG) ? "" : " MAXVAL");
return 0;
}
if (expected_depth != -1 && info->depth != expected_depth) {
fprintf(stderr, "PAM header error: expected DEPTH %d but got DEPTH %d\n",
expected_depth, info->depth);
return 0;
}
return off;
}
static size_t ReadHeader(PNMInfo* const info) {
size_t off = 0;
char out[MAX_LINE_SIZE + 1];
size_t out_size;
if (info == NULL) return 0;
if (info->data == NULL || info->data_size < kMinPNMHeaderSize) return 0;
info->width = info->height = 0;
info->type = -1;
info->seen_flags = 0;
info->bytes_per_px = 0;
info->depth = 0;
info->max_value = 0;
off = ReadLine(info->data, off, info->data_size, out, &out_size);
if (off == 0 || sscanf(out, "P%d", &info->type) != 1) return 0;
if (info->type == 7) {
off = ReadPAMFields(info, off);
} else {
off = ReadLine(info->data, off, info->data_size, out, &out_size);
if (off == 0 || sscanf(out, "%d %d", &info->width, &info->height) != 2) {
return 0;
}
off = ReadLine(info->data, off, info->data_size, out, &out_size);
if (off == 0 || sscanf(out, "%d", &info->max_value) != 1) return 0;
// finish initializing missing fields
info->depth = (info->type == 5) ? 1 : 3;
}
// perform some basic numerical validation
if (info->width <= 0 || info->height <= 0 ||
info->type <= 0 || info->type >= 9 ||
info->depth <= 0 || info->depth > 4 ||
info->max_value <= 0 || info->max_value >= 65536) {
return 0;
}
info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1);
return off;
}
int ReadPNM(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
int ok = 0;
int i, j;
uint64_t stride, pixel_bytes, sample_size, depth;
uint8_t* rgb = NULL, *tmp_rgb;
size_t offset;
PNMInfo info;
info.data = data;
info.data_size = data_size;
offset = ReadHeader(&info);
if (offset == 0) {
fprintf(stderr, "Error parsing PNM header.\n");
goto End;
}
if (info.type < 5 || info.type > 7) {
fprintf(stderr, "Unsupported P%d PNM format.\n", info.type);
goto End;
}
// Some basic validations.
if (pic == NULL) goto End;
if (info.width > WEBP_MAX_DIMENSION || info.height > WEBP_MAX_DIMENSION) {
fprintf(stderr, "Invalid %dx%d dimension for PNM\n",
info.width, info.height);
goto End;
}
pixel_bytes = (uint64_t)info.width * info.height * info.bytes_per_px;
if (data_size < offset + pixel_bytes) {
fprintf(stderr, "Truncated PNM file (P%d).\n", info.type);
goto End;
}
sample_size = (info.max_value > 255) ? 2 : 1;
// final depth
depth = (info.depth == 1 || info.depth == 3 || !keep_alpha) ? 3 : 4;
stride = depth * info.width;
if (stride != (size_t)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, info.height)) {
goto End;
}
rgb = (uint8_t*)malloc((size_t)stride * info.height);
if (rgb == NULL) goto End;
// Convert input.
// We only optimize for the sample_size=1, max_value=255, depth=1 case.
tmp_rgb = rgb;
for (j = 0; j < info.height; ++j) {
const uint8_t* in = data + offset;
offset += info.bytes_per_px * info.width;
assert(offset <= data_size);
if (info.max_value == 255 && info.depth >= 3) {
// RGB or RGBA
if (info.depth == 3 || keep_alpha) {
memcpy(tmp_rgb, in, info.depth * info.width * sizeof(*in));
} else {
assert(info.depth == 4 && !keep_alpha);
for (i = 0; i < info.width; ++i) {
tmp_rgb[3 * i + 0] = in[4 * i + 0];
tmp_rgb[3 * i + 1] = in[4 * i + 1];
tmp_rgb[3 * i + 2] = in[4 * i + 2];
}
}
} else {
// Unoptimized case, we need to handle non-trivial operations:
// * convert 16b to 8b (if max_value > 255)
// * rescale to [0..255] range (if max_value != 255)
// * drop the alpha channel (if keep_alpha is false)
const uint32_t round = info.max_value / 2;
int k = 0;
for (i = 0; i < info.width * info.depth; ++i) {
uint32_t v = (sample_size == 2) ? 256u * in[2 * i + 0] + in[2 * i + 1]
: in[i];
if (info.max_value != 255) v = (v * 255u + round) / info.max_value;
if (v > 255u) v = 255u;
if (info.depth > 2) {
if (!keep_alpha && info.depth == 4 && (i % 4) == 3) {
// skip alpha
} else {
tmp_rgb[k] = v;
k += 1;
}
} else if (info.depth == 1 || (i % 2) == 0) {
tmp_rgb[k + 0] = tmp_rgb[k + 1] = tmp_rgb[k + 2] = v;
k += 3;
} else if (keep_alpha && info.depth == 2) {
tmp_rgb[k] = v;
k += 1;
} else {
// skip alpha
}
}
}
tmp_rgb += stride;
}
// WebP conversion.
pic->width = info.width;
pic->height = info.height;
ok = (depth == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
: WebPPictureImportRGB(pic, rgb, (int)stride);
if (!ok) goto End;
ok = 1;
End:
free((void*)rgb);
(void)metadata;
(void)keep_alpha;
return ok;
}
// -----------------------------------------------------------------------------

View File

@ -1,37 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// partial PNM format decoder (ppm/pgm)
#ifndef WEBP_IMAGEIO_PNMDEC_H_
#define WEBP_IMAGEIO_PNMDEC_H_
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads a PNM file from 'data', returning the decoded output in 'pic'.
// The output is RGB or YUV depending on pic->use_argb value.
// Returns true on success.
// 'metadata' has no effect, but is kept for coherence with other signatures
// for image readers.
int ReadPNM(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_IMAGEIO_PNMDEC_H_

View File

@ -15,7 +15,6 @@
#include "webp/config.h" #include "webp/config.h"
#endif #endif
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -46,7 +45,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_t tag_data_len; uint32 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)) {
@ -108,7 +107,7 @@ static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) {
static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) { static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
MyData* const my_data = (MyData*)opaque; MyData* const my_data = (MyData*)opaque;
if (my_data->pos + size > my_data->size) { if (my_data->pos + size > my_data->size) {
size = (tsize_t)(my_data->size - my_data->pos); size = my_data->size - my_data->pos;
} }
if (size > 0) { if (size > 0) {
memcpy(dst, my_data->data + my_data->pos, size); memcpy(dst, my_data->data + my_data->pos, size);
@ -117,58 +116,18 @@ static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
return size; return size;
} }
// Unmultiply Argb data. Taken from dsp/alpha_processing
// (we don't want to force a dependency to a libdspdec library).
#define MFIX 24 // 24bit fixed-point arithmetic
#define HALF ((1u << MFIX) >> 1)
static uint32_t Unmult(uint8_t x, uint32_t mult) {
const uint32_t v = (x * mult + HALF) >> MFIX;
return (v > 255u) ? 255u : v;
}
static WEBP_INLINE uint32_t GetScale(uint32_t a) {
return (255u << MFIX) / a;
}
#undef MFIX
#undef HALF
static void MultARGBRow(uint8_t* ptr, int width) {
int x;
for (x = 0; x < width; ++x, ptr += 4) {
const uint32_t alpha = ptr[3];
if (alpha < 255) {
if (alpha == 0) { // alpha == 0
ptr[0] = ptr[1] = ptr[2] = 0;
} else {
const uint32_t scale = GetScale(alpha);
ptr[0] = Unmult(ptr[0], scale);
ptr[1] = Unmult(ptr[1], scale);
ptr[2] = Unmult(ptr[2], scale);
}
}
}
}
int ReadTIFF(const uint8_t* const data, size_t data_size, int ReadTIFF(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha, WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) { Metadata* const metadata) {
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 width, height;
uint64_t stride; uint32* raster;
uint16_t samples_per_px = 0;
uint16_t extra_samples = 0;
uint16_t* extra_samples_ptr = NULL;
uint32_t* raster;
int64_t alloc_size; int64_t alloc_size;
int ok = 0; int ok = 0;
tdir_t dircount; tdir_t dircount;
if (data == NULL || data_size == 0 || data_size > INT_MAX || pic == NULL) { if (data == NULL || data_size == 0 || pic == NULL) return 0;
return 0;
}
tif = TIFFClientOpen("Memory", "r", &my_data, tif = TIFFClientOpen("Memory", "r", &my_data,
MyRead, MyRead, MySeek, MyClose, MyRead, MyRead, MySeek, MyClose,
@ -184,77 +143,35 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
"Only the first will be used, %d will be ignored.\n", "Only the first will be used, %d will be ignored.\n",
dircount - 1); dircount - 1);
} }
if (!TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_px)) {
fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
goto End;
}
if (!(samples_per_px == 1 || samples_per_px == 3 || samples_per_px == 4)) {
goto End; // not supported
}
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) && if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) { TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
goto End; goto End;
} }
stride = (uint64_t)image_width * sizeof(*raster);
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) { if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n", sizeof(*raster))) {
image_width, image_height);
goto End; goto End;
} }
// According to spec, a tile can be bigger than the image. However it should
// be a multiple of 16 and not way too large, so check that it's not more
// than twice the image size, for dimensions above some arbitrary minimum
// 32. We also check that they respect WebP's dimension and memory limit.
// Note that a tile can be 6byte/px in some cases. Here we assume
// 4byte/px with sizeof(*raster), to be conservative.
if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) &&
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) {
if ((tile_width > 32 && tile_width / 2 > image_width) ||
(tile_height > 32 && tile_height / 2 > image_height) ||
!ImgIoUtilCheckSizeArgumentsOverflow(
(uint64_t)tile_width * sizeof(*raster), tile_height)) {
fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n",
tile_width, tile_height);
goto End;
}
}
if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extra_samples, &extra_samples_ptr)) {
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
goto End;
}
// _Tiffmalloc uses a signed type for size. // _Tiffmalloc uses a signed type for size.
alloc_size = (int64_t)(stride * image_height); alloc_size = (int64_t)((uint64_t)width * 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_t*)_TIFFmalloc((tsize_t)alloc_size); raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
if (raster != NULL) { if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster, if (TIFFReadRGBAImageOriented(tif, width, height, raster,
ORIENTATION_TOPLEFT, 1)) { ORIENTATION_TOPLEFT, 1)) {
pic->width = image_width; const int stride = width * sizeof(*raster);
pic->height = image_height; pic->width = width;
pic->height = height;
// TIFF data is ABGR // TIFF data is ABGR
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
TIFFSwabArrayOfLong(raster, image_width * image_height); TIFFSwabArrayOfLong(raster, width * height);
#endif #endif
// if we have an alpha channel, we must un-multiply from rgbA to RGBA
if (extra_samples == 1 && extra_samples_ptr != NULL &&
extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) {
uint32_t y;
uint8_t* tmp = (uint8_t*)raster;
for (y = 0; y < image_height; ++y) {
MultARGBRow(tmp, image_width);
tmp += stride;
}
}
ok = keep_alpha ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride) ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride); : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
} }
_TIFFfree(raster); _TIFFfree(raster);
} else { } else {

View File

@ -9,20 +9,13 @@
// //
// WebP decode. // WebP decode.
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "./webpdec.h" #include "./webpdec.h"
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "webp/decode.h" #include "webp/decode.h"
#include "webp/demux.h"
#include "webp/encode.h" #include "webp/encode.h"
#include "../examples/unicode.h"
#include "./imageio_util.h" #include "./imageio_util.h"
#include "./metadata.h" #include "./metadata.h"
@ -44,7 +37,7 @@ static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
} }
void PrintWebPError(const char* const in_file, int status) { void PrintWebPError(const char* const in_file, int status) {
WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file); fprintf(stderr, "Decoding of %s failed.\n", in_file);
fprintf(stderr, "Status: %d", status); fprintf(stderr, "Status: %d", status);
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) { if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
fprintf(stderr, "(%s)", kStatusMessages[status]); fprintf(stderr, "(%s)", kStatusMessages[status]);
@ -65,7 +58,7 @@ int LoadWebP(const char* const in_file,
status = WebPGetFeatures(*data, *data_size, bitstream); status = WebPGetFeatures(*data, *data_size, bitstream);
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {
WebPFree((void*)*data); free((void*)*data);
*data = NULL; *data = NULL;
*data_size = 0; *data_size = 0;
PrintWebPError(in_file, status); PrintWebPError(in_file, status);
@ -95,50 +88,28 @@ 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 WebPIDecode().\n"); fprintf(stderr, "Failed during WebPINewDecoder().\n");
return VP8_STATUS_OUT_OF_MEMORY; return VP8_STATUS_OUT_OF_MEMORY;
} else { } else {
#ifdef WEBP_EXPERIMENTAL_FEATURES
size_t size = 0;
const size_t incr = 2 + (data_size / 20);
while (size < data_size) {
size_t next_size = size + (rand() % incr);
if (next_size > data_size) next_size = data_size;
status = WebPIUpdate(idec, data, next_size);
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) break;
size = next_size;
}
#else
status = WebPIUpdate(idec, data, data_size); status = WebPIUpdate(idec, data, data_size);
#endif
WebPIDelete(idec); WebPIDelete(idec);
} }
} }
return status; return status;
} }
// -----------------------------------------------------------------------------
// Metadata
static int ExtractMetadata(const uint8_t* const data, size_t data_size,
Metadata* const metadata) {
WebPData webp_data = { data, data_size };
WebPDemuxer* const demux = WebPDemux(&webp_data);
WebPChunkIterator chunk_iter;
uint32_t flags;
if (demux == NULL) return 0;
assert(metadata != NULL);
flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->iccp);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->exif);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->xmp);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
WebPDemuxDelete(demux);
return 1;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
int ReadWebP(const uint8_t* const data, size_t data_size, int ReadWebP(const uint8_t* const data, size_t data_size,
@ -152,6 +123,11 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
if (data == NULL || data_size == 0 || pic == NULL) return 0; if (data == NULL || data_size == 0 || pic == NULL) return 0;
// TODO(jzern): add Exif/XMP/ICC extraction.
if (metadata != NULL) {
fprintf(stderr, "Warning: metadata extraction from WebP is unsupported.\n");
}
if (!WebPInitDecoderConfig(&config)) { if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
return 0; return 0;
@ -162,82 +138,52 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
PrintWebPError("input data", status); PrintWebPError("input data", status);
return 0; return 0;
} }
{
do {
const int has_alpha = keep_alpha && bitstream->has_alpha; const int has_alpha = keep_alpha && bitstream->has_alpha;
uint64_t stride;
pic->width = bitstream->width;
pic->height = bitstream->height;
if (pic->use_argb) { if (pic->use_argb) {
stride = (uint64_t)bitstream->width * 4; output_buffer->colorspace = has_alpha ? MODE_RGBA : MODE_RGB;
} else {
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
}
status = DecodeWebP(data, data_size, &config);
if (status == VP8_STATUS_OK) {
pic->width = output_buffer->width;
pic->height = output_buffer->height;
if (pic->use_argb) {
const uint8_t* const rgba = output_buffer->u.RGBA.rgba;
const int stride = output_buffer->u.RGBA.stride;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgba, stride)
: WebPPictureImportRGB(pic, rgba, stride);
} else { } else {
stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
}
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
status = VP8_STATUS_OUT_OF_MEMORY;
break;
}
ok = WebPPictureAlloc(pic); ok = WebPPictureAlloc(pic);
if (!ok) { if (!ok) {
status = VP8_STATUS_OUT_OF_MEMORY; status = VP8_STATUS_OUT_OF_MEMORY;
break;
}
if (pic->use_argb) {
#ifdef WORDS_BIGENDIAN
output_buffer->colorspace = MODE_ARGB;
#else
output_buffer->colorspace = MODE_BGRA;
#endif
output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
} else { } else {
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV; const WebPYUVABuffer* const yuva = &output_buffer->u.YUVA;
output_buffer->u.YUVA.y = pic->y; const int uv_width = (pic->width + 1) >> 1;
output_buffer->u.YUVA.u = pic->u; const int uv_height = (pic->height + 1) >> 1;
output_buffer->u.YUVA.v = pic->v; ImgIoUtilCopyPlane(yuva->y, yuva->y_stride,
output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL; pic->y, pic->y_stride, pic->width, pic->height);
output_buffer->u.YUVA.y_stride = pic->y_stride; ImgIoUtilCopyPlane(yuva->u, yuva->u_stride,
output_buffer->u.YUVA.u_stride = pic->uv_stride; pic->u, pic->uv_stride, uv_width, uv_height);
output_buffer->u.YUVA.v_stride = pic->uv_stride; ImgIoUtilCopyPlane(yuva->v, yuva->v_stride,
output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0; pic->v, pic->uv_stride, uv_width, uv_height);
output_buffer->u.YUVA.y_size = pic->height * pic->y_stride; if (has_alpha) {
output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride; ImgIoUtilCopyPlane(yuva->a, yuva->a_stride,
output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride; pic->a, pic->a_stride, pic->width, pic->height);
output_buffer->u.YUVA.a_size = pic->height * pic->a_stride; }
} }
output_buffer->is_external_memory = 1; }
status = DecodeWebP(data, data_size, &config);
ok = (status == VP8_STATUS_OK);
if (ok && !keep_alpha && pic->use_argb) {
// Need to wipe out the alpha value, as requested.
int x, y;
uint32_t* argb = pic->argb;
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
argb += pic->argb_stride;
} }
} }
} while (0); // <- so we can 'break' out of the loop
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {
PrintWebPError("input data", status); PrintWebPError("input data", status);
ok = 0;
} }
WebPFreeDecBuffer(output_buffer); WebPFreeDecBuffer(output_buffer);
if (ok && metadata != NULL) {
ok = ExtractMetadata(data, data_size, metadata);
if (!ok) {
PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
}
}
if (!ok) WebPPictureFree(pic);
return ok; return ok;
} }

View File

@ -51,7 +51,7 @@ VP8StatusCode DecodeWebPIncremental(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Decodes a WebP contained in 'data', returning the decoded output in 'pic'. // Reads a WebP from 'in_file', returning the decoded output in 'pic'.
// Output is RGBA or YUVA, depending on pic->use_argb value. // Output is RGBA or YUVA, depending on pic->use_argb value.
// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA // If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.

View File

@ -29,14 +29,12 @@
// code with COBJMACROS. // code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal() #include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h> #include <shlwapi.h>
#include <tchar.h>
#include <windows.h> #include <windows.h>
#include <wincodec.h> #include <wincodec.h>
#include "../examples/unicode.h" #include "webp/encode.h"
#include "./imageio_util.h" #include "./imageio_util.h"
#include "./metadata.h" #include "./metadata.h"
#include "webp/encode.h"
#define IFS(fn) \ #define IFS(fn) \
do { \ do { \
@ -87,7 +85,7 @@ WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
static HRESULT OpenInputStream(const char* filename, IStream** stream) { static HRESULT OpenInputStream(const char* filename, IStream** stream) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!WSTRCMP(filename, "-")) { if (!strcmp(filename, "-")) {
const uint8_t* data = NULL; const uint8_t* data = NULL;
size_t data_size = 0; size_t data_size = 0;
const int ok = ImgIoUtilReadFile(filename, &data, &data_size); const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
@ -110,12 +108,11 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) {
hr = E_FAIL; hr = E_FAIL;
} }
} else { } else {
IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream)); IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
} }
if (FAILED(hr)) { if (FAILED(hr)) {
_ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"), fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
(const LPTSTR)filename, hr);
} }
return hr; return hr;
} }
@ -134,10 +131,7 @@ 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) { if (FAILED(hr) || count == 0) return hr;
// 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;
@ -273,15 +267,10 @@ 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;
@ -306,15 +295,9 @@ int ReadPictureWithWIC(const char* const filename,
factory, stream, NULL, factory, stream, NULL,
WICDecodeMetadataCacheOnDemand, &decoder)); WICDecodeMetadataCacheOnDemand, &decoder));
IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count)); IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr) && frame_count == 0) {
if (frame_count == 0) {
fprintf(stderr, "No frame found in input file.\n"); fprintf(stderr, "No frame found in input file.\n");
hr = E_FAIL; hr = E_FAIL;
} else if (frame_count > 1) {
// WIC will be tried before native WebP decoding so avoid duplicating the
// error message.
hr = E_FAIL;
}
} }
IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame)); IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format)); IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));

View File

@ -1,106 +0,0 @@
# 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}" ]]
}

View File

@ -1,401 +0,0 @@
#!/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

View File

@ -1,224 +0,0 @@
#!/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

View File

@ -1,75 +0,0 @@
#!/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

View File

@ -1,98 +0,0 @@
#!/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

View File

@ -1,21 +1,17 @@
#!/bin/bash #!/bin/bash
# #
# This script generates 'WebP.framework' and 'WebPDecoder.framework', # This script generates 'WebP.framework' and 'WebPDecoder.framework'. An iOS
# 'WebPDemux.framework' and 'WebPMux.framework'. # app can decode WebP images by including 'WebPDecoder.framework' and both
# An iOS app can decode WebP images by including 'WebPDecoder.framework' and # encode and decode WebP images by including 'WebP.framework'.
# both encode and decode WebP images by including 'WebP.framework'.
# #
# Run ./iosbuild.sh to generate the frameworks under the current directory # Run ./iosbuild.sh to generate the frameworks under the current directory
# (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.
# (https://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/). # (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
set -e set -e
# Set this variable based on the desired minimum deployment target.
readonly IOS_MIN_VERSION=6.0
# Extract the latest SDK version from the final field of the form: iphoneosX.Y # Extract the latest SDK version from the final field of the form: iphoneosX.Y
readonly SDK=$(xcodebuild -showsdks \ readonly SDK=$(xcodebuild -showsdks \
| grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
@ -39,59 +35,35 @@ readonly TOPDIR=$(pwd)
readonly BUILDDIR="${TOPDIR}/iosbuild" readonly BUILDDIR="${TOPDIR}/iosbuild"
readonly TARGETDIR="${TOPDIR}/WebP.framework" readonly TARGETDIR="${TOPDIR}/WebP.framework"
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework" readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.framework"
readonly DEVELOPER=$(xcode-select --print-path) readonly DEVELOPER=$(xcode-select --print-path)
readonly PLATFORMSROOT="${DEVELOPER}/Platforms" readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo) readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
LIBLIST='' LIBLIST=''
DECLIBLIST='' DECLIBLIST=''
MUXLIBLIST=''
DEMUXLIBLIST=''
if [[ -z "${SDK}" ]]; then if [[ -z "${SDK}" ]]; then
echo "iOS SDK not available" echo "iOS SDK not available"
exit 1 exit 1
elif [[ ${SDK%%.*} -gt 8 ]]; then elif [[ ${SDK%%.*} -gt 8 ]]; then
EXTRA_CFLAGS="-fembed-bitcode" EXTRA_CFLAGS="-fembed-bitcode"
elif [[ ${SDK%%.*} -le 6 ]]; then elif [[ ${SDK} < 6.0 ]]; then
echo "You need iOS SDK version 6.0 or above" echo "You need iOS SDK version 6.0 or above"
exit 1 exit 1
else
echo "iOS SDK Version ${SDK}"
fi fi
echo "Xcode Version: ${XCODE}" rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR}
echo "iOS SDK Version: ${SDK}" mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/
if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
|| -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \
|| -e "${SHARPYUVTARGETDIR}" ]]; then
cat << EOF
WARNING: The following directories will be deleted:
WARNING: ${BUILDDIR}
WARNING: ${TARGETDIR}
WARNING: ${DECTARGETDIR}
WARNING: ${MUXTARGETDIR}
WARNING: ${DEMUXTARGETDIR}
WARNING: ${SHARPYUVTARGETDIR}
WARNING: The build will continue in 5 seconds...
EOF
sleep 5
fi
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR}
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \
${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/ \
${SHARPYUVTARGETDIR}/Headers/
if [[ ! -e ${SRCDIR}/configure ]]; then if [[ ! -e ${SRCDIR}/configure ]]; then
if ! (cd ${SRCDIR} && sh autogen.sh); then if ! (cd ${SRCDIR} && sh autogen.sh); then
cat << EOF cat <<EOT
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:
https://www.macports.org/install.php http://www.macports.org/install.php
EOF EOT
exit 1 exit 1
fi fi
fi fi
@ -125,7 +97,7 @@ for PLATFORM in ${PLATFORMS}; do
SDKROOT="${PLATFORMSROOT}/" SDKROOT="${PLATFORMSROOT}/"
SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/" SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG" CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
CFLAGS+=" -miphoneos-version-min=${IOS_MIN_VERSION} ${EXTRA_CFLAGS}" CFLAGS+=" -miphoneos-version-min=6.0 ${EXTRA_CFLAGS}"
set -x set -x
export PATH="${DEVROOT}/usr/bin:${OLDPATH}" export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
@ -133,46 +105,25 @@ for PLATFORM in ${PLATFORMS}; do
--build=$(${SRCDIR}/config.guess) \ --build=$(${SRCDIR}/config.guess) \
--disable-shared --enable-static \ --disable-shared --enable-static \
--enable-libwebpdecoder --enable-swap-16bit-csp \ --enable-libwebpdecoder --enable-swap-16bit-csp \
--enable-libwebpmux \
CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS}"
set +x set +x
# Build only the libraries, skip the examples. # run make only in the src/ directory to create libwebp.a/libwebpdecoder.a
make V=0 -C sharpyuv install cd src/
make V=0 -C src install make V=0
make install
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a" LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a" DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
SHARPYUVLIBLIST+=" ${ROOTDIR}/lib/libsharpyuv.a"
make clean make clean
cd ..
export PATH=${OLDPATH} export PATH=${OLDPATH}
done done
echo "LIBLIST = ${LIBLIST}"
cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/ cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP ${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
echo "DECLIBLIST = ${DECLIBLIST}"
cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/ cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/
${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder ${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder
echo "MUXLIBLIST = ${MUXLIBLIST}"
cp -a ${SRCDIR}/src/webp/{types,mux,mux_types}.h \
${MUXTARGETDIR}/Headers/
${LIPO} -create ${MUXLIBLIST} -output ${MUXTARGETDIR}/WebPMux
echo "DEMUXLIBLIST = ${DEMUXLIBLIST}"
cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
${DEMUXTARGETDIR}/Headers/
${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux
echo "SHARPYUVLIBLIST = ${SHARPYUVLIBLIST}"
cp -a ${SRCDIR}/sharpyuv/{sharpyuv,sharpyuv_csp}.h \
${SHARPYUVTARGETDIR}/Headers/
${LIPO} -create ${SHARPYUVLIBLIST} -output ${SHARPYUVTARGETDIR}/SharpYuv
echo "SUCCESS"

View File

@ -3,8 +3,7 @@
# It will not install the libraries system-wide, but just create the 'cwebp' # It will not install the libraries system-wide, but just create the 'cwebp'
# and 'dwebp' tools in the examples/ directory, along with the static # and 'dwebp' tools in the examples/ directory, along with the static
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a', # libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
# 'src/demux/libwebpdemux.a', 'extras/libwebpextras.a' and # 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'.
# 'sharpyuv/libsharpyuv.a'.
# #
# To build the library and examples, use: # To build the library and examples, use:
# make -f makefile.unix # make -f makefile.unix
@ -26,29 +25,16 @@ ifeq ($(strip $(shell uname)), Darwin)
# Failure observed with: gcc 4.2.1 and 4.0.1. # Failure observed with: gcc 4.2.1 and 4.0.1.
EXTRA_FLAGS += -fno-common EXTRA_FLAGS += -fno-common
EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H
EXTRA_FLAGS += -Wno-deprecated-declarations
EXTRA_FLAGS += -I/opt/local/include EXTRA_FLAGS += -I/opt/local/include
EXTRA_LIBS += -L/opt/local/lib EXTRA_LIBS += -L/opt/local/lib
GL_LIBS = -framework GLUT -framework OpenGL GL_LIBS = -framework GLUT -framework OpenGL
else else
EXTRA_FLAGS += -I/usr/local/include
EXTRA_LIBS += -L/usr/local/lib
GL_LIBS = -lglut -lGL GL_LIBS = -lglut -lGL
endif endif
# SDL flags: use sdl-config if it exists
SDL_CONFIG = $(shell sdl-config --version 2> /dev/null)
ifneq ($(SDL_CONFIG),)
SDL_LIBS = $(shell sdl-config --libs)
SDL_FLAGS = $(shell sdl-config --cflags)
else
# use best-guess
SDL_LIBS = -lSDL
SDL_FLAGS =
endif
# To install libraries on Mac OS X: # To install libraries on Mac OS X:
# 1. Install MacPorts (https://www.macports.org/install.php) # 1. Install MacPorts (http://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"
@ -65,8 +51,11 @@ endif
# 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect. # 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect.
# EXTRA_FLAGS += -m32 # EXTRA_FLAGS += -m32
# Extra flags to enable experimental features and code
# EXTRA_FLAGS += -DWEBP_EXPERIMENTAL_FEATURES
# Extra flags to enable byte swap for 16 bit colorspaces. # Extra flags to enable byte swap for 16 bit colorspaces.
# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP=1 # EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP
# Extra flags to enable multi-threading # Extra flags to enable multi-threading
EXTRA_FLAGS += -DWEBP_USE_THREAD EXTRA_FLAGS += -DWEBP_USE_THREAD
@ -90,6 +79,12 @@ EXTRA_FLAGS += -DWEBP_HAVE_SSE41
src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1 src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1
endif endif
# AVX2-specific flags:
ifeq ($(HAVE_AVX2), 1)
EXTRA_FLAGS += -DWEBP_HAVE_AVX2
src/dsp/%_avx2.o: EXTRA_FLAGS += -mavx2
endif
# NEON-specific flags: # NEON-specific flags:
# EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 # EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8
# -> seems to make the overall lib slower: -fno-split-wide-types # -> seems to make the overall lib slower: -fno-split-wide-types
@ -106,35 +101,17 @@ endif
AR = ar AR = ar
ARFLAGS = r ARFLAGS = r
CPPFLAGS = -I. -Isrc/ -Wall CPPFLAGS = -Isrc/ -Wall
ifeq ($(DEBUG), 1) CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
CFLAGS = -g
else
CFLAGS = -O3 -DNDEBUG
endif
CFLAGS += $(EXTRA_FLAGS)
CC = gcc CC = gcc
INSTALL = install INSTALL = install
GROFF = /usr/bin/groff GROFF = /usr/bin/groff
COL = /usr/bin/col COL = /usr/bin/col
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
ifdef BITTRACE
CFLAGS += -DBITTRACE=$(BITTRACE)
endif
ANIM_UTIL_OBJS = \ ANIM_UTIL_OBJS = \
examples/anim_util.o \ examples/anim_util.o \
SHARPYUV_OBJS = \
sharpyuv/sharpyuv.o \
sharpyuv/sharpyuv_cpu.o \
sharpyuv/sharpyuv_csp.o \
sharpyuv/sharpyuv_dsp.o \
sharpyuv/sharpyuv_gamma.o \
sharpyuv/sharpyuv_neon.o \
sharpyuv/sharpyuv_sse2.o \
DEC_OBJS = \ DEC_OBJS = \
src/dec/alpha_dec.o \ src/dec/alpha_dec.o \
src/dec/buffer_dec.o \ src/dec/buffer_dec.o \
@ -176,7 +153,6 @@ 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 \
@ -188,21 +164,21 @@ DSP_DEC_OBJS = \
src/dsp/upsampling_msa.o \ src/dsp/upsampling_msa.o \
src/dsp/upsampling_neon.o \ src/dsp/upsampling_neon.o \
src/dsp/upsampling_sse2.o \ src/dsp/upsampling_sse2.o \
src/dsp/upsampling_sse41.o \
src/dsp/yuv.o \ src/dsp/yuv.o \
src/dsp/yuv_mips32.o \ src/dsp/yuv_mips32.o \
src/dsp/yuv_mips_dsp_r2.o \ src/dsp/yuv_mips_dsp_r2.o \
src/dsp/yuv_neon.o \
src/dsp/yuv_sse2.o \ src/dsp/yuv_sse2.o \
src/dsp/yuv_sse41.o \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
src/dsp/argb.o \
src/dsp/argb_mips_dsp_r2.o \
src/dsp/argb_sse2.o \
src/dsp/cost.o \ src/dsp/cost.o \
src/dsp/cost_mips32.o \ src/dsp/cost_mips32.o \
src/dsp/cost_mips_dsp_r2.o \ src/dsp/cost_mips_dsp_r2.o \
src/dsp/cost_neon.o \
src/dsp/cost_sse2.o \ src/dsp/cost_sse2.o \
src/dsp/enc.o \ src/dsp/enc.o \
src/dsp/enc_avx2.o \
src/dsp/enc_mips32.o \ src/dsp/enc_mips32.o \
src/dsp/enc_mips_dsp_r2.o \ src/dsp/enc_mips_dsp_r2.o \
src/dsp/enc_msa.o \ src/dsp/enc_msa.o \
@ -216,16 +192,14 @@ DSP_ENC_OBJS = \
src/dsp/lossless_enc_neon.o \ src/dsp/lossless_enc_neon.o \
src/dsp/lossless_enc_sse2.o \ src/dsp/lossless_enc_sse2.o \
src/dsp/lossless_enc_sse41.o \ src/dsp/lossless_enc_sse41.o \
src/dsp/ssim.o \
src/dsp/ssim_sse2.o \
ENC_OBJS = \ ENC_OBJS = \
src/enc/alpha_enc.o \ src/enc/alpha_enc.o \
src/enc/analysis_enc.o \ src/enc/analysis_enc.o \
src/enc/backward_references_cost_enc.o \
src/enc/backward_references_enc.o \ src/enc/backward_references_enc.o \
src/enc/config_enc.o \ src/enc/config_enc.o \
src/enc/cost_enc.o \ src/enc/cost_enc.o \
src/enc/delta_palettization_enc.o \
src/enc/filter_enc.o \ src/enc/filter_enc.o \
src/enc/frame_enc.o \ src/enc/frame_enc.o \
src/enc/histogram_enc.o \ src/enc/histogram_enc.o \
@ -249,7 +223,6 @@ EX_FORMAT_DEC_OBJS = \
imageio/jpegdec.o \ imageio/jpegdec.o \
imageio/metadata.o \ imageio/metadata.o \
imageio/pngdec.o \ imageio/pngdec.o \
imageio/pnmdec.o \
imageio/tiffdec.o \ imageio/tiffdec.o \
imageio/webpdec.o \ imageio/webpdec.o \
@ -292,12 +265,11 @@ 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) \ LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
$(DSP_ENC_OBJS) $(UTILS_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)
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
HDRS_INSTALLED = \ HDRS_INSTALLED = \
src/webp/decode.h \ src/webp/decode.h \
@ -307,11 +279,6 @@ HDRS_INSTALLED = \
src/webp/mux_types.h \ src/webp/mux_types.h \
src/webp/types.h \ src/webp/types.h \
SHARPYUV_HDRS_INSTALLED = \
sharpyuv/sharpyuv.h \
sharpyuv/sharpyuv_cpu.h \
sharpyuv/sharpyuv_csp.h \
HDRS = \ HDRS = \
src/dec/alphai_dec.h \ src/dec/alphai_dec.h \
src/dec/common_dec.h \ src/dec/common_dec.h \
@ -320,7 +287,6 @@ 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 \
@ -330,6 +296,7 @@ HDRS = \
src/dsp/yuv.h \ src/dsp/yuv.h \
src/enc/backward_references_enc.h \ src/enc/backward_references_enc.h \
src/enc/cost_enc.h \ src/enc/cost_enc.h \
src/enc/delta_palettization_enc.h \
src/enc/histogram_enc.h \ src/enc/histogram_enc.h \
src/enc/vp8i_enc.h \ src/enc/vp8i_enc.h \
src/enc/vp8li_enc.h \ src/enc/vp8li_enc.h \
@ -351,7 +318,6 @@ HDRS = \
src/utils/utils.h \ src/utils/utils.h \
src/webp/format_constants.h \ src/webp/format_constants.h \
$(HDRS_INSTALLED) \ $(HDRS_INSTALLED) \
$(SHARPYUV_HDRS_INSTALLED) \
OUT_LIBS = examples/libexample_util.a OUT_LIBS = examples/libexample_util.a
OUT_LIBS += imageio/libimageio_util.a OUT_LIBS += imageio/libimageio_util.a
@ -359,13 +325,11 @@ OUT_LIBS += imageio/libimagedec.a
OUT_LIBS += imageio/libimageenc.a OUT_LIBS += imageio/libimageenc.a
OUT_LIBS += src/libwebpdecoder.a OUT_LIBS += src/libwebpdecoder.a
OUT_LIBS += src/libwebp.a OUT_LIBS += src/libwebp.a
OUT_LIBS += sharpyuv/libsharpyuv.a
EXTRA_LIB = extras/libwebpextras.a EXTRA_LIB = extras/libwebpextras.a
OUT_EXAMPLES = examples/cwebp examples/dwebp OUT_EXAMPLES = examples/cwebp examples/dwebp
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \ EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
examples/anim_diff examples/anim_dump \ examples/anim_diff examples/img2webp
examples/img2webp examples/webpinfo OTHER_EXAMPLES = extras/get_disto extras/webp_quality
OTHER_EXAMPLES = extras/get_disto extras/webp_quality extras/vwebp_sdl
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES) OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
ifeq ($(MAKECMDGOALS),clean) ifeq ($(MAKECMDGOALS),clean)
@ -392,7 +356,7 @@ src/utils/bit_reader_utils.o: src/utils/endian_inl_utils.h
src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h
%.o: %.c $(HDRS) %.o: %.c $(HDRS)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
examples/libanim_util.a: $(ANIM_UTIL_OBJS) examples/libanim_util.a: $(ANIM_UTIL_OBJS)
examples/libexample_util.a: $(EX_UTIL_OBJS) examples/libexample_util.a: $(EX_UTIL_OBJS)
@ -405,92 +369,56 @@ src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
src/libwebp.a: $(LIBWEBP_OBJS) src/libwebp.a: $(LIBWEBP_OBJS)
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS) src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS) src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
sharpyuv/libsharpyuv.a: $(LIBSHARPYUV_OBJS)
%.a: %.a:
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS) examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
examples/cwebp: examples/cwebp.o examples/cwebp: examples/cwebp.o
examples/dwebp: examples/dwebp.o examples/dwebp: examples/dwebp.o
examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS) examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
examples/vwebp: examples/vwebp.o examples/vwebp: examples/vwebp.o
examples/webpmux: examples/webpmux.o examples/webpmux: examples/webpmux.o
examples/img2webp: examples/img2webp.o examples/img2webp: examples/img2webp.o
examples/webpinfo: examples/webpinfo.o
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
examples/anim_diff: sharpyuv/libsharpyuv.a examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS)
examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS)
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/anim_dump: examples/libanim_util.a examples/libgifdec.a
examples/anim_dump: src/demux/libwebpdemux.a
examples/anim_dump: examples/libexample_util.a
examples/anim_dump: imageio/libimageio_util.a
examples/anim_dump: imageio/libimageenc.a
examples/anim_dump: src/libwebp.a
examples/anim_dump: sharpyuv/libsharpyuv.a
examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
examples/cwebp: examples/libexample_util.a examples/cwebp: examples/libexample_util.a
examples/cwebp: imageio/libimagedec.a examples/cwebp: imageio/libimagedec.a
examples/cwebp: src/demux/libwebpdemux.a
examples/cwebp: imageio/libimageio_util.a examples/cwebp: imageio/libimageio_util.a
examples/cwebp: src/libwebp.a examples/cwebp: src/libwebp.a
examples/cwebp: sharpyuv/libsharpyuv.a examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
examples/cwebp: override EXTRA_LIBS += $(CWEBP_LIBS)
examples/dwebp: examples/libexample_util.a examples/dwebp: examples/libexample_util.a
examples/dwebp: imageio/libimagedec.a examples/dwebp: imageio/libimagedec.a
examples/dwebp: src/demux/libwebpdemux.a
examples/dwebp: imageio/libimageenc.a examples/dwebp: imageio/libimageenc.a
examples/dwebp: imageio/libimageio_util.a examples/dwebp: imageio/libimageio_util.a
examples/dwebp: src/libwebp.a examples/dwebp: src/libwebp.a
examples/dwebp: sharpyuv/libsharpyuv.a examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS)
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
examples/gif2webp: sharpyuv/libsharpyuv.a examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS)
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
examples/vwebp: imageio/libimageio_util.a src/libwebp.a examples/vwebp: imageio/libimageio_util.a src/libwebp.a
examples/vwebp: sharpyuv/libsharpyuv.a examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: override EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a
examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/img2webp: imageio/libimagedec.a examples/img2webp: imageio/libimagedec.a
examples/img2webp: src/demux/libwebpdemux.a examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
examples/img2webp: src/mux/libwebpmux.a examples/img2webp: EXTRA_LIBS += $(CWEBP_LIBS)
examples/img2webp: src/libwebp.a
examples/img2webp: sharpyuv/libsharpyuv.a
examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS)
examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
examples/webpinfo: src/libwebpdecoder.a
extras/get_disto: extras/get_disto.o extras/get_disto: extras/get_disto.o
extras/get_disto: imageio/libimagedec.a extras/get_disto: imageio/libimagedec.a imageio/libimageio_util.a src/libwebp.a
extras/get_disto: src/demux/libwebpdemux.a extras/get_disto: EXTRA_LIBS += $(CWEBP_LIBS)
extras/get_disto: imageio/libimageio_util.a
extras/get_disto: src/libwebp.a
extras/get_disto: sharpyuv/libsharpyuv.a
extras/get_disto: override EXTRA_LIBS += $(CWEBP_LIBS)
extras/webp_quality: extras/webp_quality.o extras/webp_quality: extras/webp_quality.o
extras/webp_quality: imageio/libimageio_util.a extras/webp_quality: imageio/libimageio_util.a
extras/webp_quality: $(EXTRA_LIB) src/libwebp.a extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
extras/webp_quality: sharpyuv/libsharpyuv.a
extras/vwebp_sdl: extras/vwebp_sdl.o
extras/vwebp_sdl: extras/webp_to_sdl.o
extras/vwebp_sdl: imageio/libimageio_util.a
extras/vwebp_sdl: src/libwebp.a
extras/vwebp_sdl: sharpyuv/libsharpyuv.a
extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS)
extras/vwebp_sdl: override EXTRA_LIBS += $(SDL_LIBS)
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES): $(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)
@ -499,20 +427,17 @@ dist: DESTDIR := dist
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES) dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
dist: all dist: all
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \ $(INSTALL) -m755 -d $(DESTDIR)/include/webp \
$(DESTDIR)/include/webp/sharpyuv \
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib $(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin $(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp $(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
$(INSTALL) -m644 $(SHARPYUV_HDRS_INSTALLED) $(DESTDIR)/include/webp/sharpyuv
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib $(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib $(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib $(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
$(INSTALL) -m644 sharpyuv/libsharpyuv.a $(DESTDIR)/lib
umask 022; \ umask 022; \
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \ for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \
man/img2webp.1 man/webpinfo.1; do \ man/img2webp.1; do \
basenam=$$(basename $$m .1); \ basenam=$$(basename $$m .1); \
$(GROFF) -t -e -man -T ascii $$m \ $(GROFF) -t -e -man -T utf8 $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
$(GROFF) -t -e -man -T html $$m \ $(GROFF) -t -e -man -T html $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \
@ -523,7 +448,6 @@ 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/*~ \

View File

@ -1,17 +1,11 @@
man_MANS = cwebp.1 dwebp.1 man_MANS = cwebp.1 dwebp.1
if BUILD_MUX if WANT_MUX
man_MANS += webpmux.1 man_MANS += webpmux.1
endif endif
if BUILD_GIF2WEBP if BUILD_GIF2WEBP
man_MANS += gif2webp.1 man_MANS += gif2webp.1
endif endif
if BUILD_IMG2WEBP
man_MANS += img2webp.1
endif
if BUILD_VWEBP if BUILD_VWEBP
man_MANS += vwebp.1 man_MANS += vwebp.1
endif endif
if BUILD_WEBPINFO
man_MANS += webpinfo.1
endif
EXTRA_DIST = $(man_MANS) EXTRA_DIST = $(man_MANS)

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "March 17, 2022" .TH CWEBP 1 "January 20, 2017"
.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
@ -13,7 +13,6 @@ command.
.PP .PP
\fBcwebp\fP compresses an image using the WebP format. \fBcwebp\fP compresses an image using the WebP format.
Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples. Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples.
Note: Animated PNG and WebP files are not supported.
.SH OPTIONS .SH OPTIONS
The basic options are: The basic options are:
.TP .TP
@ -42,12 +41,10 @@ the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the
\-exact option is used. \-exact option is used.
.TP .TP
.BI \-near_lossless " int .BI \-near_lossless " int
Specify the level of near\-lossless image preprocessing. This option adjusts Use near\-lossless image preprocessing. This option adjusts pixel values
pixel values to help compressibility, but has minimal impact on the visual to help compressibility, but has minimal impact on the visual quality.
quality. It triggers lossless compression mode automatically. The range is 0 It triggers lossless compression mode automatically.
(maximum preprocessing) to 100 (no preprocessing, the default). The typical Range is 0 (maximum preprocessing) to 100 (no preprocessing, the default).
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
better results.
.TP .TP
.BI \-q " float .BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default Specify the compression factor for RGB channels between 0 and 100. The default
@ -90,20 +87,19 @@ 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. This option is only effective
when using lossy compression on a source with a transparency channel.
.TP .TP
.B \-low_memory .B \-low_memory
Reduce memory usage of lossy encoding by saving four times the compressed Reduce memory usage of lossy encoding by saving four times the compressed
@ -137,13 +133,6 @@ options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
specified, a default value of '6' passes will be used. specified, a default value of '6' passes will be used.
.TP .TP
.BI \-qrange " int int
Specifies the permissible interval for the quality factor. This is particularly
useful when using multi-pass (\fB\-size\fP or \fB\-psnr\fP options).
Default is 0 100.
If the quality factor is outside this range, it will be clamped.
If the minimum value must be less or equal to the maximum one.
.TP
.B \-af .B \-af
Turns auto\-filter on. This algorithm will spend additional time optimizing Turns auto\-filter on. This algorithm will spend additional time optimizing
the filtering strength to reach a well\-balanced quality. the filtering strength to reach a well\-balanced quality.
@ -224,7 +213,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 https://en.wikipedia.org/wiki/SSIM for additional details). metric, see http://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
@ -300,7 +289,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://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
@ -324,5 +313,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 https://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH DWEBP 1 "November 17, 2021" .TH DWEBP 1 "June 23, 2016"
.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
@ -12,7 +12,6 @@ This manual page documents the
command. command.
.PP .PP
\fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images. \fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images.
Note: Animated WebP files are not supported.
.SH OPTIONS .SH OPTIONS
The basic options are: The basic options are:
.TP .TP
@ -113,7 +112,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://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 +137,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 https://developers.google.com/speed/webp/ for additional Please refer to http://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

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH GIF2WEBP 1 "November 17, 2021" .TH GIF2WEBP 1 "January 25, 2017"
.SH NAME .SH NAME
gif2webp \- Convert a GIF image to WebP gif2webp \- Convert a GIF image to WebP
.SH SYNOPSIS .SH SYNOPSIS
@ -20,12 +20,6 @@ Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will
perform conversion but only report statistics. perform conversion but only report statistics.
Using "\-" as output name will direct output to 'stdout'. Using "\-" as output name will direct output to 'stdout'.
.TP .TP
.BI \-\- " string
Explicitly specify the input file. This option is useful if the input
file starts with an '\-' for instance. This option must appear \fBlast\fP.
Any other options afterward will be ignored. If the input file is "\-",
the data will be read from \fIstdin\fP instead of a file.
.TP
.B \-h, \-help .B \-h, \-help
Usage information. Usage information.
.TP .TP
@ -62,9 +56,9 @@ larger file size and lower compression quality.
.TP .TP
.BI \-min_size .BI \-min_size
Encode image to achieve smallest size. This disables key frame insertion and Encode image to achieve smallest size. This disables key frame insertion and
picks the dispose method resulting in the smallest output for each frame. It picks the dispose method resulting in smallest output for each frame. It uses
uses lossless compression by default, but can be combined with \-q, \-m, lossless compression by default, but can be combined with \-q, \-m, \-lossy or
\-lossy or \-mixed options. \-mixed options.
.TP .TP
.BI \-kmin " int .BI \-kmin " int
.TP .TP
@ -114,11 +108,8 @@ the value the smoother the picture will appear. Typical values are usually in
the range of 20 to 50. the range of 20 to 50.
.TP .TP
.B \-mt .B \-mt
Use multi-threading for encoding, if possible. Use multi-threading for encoding, if possible. This option is only effective
.TP when using lossy compression.
.B \-loop_compatibility
If enabled, handle the loop information in a compatible fashion for Chrome
version prior to M62 (inclusive) and Firefox.
.TP .TP
.B \-v .B \-v
Print extra information. Print extra information.
@ -131,7 +122,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES .SH EXAMPLES
gif2webp picture.gif \-o picture.webp gif2webp picture.gif \-o picture.webp
@ -143,8 +134,6 @@ gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp
gif2webp \-lossy \-f 50 picture.gif \-o picture.webp gif2webp \-lossy \-f 50 picture.gif \-o picture.webp
.br .br
gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif
.br
cat picture.gif | gif2webp \-o \- \-\- \- > output.webp
.SH AUTHORS .SH AUTHORS
\fBgif2webp\fP is a part of libwebp and was written by the WebP team. \fBgif2webp\fP is a part of libwebp and was written by the WebP team.
@ -160,5 +149,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 https://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,12 +1,10 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH IMG2WEBP 1 "March 17, 2023" .TH IMG2WEBP 1 "January 23, 2017"
.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_options] [[frame_options] frame_file]... [\-o webp_file] [file_level_options] [files] [per_frame_options...]
.br
.B img2webp argument_file_name
.br .br
.SH DESCRIPTION .SH DESCRIPTION
This manual page documents the This manual page documents the
@ -15,9 +13,6 @@ command.
.PP .PP
\fBimg2webp\fP compresses a sequence of images using the animated WebP format. \fBimg2webp\fP compresses a sequence of images using the animated WebP format.
Input images can either be PNG, JPEG, TIFF or WebP. Input images can either be PNG, JPEG, TIFF or WebP.
If a single file name (not starting with the character '\-') is supplied as
the argument, the command line arguments are actually tokenized from this file.
This allows for easy scripting or using a large number of arguments.
.SH FILE-LEVEL OPTIONS .SH FILE-LEVEL OPTIONS
The file-level options are applied at the beginning of the compression process, The file-level options are applied at the beginning of the compression process,
before the input frames are read. before the input frames are read.
@ -27,7 +22,7 @@ Specify the name of the output WebP file.
.TP .TP
.BI \-min_size .BI \-min_size
Encode images to achieve smallest size. This disables key frame insertion and Encode images to achieve smallest size. This disables key frame insertion and
picks the parameters resulting in the smallest output for each frame. It uses picks the parameters resulting in smallest output for each frame. It uses
lossless compression by default, but can be combined with \-q, \-m, \-lossy or lossless compression by default, but can be combined with \-q, \-m, \-lossy or
\-mixed options. \-mixed options.
.TP .TP
@ -44,30 +39,15 @@ Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically. This global lossy or lossless compression for each frame heuristically. This global
option disables the local option \fB-lossy\fP and \fB-lossless\fP . option disables the local option \fB-lossy\fP and \fB-lossless\fP .
.TP .TP
.BI \-near_lossless " int
Specify the level of near\-lossless image preprocessing. This option adjusts
pixel values to help compressibility, but has minimal impact on the visual
quality. It triggers lossless compression mode automatically. The range is 0
(maximum preprocessing) to 100 (no preprocessing, the default). The typical
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
better results.
.TP
.B \-sharp_yuv
Use more accurate and sharper RGB->YUV conversion if needed. Note that this
process is slower than the default 'fast' RGB->YUV conversion.
.TP
.BI \-loop " int .BI \-loop " int
Specifies the number of times the animation should loop. Using '0' Specifies the number of times the animation should loop. Using '0' means
means 'loop indefinitely'. 'loop indefinitely'.
.TP .TP
.BI \-v .BI \-v
Be more verbose. Be more verbose.
.TP .TP
.B \-h, \-help .B \-h, \-help
A short usage summary. A short usage summary.
.TP
.B \-version
Print the version numbers of the relevant libraries used.
.SH PER-FRAME OPTIONS .SH PER-FRAME OPTIONS
The per-frame options are applied for the images following as arguments in the The per-frame options are applied for the images following as arguments in the
@ -98,7 +78,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://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.
@ -113,5 +93,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 https://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH VWEBP 1 "November 17, 2021" .TH VWEBP 1 "November 25, 2016"
.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
@ -38,10 +38,6 @@ It helps by smoothing gradients and avoiding banding artifacts. Default: 50.
By default, quantized transparency planes are dithered during decompression, By default, quantized transparency planes are dithered during decompression,
to smooth the gradients. This flag will prevent this dithering. to smooth the gradients. This flag will prevent this dithering.
.TP .TP
.B \-usebgcolor
Fill transparent areas with the bitstream's own background color instead of
checkerboard only. Default is white for non-animated images.
.TP
.B \-mt .B \-mt
Use multi-threading for decoding, if possible. Use multi-threading for decoding, if possible.
.TP .TP
@ -60,9 +56,6 @@ the data will be read from \fIstdin\fP instead of a file.
.B 'c' .B 'c'
Toggle use of color profile. Toggle use of color profile.
.TP .TP
.B 'b'
Toggle display of background color.
.TP
.B 'i' .B 'i'
Overlay file information. Overlay file information.
.TP .TP
@ -77,7 +70,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES .SH EXAMPLES
vwebp picture.webp vwebp picture.webp
@ -97,5 +90,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 https://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,80 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.TH WEBPINFO 1 "November 17, 2021"
.SH NAME
webpinfo \- print out the chunk level structure of WebP files
along with basic integrity checks.
.SH SYNOPSIS
.B webpinfo
.I OPTIONS
.I INPUT
.br
.B webpinfo [\-h|\-help|\-H|\-longhelp]
.br
.SH DESCRIPTION
This manual page documents the
.B webpinfo
command.
.PP
\fBwebpinfo\fP can be used to print out the chunk level structure and bitstream
header information of WebP files. It can also check if the files are of valid
WebP format.
.SH OPTIONS
.TP
.B \-version
Print the version number (as major.minor.revision) and exit.
.TP
.B \-quiet
Do not show chunk parsing information.
.TP
.B \-diag
Show parsing error diagnosis.
.TP
.B \-summary
Show chunk stats summary.
.TP
.BI \-bitstream_info
Parse bitstream header.
.TP
.B \-h, \-help
A short usage summary.
.TP
.B \-H, \-longhelp
Detailed usage instructions.
.SH INPUT
Input files in WebP format. Input files must come last, following
options (if any). There can be multiple input files.
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
https://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXAMPLES
.br
webpinfo \-h
.br
webpinfo \-diag \-summary input_file.webp
.br
webpinfo \-bitstream_info input_file_1.webp input_file_2.webp
.br
webpinfo *.webp
.SH AUTHORS
\fBwebpinfo\fP is a part of libwebp and was written by the WebP team.
.br
The latest source tree is available at
https://chromium.googlesource.com/webm/libwebp
.PP
This manual page was written by Hui Su <huisu@google.com>,
for the Debian project (and may be used by others).
.SH SEE ALSO
.BR webpmux (1)
.br
Please refer to https://developers.google.com/speed/webp/ for additional
information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "November 17, 2021" .TH WEBPMUX 1 "November 10, 2016"
.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.
@ -48,8 +48,6 @@ frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
.B webpmux [\-h|\-help] .B webpmux [\-h|\-help]
.br .br
.B webpmux \-version .B webpmux \-version
.br
.B webpmux argument_file_name
.SH DESCRIPTION .SH DESCRIPTION
This manual page documents the This manual page documents the
.B webpmux .B webpmux
@ -57,9 +55,6 @@ command.
.PP .PP
\fBwebpmux\fP can be used to create/extract from animated WebP files, as well as \fBwebpmux\fP can be used to create/extract from animated WebP files, as well as
to add/extract/strip XMP/EXIF metadata and ICC profile. to add/extract/strip XMP/EXIF metadata and ICC profile.
If a single file name (not starting with the character '\-') is supplied as
the argument, the command line arguments are actually tokenized from this file.
This allows for easy scripting or using a large number of arguments.
.SH OPTIONS .SH OPTIONS
.SS GET_OPTIONS (\-get): .SS GET_OPTIONS (\-get):
.TP .TP
@ -77,17 +72,6 @@ Get nth frame from an animated image. (n = 0 has a special meaning: last frame).
.SS SET_OPTIONS (\-set) .SS SET_OPTIONS (\-set)
.TP .TP
.BI loop " loop_count
Set loop count on an animated file.
.P
Where: 'loop_count' must be in range [0, 65535].
.TP
.BI bgcolor " A,R,G,B
Set the background color of the canvas on an animated file.
.P
where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the
Alpha, Red, Green and Blue component values respectively.
.TP
.BI icc " file.icc .BI icc " file.icc
Set ICC profile. Set ICC profile.
.P .P
@ -191,7 +175,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:
https://www.webmproject.org/code/contribute/submitting\-patches/ http://www.webmproject.org/code/contribute/submitting\-patches/
.SH EXAMPLES .SH EXAMPLES
.P .P
@ -267,5 +251,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 https://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,41 +0,0 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
lib_LTLIBRARIES = libsharpyuv.la
noinst_LTLIBRARIES =
noinst_LTLIBRARIES += libsharpyuv_sse2.la
noinst_LTLIBRARIES += libsharpyuv_neon.la
libsharpyuvinclude_HEADERS =
libsharpyuvinclude_HEADERS += sharpyuv.h
libsharpyuvinclude_HEADERS += sharpyuv_csp.h
noinst_HEADERS =
noinst_HEADERS += ../src/dsp/cpu.c
noinst_HEADERS += ../src/dsp/cpu.h
noinst_HEADERS += ../src/webp/types.h
libsharpyuv_sse2_la_SOURCES =
libsharpyuv_sse2_la_SOURCES += sharpyuv_sse2.c
libsharpyuv_sse2_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS)
libsharpyuv_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS)
libsharpyuv_neon_la_SOURCES =
libsharpyuv_neon_la_SOURCES += sharpyuv_neon.c
libsharpyuv_neon_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS)
libsharpyuv_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
libsharpyuv_la_SOURCES =
libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h
libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
libsharpyuv_la_LDFLAGS = -no-undefined -version-info 0:1:0 -lm
libsharpyuv_la_LIBADD =
libsharpyuv_la_LIBADD += libsharpyuv_sse2.la
libsharpyuv_la_LIBADD += libsharpyuv_neon.la
libsharpyuvincludedir = $(includedir)/webp/sharpyuv
pkgconfig_DATA = libsharpyuv.pc

View File

@ -1,11 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/webp
Name: libsharpyuv
Description: Library for sharp RGB to YUV conversion
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -l@webp_libname_prefix@sharpyuv
Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@

View File

@ -1,41 +0,0 @@
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,2,1
PRODUCTVERSION 0,0,2,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libsharpyuv DLL"
VALUE "FileVersion", "0.2.1"
VALUE "InternalName", "libsharpyuv.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "libsharpyuv.dll"
VALUE "ProductName", "SharpYuv Library"
VALUE "ProductVersion", "0.2.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources

View File

@ -1,527 +0,0 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Sharp RGB to YUV conversion.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "sharpyuv/sharpyuv.h"
#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "src/webp/types.h"
#include "sharpyuv/sharpyuv_cpu.h"
#include "sharpyuv/sharpyuv_dsp.h"
#include "sharpyuv/sharpyuv_gamma.h"
//------------------------------------------------------------------------------
int SharpYuvGetVersion(void) {
return SHARPYUV_VERSION;
}
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
static const int kNumIterations = 4;
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
static const int kYuvHalf = 1 << (YUV_FIX - 1);
// Max bit depth so that intermediate calculations fit in 16 bits.
static const int kMaxBitDepth = 14;
// Returns the precision shift to use based on the input rgb_bit_depth.
static int GetPrecisionShift(int rgb_bit_depth) {
// Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove
// bits if needed.
return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2
: (kMaxBitDepth - rgb_bit_depth);
}
typedef int16_t fixed_t; // signed type with extra precision for UV
typedef uint16_t fixed_y_t; // unsigned type with extra precision for W
//------------------------------------------------------------------------------
static uint8_t clip_8b(fixed_t v) {
return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
}
static uint16_t clip(fixed_t v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
}
static fixed_y_t clip_bit_depth(int y, int bit_depth) {
const int max = (1 << bit_depth) - 1;
return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max;
}
//------------------------------------------------------------------------------
static int RGBToGray(int64_t r, int64_t g, int64_t b) {
const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf;
return (int)(luma >> YUV_FIX);
}
static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
int rgb_bit_depth) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
int rgb_bit_depth) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
int i;
for (i = 0; i < w; ++i) {
const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
const uint32_t Y = RGBToGray(R, G, B);
dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
}
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
fixed_t* dst, int uv_w, int rgb_bit_depth) {
int i;
for (i = 0; i < uv_w; ++i) {
const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
src2[0 * uv_w + 1], rgb_bit_depth);
const int g =
ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
src2[2 * uv_w + 1], rgb_bit_depth);
const int b =
ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
src2[4 * uv_w + 1], rgb_bit_depth);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
dst[2 * uv_w] = (fixed_t)(b - W);
dst += 1;
src1 += 2;
src2 += 2;
}
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
int i;
assert(w > 0);
for (i = 0; i < w; ++i) {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
}
}
//------------------------------------------------------------------------------
static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) {
const int v0 = (A * 3 + B + 2) >> 2;
return clip_bit_depth(v0 + W0, bit_depth);
}
//------------------------------------------------------------------------------
static WEBP_INLINE int Shift(int v, int shift) {
return (shift >= 0) ? (v << shift) : (v >> -shift);
}
static void ImportOneRow(const uint8_t* const r_ptr,
const uint8_t* const g_ptr,
const uint8_t* const b_ptr,
int rgb_step,
int rgb_bit_depth,
int pic_width,
fixed_y_t* const dst) {
// Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
int i;
const int w = (pic_width + 1) & ~1;
for (i = 0; i < pic_width; ++i) {
const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) {
dst[i + 0 * w] = Shift(r_ptr[off], shift);
dst[i + 1 * w] = Shift(g_ptr[off], shift);
dst[i + 2 * w] = Shift(b_ptr[off], shift);
} else {
dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift);
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
}
}
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
}
}
static void InterpolateTwoRows(const fixed_y_t* const best_y,
const fixed_t* prev_uv,
const fixed_t* cur_uv,
const fixed_t* next_uv,
int w,
fixed_y_t* out1,
fixed_y_t* out2,
int rgb_bit_depth) {
const int uv_w = w >> 1;
const int len = (w - 1) >> 1; // length to filter
int k = 3;
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
while (k-- > 0) { // process each R/G/B segments in turn
// special boundary case for i==0
out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth);
out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth);
SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1,
bit_depth);
SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1,
bit_depth);
// special boundary case for i == w - 1 when w is even
if (!(w & 1)) {
out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
best_y[w - 1 + 0], bit_depth);
out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
best_y[w - 1 + w], bit_depth);
}
out1 += w;
out2 += w;
prev_uv += uv_w;
cur_uv += uv_w;
next_uv += uv_w;
}
}
static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b,
const int coeffs[4], int sfix) {
const int srounder = 1 << (YUV_FIX + sfix - 1);
const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b +
coeffs[3] + srounder;
return (luma >> (YUV_FIX + sfix));
}
static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
uint8_t* y_ptr, int y_stride, uint8_t* u_ptr,
int u_stride, uint8_t* v_ptr, int v_stride,
int rgb_bit_depth,
int yuv_bit_depth, int width, int height,
const SharpYuvConversionMatrix* yuv_matrix) {
int i, j;
const fixed_t* const best_uv_base = best_uv;
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1;
for (best_uv = best_uv_base, j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
const int g = best_uv[off + 1 * uv_w] + W;
const int b = best_uv[off + 2 * uv_w] + W;
const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix);
if (yuv_bit_depth <= 8) {
y_ptr[i] = clip_8b(y);
} else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
}
}
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride;
}
for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
for (i = 0; i < uv_w; ++i) {
const int off = i;
// Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix.
const int r = best_uv[off + 0 * uv_w];
const int g = best_uv[off + 1 * uv_w];
const int b = best_uv[off + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) {
u_ptr[i] = clip_8b(u);
v_ptr[i] = clip_8b(v);
} else {
((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
}
}
best_uv += 3 * uv_w;
u_ptr += u_stride;
v_ptr += v_stride;
}
return 1;
}
//------------------------------------------------------------------------------
// Main function
static void* SafeMalloc(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * (uint64_t)size;
if (total_size != (size_t)total_size) return NULL;
return malloc((size_t)total_size);
}
#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, uint8_t* y_ptr, int y_stride,
uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height,
const SharpYuvConversionMatrix* yuv_matrix) {
// we expand the right/bottom border if needed
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
uint64_t prev_diff_y_sum = ~0;
int j, iter;
// TODO(skal): allocate one big memory chunk. But for now, it's easier
// for valgrind debugging to have several chunks.
fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
fixed_y_t* best_y = best_y_base;
fixed_y_t* target_y = target_y_base;
fixed_t* best_uv = best_uv_base;
fixed_t* target_uv = target_uv_base;
const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
int ok;
assert(w > 0);
assert(h > 0);
if (best_y_base == NULL || best_uv_base == NULL ||
target_y_base == NULL || target_uv_base == NULL ||
best_rgb_y == NULL || best_rgb_uv == NULL ||
tmp_buffer == NULL) {
ok = 0;
goto End;
}
// Import RGB samples to W/RGB representation.
for (j = 0; j < height; j += 2) {
const int is_last_row = (j == height - 1);
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
// prepare two rows of input
ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width,
src1);
if (!is_last_row) {
ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
rgb_step, rgb_bit_depth, width, src2);
} else {
memcpy(src2, src1, 3 * w * sizeof(*src2));
}
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
UpdateW(src1, target_y, w, rgb_bit_depth);
UpdateW(src2, target_y + w, w, rgb_bit_depth);
UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
r_ptr += 2 * rgb_stride;
g_ptr += 2 * rgb_stride;
b_ptr += 2 * rgb_stride;
}
// Iterate and resolve clipping conflicts.
for (iter = 0; iter < kNumIterations; ++iter) {
const fixed_t* cur_uv = best_uv_base;
const fixed_t* prev_uv = best_uv_base;
uint64_t diff_y_sum = 0;
best_y = best_y_base;
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
for (j = 0; j < h; j += 2) {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w,
src1, src2, rgb_bit_depth);
prev_uv = cur_uv;
cur_uv = next_uv;
}
UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
// update two rows of Y and one row of RGB
diff_y_sum +=
SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
}
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
if (diff_y_sum > prev_diff_y_sum) break;
}
prev_diff_y_sum = diff_y_sum;
}
// final reconstruction
ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr,
u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth,
width, height, yuv_matrix);
End:
free(best_y_base);
free(best_uv_base);
free(target_y_base);
free(target_uv_base);
free(best_rgb_y);
free(best_rgb_uv);
free(tmp_buffer);
return ok;
}
#undef SAFE_ALLOC
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
#include <pthread.h> // NOLINT
#define LOCK_ACCESS \
static pthread_mutex_t sharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; \
if (pthread_mutex_lock(&sharpyuv_lock)) return
#define UNLOCK_ACCESS_AND_RETURN \
do { \
(void)pthread_mutex_unlock(&sharpyuv_lock); \
return; \
} while (0)
#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
#define LOCK_ACCESS do {} while (0)
#define UNLOCK_ACCESS_AND_RETURN return
#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
// Hidden exported init function.
// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed,
// users can declare it as extern and call it with an alternate VP8CPUInfo
// function.
extern VP8CPUInfo SharpYuvGetCPUInfo;
SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func);
void SharpYuvInit(VP8CPUInfo cpu_info_func) {
static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
(VP8CPUInfo)&sharpyuv_last_cpuinfo_used;
LOCK_ACCESS;
// Only update SharpYuvGetCPUInfo when called from external code to avoid a
// race on reading the value in SharpYuvConvert().
if (cpu_info_func != (VP8CPUInfo)&SharpYuvGetCPUInfo) {
SharpYuvGetCPUInfo = cpu_info_func;
}
if (sharpyuv_last_cpuinfo_used == SharpYuvGetCPUInfo) {
UNLOCK_ACCESS_AND_RETURN;
}
SharpYuvInitDsp();
SharpYuvInitGammaTables();
sharpyuv_last_cpuinfo_used = SharpYuvGetCPUInfo;
UNLOCK_ACCESS_AND_RETURN;
}
int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, void* y_ptr, int y_stride,
void* u_ptr, int u_stride, void* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix) {
SharpYuvConversionMatrix scaled_matrix;
const int rgb_max = (1 << rgb_bit_depth) - 1;
const int rgb_round = 1 << (rgb_bit_depth - 1);
const int yuv_max = (1 << yuv_bit_depth) - 1;
const int sfix = GetPrecisionShift(rgb_bit_depth);
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL ||
u_ptr == NULL || v_ptr == NULL) {
return 0;
}
if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 &&
rgb_bit_depth != 16) {
return 0;
}
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0;
}
if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
// Step/stride should be even for uint16_t buffers.
return 0;
}
if (yuv_bit_depth > 8 &&
(y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) {
// Stride should be even for uint16_t buffers.
return 0;
}
// The address of the function pointer is used to avoid a read race.
SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo);
// Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the
// rgb->yuv conversion matrix.
if (rgb_bit_depth == yuv_bit_depth) {
memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix));
} else {
int i;
for (i = 0; i < 3; ++i) {
scaled_matrix.rgb_to_y[i] =
(yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max;
scaled_matrix.rgb_to_u[i] =
(yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max;
scaled_matrix.rgb_to_v[i] =
(yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max;
}
}
// Also incorporate precision change scaling.
scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix);
scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix);
scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix);
return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
v_ptr, v_stride, yuv_bit_depth, width, height,
&scaled_matrix);
}
//------------------------------------------------------------------------------

Some files were not shown because too many files have changed in this diff Show More