mirror of
https://github.com/webmproject/libwebp.git
synced 2025-12-24 22:19:11 +01:00
Compare commits
46 Commits
v1.6.0-rc1
...
portable-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d7614fddf | ||
|
|
88692490a5 | ||
|
|
0af22e17d6 | ||
|
|
08af967025 | ||
|
|
a26996116f | ||
|
|
5505a5b107 | ||
|
|
8ed24a564c | ||
|
|
0e8c3004be | ||
|
|
6fcc3a720d | ||
|
|
2371724d79 | ||
|
|
9d1e151bf5 | ||
|
|
a1ab868427 | ||
|
|
0b8ecc8cfa | ||
|
|
c646241391 | ||
|
|
cfaebe3e95 | ||
|
|
c0eb3ff7d4 | ||
|
|
415b98ffad | ||
|
|
09bcd9a397 | ||
|
|
e83df9d208 | ||
|
|
3387fb6fa6 | ||
|
|
599bddb658 | ||
|
|
28fbe808b9 | ||
|
|
c396e6701b | ||
|
|
96ef09107c | ||
|
|
bc01db116f | ||
|
|
d2adc08095 | ||
|
|
d6f90a3d83 | ||
|
|
cd01fc3944 | ||
|
|
9a1a3aa827 | ||
|
|
9eceff25c0 | ||
|
|
fe6184d706 | ||
|
|
cb6c3a2a36 | ||
|
|
ec666c7526 | ||
|
|
bafa90ccd8 | ||
|
|
e6e3ec335c | ||
|
|
168a3a9e28 | ||
|
|
ad4ca27449 | ||
|
|
3a5528713b | ||
|
|
b4cefba731 | ||
|
|
440945ca57 | ||
|
|
a37a7b00d5 | ||
|
|
a604ab5600 | ||
|
|
b005d916f8 | ||
|
|
586eda373d | ||
|
|
4026e34e3f | ||
|
|
4b21971337 |
240
.cmake-format.py
240
.cmake-format.py
@@ -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
1
.gitattributes
vendored
@@ -1,6 +1,5 @@
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.mailmap export-ignore
|
||||
*.bat text eol=crlf
|
||||
*.pdf -text -diff
|
||||
*.ppm -text -diff
|
||||
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,11 +1,8 @@
|
||||
*.l[ao]
|
||||
*.[ao]
|
||||
*.pc
|
||||
.DS_Store
|
||||
.deps
|
||||
.idea
|
||||
.libs
|
||||
.vscode
|
||||
/aclocal.m4
|
||||
/ar-lib
|
||||
/autom4te.cache
|
||||
@@ -23,11 +20,9 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
examples/anim_diff
|
||||
examples/anim_dump
|
||||
examples/[cdv]webp
|
||||
examples/gif2webp
|
||||
examples/img2webp
|
||||
examples/webpinfo
|
||||
examples/webpmux
|
||||
src/webp/config.h*
|
||||
src/webp/stamp-h1
|
||||
@@ -36,22 +31,11 @@ src/webp/stamp-h1
|
||||
*.idb
|
||||
*.pdb
|
||||
/iosbuild
|
||||
/xcframeworkbuild
|
||||
/WebP*.*framework
|
||||
/WebP.framework
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
.gradle
|
||||
/build
|
||||
extras/get_disto
|
||||
extras/vwebp_sdl
|
||||
extras/webp_quality
|
||||
tests/fuzzer/advanced_api_fuzzer
|
||||
tests/fuzzer/animation_api_fuzzer
|
||||
tests/fuzzer/animdecoder_fuzzer
|
||||
tests/fuzzer/animencoder_fuzzer
|
||||
tests/fuzzer/demux_api_fuzzer
|
||||
tests/fuzzer/enc_dec_fuzzer
|
||||
tests/fuzzer/huffman_fuzzer
|
||||
tests/fuzzer/mux_demux_api_fuzzer
|
||||
tests/fuzzer/simple_api_fuzzer
|
||||
|
||||
12
.mailmap
12
.mailmap
@@ -1,20 +1,12 @@
|
||||
Johann Koenig <johann.koenig@duck.com>
|
||||
Johann Koenig <johann.koenig@duck.com> <johannkoenig@google.com>
|
||||
<johann.koenig@duck.com> <johannkoenig@google.com>
|
||||
Mikołaj Zalewski <mikolajz@google.com>
|
||||
Pascal Massimino <pascal.massimino@gmail.com>
|
||||
Pascal Massimino <pascal.massimino@gmail.com> <skal@google.com>
|
||||
<pascal.massimino@gmail.com> <skal@google.com>
|
||||
Vikas Arora <vikasa@google.com>
|
||||
<vikasa@google.com> <vikasa@gmail.com>
|
||||
<vikasa@google.com> <vikaas.arora@gmail.com>
|
||||
<slobodan.prijic@imgtec.com> <Slobodan.Prijic@imgtec.com>
|
||||
<vrabaud@google.com> <vincent.rabaud@gmail.com>
|
||||
Vincent Rabaud <vrabaud@google.com>
|
||||
Tamar Levy <tamar.levy@intel.com>
|
||||
<qrczak@google.com> <qrczak>
|
||||
Hui Su <huisu@google.com>
|
||||
James Zern <jzern@google.com>
|
||||
Roberto Alanis <alanisbaez@google.com>
|
||||
Brian Ledger <brianpl@google.com>
|
||||
Maryla Ustarroz-Calonge <maryla@google.com>
|
||||
Yannis Guyon <yguyon@google.com>
|
||||
Henner Zeller <hzeller@google.com> <h.zeller@acm.org>
|
||||
|
||||
441
.pylintrc
441
.pylintrc
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
[style]
|
||||
based_on_style = yapf
|
||||
36
AUTHORS
36
AUTHORS
@@ -1,56 +1,28 @@
|
||||
Contributors:
|
||||
- Aidan O'Loan (aidanol at gmail dot com)
|
||||
- Alan Browning (browning at google dot com)
|
||||
- Alexandru Ardelean (ardeleanalex at gmail dot com)
|
||||
- Anuraag Agrawal (anuraaga at gmail dot com)
|
||||
- Arthur Eubanks (aeubanks at google dot com)
|
||||
- Brian Ledger (brianpl at google dot com)
|
||||
- Charles Munger (clm at google dot com)
|
||||
- Cheng Yi (cyi at google dot com)
|
||||
- Christian Duvivier (cduvivier at google dot com)
|
||||
- Christopher Degawa (ccom at randomderp dot com)
|
||||
- Clement Courbet (courbet at google dot com)
|
||||
- devtools-clrobot at google dot com (devtools-clrobot@google dot com)
|
||||
- Djordje Pesut (djordje dot pesut at imgtec dot com)
|
||||
- Frank (1433351828 at qq dot com)
|
||||
- Frank Barchard (fbarchard at google dot com)
|
||||
- Henner Zeller (hzeller 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)
|
||||
- Istvan Stefan (Istvan dot Stefan at arm dot com)
|
||||
- James Zern (jzern at google dot com)
|
||||
- Jan Engelhardt (jengelh at medozas dot de)
|
||||
- Jehan (jehan at girinstud dot io)
|
||||
- Jeremy Maitin-Shepard (jbms at google dot com)
|
||||
- Johann Koenig (johann dot koenig at duck dot com)
|
||||
- Jonathan Grant (jgrantinfotech at gmail dot com)
|
||||
- Jonliu1993 (13720414433 at 163 dot com)
|
||||
- Johann (johann dot koenig at duck dot com)
|
||||
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
|
||||
- Jyrki Alakuijala (jyrki at google dot com)
|
||||
- Konstantin Ivlev (tomskside at gmail dot com)
|
||||
- Lode Vandevenne (lode at google dot com)
|
||||
- Lou Quillio (louquillio at google dot com)
|
||||
- Mans Rullgard (mans at mansr dot com)
|
||||
- Marcin Kowalczyk (qrczak at google dot com)
|
||||
- Martin Olsson (mnemo at minimum dot se)
|
||||
- Maryla Ustarroz-Calonge (maryla at google dot com)
|
||||
- Masahiro Hanada (hanada at atmark-techno dot com)
|
||||
- Mikołaj Zalewski (mikolajz at google dot com)
|
||||
- Mislav Bradac (mislavm at google dot com)
|
||||
- natewood (natewood at fb dot com)
|
||||
- Nico Weber (thakis 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)
|
||||
- Ozkan Sezer (sezeroz at gmail dot com)
|
||||
- Parag Salasakar (img dot mips1 at gmail dot com)
|
||||
- Pascal Massimino (pascal dot massimino at gmail dot com)
|
||||
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
|
||||
- Pierre Joye (pierre dot php at gmail dot com)
|
||||
- Roberto Alanis (alanisbaez at google dot com)
|
||||
- Sam Clegg (sbc at chromium dot org)
|
||||
- Scott Hancher (seh at google dot com)
|
||||
- Scott LaVarnway (slavarnway at google dot com)
|
||||
@@ -59,14 +31,8 @@ Contributors:
|
||||
- Somnath Banerjee (somnath dot banerjee at gmail dot com)
|
||||
- Sriraman Tallam (tmsriram at google dot com)
|
||||
- Tamar Levy (tamar dot levy at intel dot com)
|
||||
- Thiago Perrotta (tperrotta at google dot com)
|
||||
- Timothy Gu (timothygu99 at gmail dot com)
|
||||
- Urvang Joshi (urvang at google dot com)
|
||||
- Vikas Arora (vikasa at google dot com)
|
||||
- Vincent Rabaud (vrabaud at google dot com)
|
||||
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
|
||||
- Wan-Teh Chang (wtc at google dot com)
|
||||
- wrv (wrv at utexas dot edu)
|
||||
- Yang Zhang (yang dot zhang at arm dot com)
|
||||
- Yannis Guyon (yguyon at google dot com)
|
||||
- Zhi An Ng (zhin at chromium dot org)
|
||||
|
||||
31
Android.mk
31
Android.mk
@@ -1,5 +1,3 @@
|
||||
# Ignore this file during non-NDK builds.
|
||||
ifdef NDK_ROOT
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD
|
||||
@@ -35,15 +33,6 @@ else
|
||||
NEON := c
|
||||
endif
|
||||
|
||||
sharpyuv_srcs := \
|
||||
sharpyuv/sharpyuv.c \
|
||||
sharpyuv/sharpyuv_cpu.c \
|
||||
sharpyuv/sharpyuv_csp.c \
|
||||
sharpyuv/sharpyuv_dsp.c \
|
||||
sharpyuv/sharpyuv_gamma.c \
|
||||
sharpyuv/sharpyuv_neon.$(NEON) \
|
||||
sharpyuv/sharpyuv_sse2.c \
|
||||
|
||||
dec_srcs := \
|
||||
src/dec/alpha_dec.c \
|
||||
src/dec/buffer_dec.c \
|
||||
@@ -66,6 +55,9 @@ dsp_dec_srcs := \
|
||||
src/dsp/alpha_processing_neon.$(NEON) \
|
||||
src/dsp/alpha_processing_sse2.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/dec.c \
|
||||
src/dsp/dec_clip_tables.c \
|
||||
@@ -85,7 +77,6 @@ dsp_dec_srcs := \
|
||||
src/dsp/lossless_msa.c \
|
||||
src/dsp/lossless_neon.$(NEON) \
|
||||
src/dsp/lossless_sse2.c \
|
||||
src/dsp/lossless_sse41.c \
|
||||
src/dsp/rescaler.c \
|
||||
src/dsp/rescaler_mips32.c \
|
||||
src/dsp/rescaler_mips_dsp_r2.c \
|
||||
@@ -97,21 +88,19 @@ dsp_dec_srcs := \
|
||||
src/dsp/upsampling_msa.c \
|
||||
src/dsp/upsampling_neon.$(NEON) \
|
||||
src/dsp/upsampling_sse2.c \
|
||||
src/dsp/upsampling_sse41.c \
|
||||
src/dsp/yuv.c \
|
||||
src/dsp/yuv_mips32.c \
|
||||
src/dsp/yuv_mips_dsp_r2.c \
|
||||
src/dsp/yuv_neon.$(NEON) \
|
||||
src/dsp/yuv_sse2.c \
|
||||
src/dsp/yuv_sse41.c \
|
||||
|
||||
dsp_enc_srcs := \
|
||||
src/dsp/cost.c \
|
||||
src/dsp/cost_mips32.c \
|
||||
src/dsp/cost_mips_dsp_r2.c \
|
||||
src/dsp/cost_neon.$(NEON) \
|
||||
src/dsp/cost_sse2.c \
|
||||
src/dsp/enc.c \
|
||||
src/dsp/enc_avx2.c \
|
||||
src/dsp/enc_mips32.c \
|
||||
src/dsp/enc_mips_dsp_r2.c \
|
||||
src/dsp/enc_msa.c \
|
||||
@@ -135,6 +124,7 @@ enc_srcs := \
|
||||
src/enc/backward_references_enc.c \
|
||||
src/enc/config_enc.c \
|
||||
src/enc/cost_enc.c \
|
||||
src/enc/delta_palettization_enc.c \
|
||||
src/enc/filter_enc.c \
|
||||
src/enc/frame_enc.c \
|
||||
src/enc/histogram_enc.c \
|
||||
@@ -164,7 +154,6 @@ utils_dec_srcs := \
|
||||
src/utils/color_cache_utils.c \
|
||||
src/utils/filters_utils.c \
|
||||
src/utils/huffman_utils.c \
|
||||
src/utils/palette.c \
|
||||
src/utils/quant_levels_dec_utils.c \
|
||||
src/utils/random_utils.c \
|
||||
src/utils/rescaler_utils.c \
|
||||
@@ -187,7 +176,7 @@ LOCAL_SRC_FILES := \
|
||||
$(utils_dec_srcs) \
|
||||
|
||||
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
|
||||
LOCAL_ARM_MODE := arm
|
||||
@@ -216,13 +205,12 @@ endif # ENABLE_SHARED=1
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(sharpyuv_srcs) \
|
||||
$(dsp_enc_srcs) \
|
||||
$(enc_srcs) \
|
||||
$(utils_enc_srcs) \
|
||||
|
||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
|
||||
|
||||
# prefer arm over thumb mode for performance gains
|
||||
LOCAL_ARM_MODE := arm
|
||||
@@ -245,7 +233,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := $(demux_srcs)
|
||||
|
||||
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
|
||||
LOCAL_ARM_MODE := arm
|
||||
@@ -268,7 +256,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := $(mux_srcs)
|
||||
|
||||
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
|
||||
LOCAL_ARM_MODE := arm
|
||||
@@ -292,4 +280,3 @@ include $(WEBP_SRC_PATH)/examples/Android.mk
|
||||
ifeq ($(USE_CPUFEATURES),yes)
|
||||
$(call import-module,android/cpufeatures)
|
||||
endif
|
||||
endif # NDK_ROOT
|
||||
|
||||
887
CMakeLists.txt
887
CMakeLists.txt
File diff suppressed because it is too large
Load Diff
@@ -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/).
|
||||
@@ -1,8 +1,8 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = sharpyuv src imageio man
|
||||
SUBDIRS = src imageio man
|
||||
EXTRA_DIST = COPYING autogen.sh
|
||||
|
||||
if BUILD_EXTRAS
|
||||
if WANT_EXTRAS
|
||||
SUBDIRS += extras
|
||||
endif
|
||||
|
||||
|
||||
141
Makefile.vc
141
Makefile.vc
@@ -5,15 +5,12 @@ LIBWEBPDECODER_BASENAME = libwebpdecoder
|
||||
LIBWEBP_BASENAME = libwebp
|
||||
LIBWEBPMUX_BASENAME = libwebpmux
|
||||
LIBWEBPDEMUX_BASENAME = libwebpdemux
|
||||
LIBSHARPYUV_BASENAME = libsharpyuv
|
||||
|
||||
!IFNDEF ARCH
|
||||
!IF ! [ cl 2>&1 | find "x86" > NUL ]
|
||||
ARCH = x86
|
||||
!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ]
|
||||
ARCH = x64
|
||||
!ELSE IF ! [ cl 2>&1 | find "ARM64" > NUL ]
|
||||
ARCH = ARM64
|
||||
!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ]
|
||||
ARCH = ARM
|
||||
!ELSE
|
||||
@@ -31,14 +28,15 @@ PLATFORM_LDFLAGS = /SAFESEH
|
||||
|
||||
NOLOGO = /nologo
|
||||
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
|
||||
CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1
|
||||
CFLAGS = /I. /Isrc $(NOLOGO) /MP /W3 /EHsc /c
|
||||
CCDEBUG = cl.exe $(NOLOGO) /Od /Gm /Zi /D_DEBUG /RTC1
|
||||
CFLAGS = /Isrc $(NOLOGO) /W3 /EHsc /c
|
||||
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)
|
||||
LNKDLL = link.exe /DLL $(NOLOGO)
|
||||
LNKEXE = link.exe $(NOLOGO)
|
||||
LNKLIB = lib.exe $(NOLOGO)
|
||||
MT = mt.exe $(NOLOGO)
|
||||
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
|
||||
RCDEBUG = $(RCNODBG) /D_DEBUG
|
||||
|
||||
@@ -55,6 +53,11 @@ OUTDIR = ..\obj\
|
||||
OUTDIR = $(OBJDIR)
|
||||
!ENDIF
|
||||
|
||||
!IF "$(HAVE_AVX2)" == "1"
|
||||
CFLAGS = $(CFLAGS) /DWEBP_HAVE_AVX2
|
||||
AVX2_FLAGS = /arch:AVX2
|
||||
!ENDIF
|
||||
|
||||
##############################################################
|
||||
# Runtime library configuration
|
||||
!IF "$(RTLIBCFG)" == "static"
|
||||
@@ -84,7 +87,6 @@ OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
|
||||
$(DIROBJ)\extras \
|
||||
$(DIROBJ)\imageio \
|
||||
$(DIROBJ)\mux \
|
||||
$(DIROBJ)\sharpyuv \
|
||||
$(DIROBJ)\utils \
|
||||
|
||||
# Target configuration
|
||||
@@ -99,7 +101,6 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
|
||||
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
|
||||
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
|
||||
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
|
||||
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
|
||||
!ELSE IF "$(CFG)" == "release-dynamic"
|
||||
CC = $(CCNODBG)
|
||||
RC = $(RCNODBG)
|
||||
@@ -113,7 +114,6 @@ LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
|
||||
LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug
|
||||
LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
|
||||
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
|
||||
LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug
|
||||
!ENDIF
|
||||
|
||||
!IF "$(STATICLIBBUILD)" == "TRUE"
|
||||
@@ -123,28 +123,23 @@ LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib
|
||||
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
|
||||
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
|
||||
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
|
||||
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME).lib
|
||||
!ELSE IF "$(DLLBUILD)" == "TRUE"
|
||||
CC = $(CC) /I$(DIROBJ) $(RTLIB) /DWEBP_DLL
|
||||
DLLINC = webp_dll.h
|
||||
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
|
||||
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
|
||||
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
|
||||
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib
|
||||
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib
|
||||
LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME)_dll.lib
|
||||
LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
|
||||
CFGSET = TRUE
|
||||
!ENDIF
|
||||
|
||||
!IF "$(UNICODE)" == "1"
|
||||
CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
|
||||
!ENDIF
|
||||
|
||||
#######################
|
||||
# Usage
|
||||
#
|
||||
!IF "$(CFGSET)" == "FALSE"
|
||||
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
|
||||
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [UNICODE=1] [<target>]
|
||||
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
|
||||
!MESSAGE
|
||||
!MESSAGE where <config> is one of:
|
||||
!MESSAGE - release-static - release static library
|
||||
@@ -160,7 +155,6 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
|
||||
!MESSAGE - all - build (de)mux-based targets for CFG
|
||||
!MESSAGE - gif2webp - requires libgif & >= VS2013
|
||||
!MESSAGE - anim_diff - requires libgif & >= VS2013
|
||||
!MESSAGE - anim_dump
|
||||
!MESSAGE
|
||||
!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'.
|
||||
!MESSAGE 'legacy' will produce a Windows 2000 compatible library.
|
||||
@@ -180,15 +174,6 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
|
||||
# A config was provided, so the library can be built.
|
||||
#
|
||||
|
||||
SHARPYUV_OBJS = \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_cpu.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_csp.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_neon.obj \
|
||||
$(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \
|
||||
|
||||
DEC_OBJS = \
|
||||
$(DIROBJ)\dec\alpha_dec.obj \
|
||||
$(DIROBJ)\dec\buffer_dec.obj \
|
||||
@@ -230,8 +215,6 @@ DSP_DEC_OBJS = \
|
||||
$(DIROBJ)\dsp\lossless_msa.obj \
|
||||
$(DIROBJ)\dsp\lossless_neon.obj \
|
||||
$(DIROBJ)\dsp\lossless_sse2.obj \
|
||||
$(DIROBJ)\dsp\lossless_sse41.obj \
|
||||
$(DIROBJ)\dsp\lossless_avx2.obj \
|
||||
$(DIROBJ)\dsp\rescaler.obj \
|
||||
$(DIROBJ)\dsp\rescaler_mips32.obj \
|
||||
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
|
||||
@@ -243,21 +226,22 @@ DSP_DEC_OBJS = \
|
||||
$(DIROBJ)\dsp\upsampling_msa.obj \
|
||||
$(DIROBJ)\dsp\upsampling_neon.obj \
|
||||
$(DIROBJ)\dsp\upsampling_sse2.obj \
|
||||
$(DIROBJ)\dsp\upsampling_sse41.obj \
|
||||
$(DIROBJ)\dsp\yuv.obj \
|
||||
$(DIROBJ)\dsp\yuv_mips32.obj \
|
||||
$(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \
|
||||
$(DIROBJ)\dsp\yuv_neon.obj \
|
||||
$(DIROBJ)\dsp\yuv_sse2.obj \
|
||||
$(DIROBJ)\dsp\yuv_sse41.obj \
|
||||
|
||||
DSP_ENC_OBJS = \
|
||||
$(DIROBJ)\dsp\argb.obj \
|
||||
$(DIROBJ)\dsp\argb_mips_dsp_r2.obj \
|
||||
$(DIROBJ)\dsp\argb_sse2.obj \
|
||||
$(DIROBJ)\dsp\cost.obj \
|
||||
$(DIROBJ)\dsp\cost_mips32.obj \
|
||||
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
|
||||
$(DIROBJ)\dsp\cost_neon.obj \
|
||||
$(DIROBJ)\dsp\cost_sse2.obj \
|
||||
$(DIROBJ)\dsp\enc.obj \
|
||||
$(DIROBJ)\dsp\enc_avx2.obj \
|
||||
$(DIROBJ)\dsp\enc_mips32.obj \
|
||||
$(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
|
||||
$(DIROBJ)\dsp\enc_msa.obj \
|
||||
@@ -271,7 +255,6 @@ DSP_ENC_OBJS = \
|
||||
$(DIROBJ)\dsp\lossless_enc_neon.obj \
|
||||
$(DIROBJ)\dsp\lossless_enc_sse2.obj \
|
||||
$(DIROBJ)\dsp\lossless_enc_sse41.obj \
|
||||
$(DIROBJ)\dsp\lossless_enc_avx2.obj \
|
||||
$(DIROBJ)\dsp\ssim.obj \
|
||||
$(DIROBJ)\dsp\ssim_sse2.obj \
|
||||
|
||||
@@ -304,6 +287,7 @@ ENC_OBJS = \
|
||||
$(DIROBJ)\enc\backward_references_enc.obj \
|
||||
$(DIROBJ)\enc\config_enc.obj \
|
||||
$(DIROBJ)\enc\cost_enc.obj \
|
||||
$(DIROBJ)\enc\delta_palettization_enc.obj \
|
||||
$(DIROBJ)\enc\filter_enc.obj \
|
||||
$(DIROBJ)\enc\frame_enc.obj \
|
||||
$(DIROBJ)\enc\histogram_enc.obj \
|
||||
@@ -325,7 +309,6 @@ ENC_OBJS = \
|
||||
EXTRAS_OBJS = \
|
||||
$(DIROBJ)\extras\extras.obj \
|
||||
$(DIROBJ)\extras\quality_estimate.obj \
|
||||
$(DIROBJ)\extras\sharpyuv_risk_table.obj \
|
||||
|
||||
IMAGEIO_UTIL_OBJS = \
|
||||
$(DIROBJ)\imageio\imageio_util.obj \
|
||||
@@ -341,7 +324,6 @@ UTILS_DEC_OBJS = \
|
||||
$(DIROBJ)\utils\color_cache_utils.obj \
|
||||
$(DIROBJ)\utils\filters_utils.obj \
|
||||
$(DIROBJ)\utils\huffman_utils.obj \
|
||||
$(DIROBJ)\utils\palette.obj \
|
||||
$(DIROBJ)\utils\quant_levels_dec_utils.obj \
|
||||
$(DIROBJ)\utils\rescaler_utils.obj \
|
||||
$(DIROBJ)\utils\random_utils.obj \
|
||||
@@ -354,13 +336,12 @@ UTILS_ENC_OBJS = \
|
||||
$(DIROBJ)\utils\quant_levels_utils.obj \
|
||||
|
||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
|
||||
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_OBJS)
|
||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
||||
$(UTILS_ENC_OBJS) $(DLL_OBJS)
|
||||
LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
|
||||
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
|
||||
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
|
||||
|
||||
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) $(LIBSHARPYUV)
|
||||
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
|
||||
!IF "$(ARCH)" == "ARM"
|
||||
ex: $(OUT_LIBS)
|
||||
all: ex
|
||||
@@ -377,25 +358,18 @@ all: ex $(EXTRA_EXAMPLES)
|
||||
# C99 support which is only available from VS2013 onward.
|
||||
gif2webp: $(DIRBIN)\gif2webp.exe
|
||||
anim_diff: $(DIRBIN)\anim_diff.exe
|
||||
anim_dump: $(DIRBIN)\anim_dump.exe
|
||||
|
||||
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
|
||||
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||
$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS)
|
||||
$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||
$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
|
||||
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
|
||||
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX) $(LIBSHARPYUV)
|
||||
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
|
||||
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
|
||||
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
|
||||
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
|
||||
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
|
||||
$(DIRBIN)\gif2webp.exe: $(LIBWEBP) $(LIBSHARPYUV)
|
||||
$(DIRBIN)\gif2webp.exe: $(LIBWEBP)
|
||||
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
|
||||
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
|
||||
@@ -405,40 +379,37 @@ $(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
|
||||
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
|
||||
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
|
||||
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP) $(LIBSHARPYUV)
|
||||
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
|
||||
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
|
||||
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||
$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj
|
||||
$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS)
|
||||
$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS)
|
||||
# EXTRA_OBJS requires private symbols from dsp. Explicitly add those when
|
||||
# building libwebp as a dll.
|
||||
!IF "$(DLLBUILD)" == "TRUE"
|
||||
$(DIRBIN)\webp_quality.exe: $(DSP_DEC_OBJS)
|
||||
!ENDIF
|
||||
$(DIRBIN)\webp_quality.exe: $(LIBWEBP)
|
||||
$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) $(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)
|
||||
$(DIRBIN)\webpinfo.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
|
||||
|
||||
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
|
||||
$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS)
|
||||
$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
|
||||
!ENDIF # ARCH == ARM
|
||||
|
||||
$(LIBSHARPYUV): $(LIBSHARPYUV_OBJS)
|
||||
experimental:
|
||||
$(MAKE) /f Makefile.vc \
|
||||
CFG=$(CFG) \
|
||||
CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
|
||||
|
||||
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
|
||||
$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBSHARPYUV)
|
||||
$(LIBWEBP): $(LIBWEBP_OBJS)
|
||||
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
|
||||
$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS)
|
||||
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \
|
||||
$(OUTPUT_DIRS)
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
|
||||
|
||||
!IF "$(DLLBUILD)" == "TRUE"
|
||||
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
|
||||
$(DIROBJ)\$(DLLINC)
|
||||
|
||||
{$(DIROBJ)}.c{$(DIROBJ)}.obj:
|
||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
|
||||
|
||||
@@ -448,20 +419,20 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \
|
||||
$(RC) /fo$@ $<
|
||||
{src\mux}.rc{$(DIROBJ)\mux}.res:
|
||||
$(RC) /fo$@ $<
|
||||
{sharpyuv}.rc{$(DIROBJ)\sharpyuv}.res:
|
||||
$(RC) /fo$@ $<
|
||||
|
||||
$(LIBSHARPYUV): $(DIROBJ)\sharpyuv\$(LIBSHARPYUV_BASENAME:_debug=).res
|
||||
$(LIBWEBP): $(LIBSHARPYUV) $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
|
||||
$(LIBWEBP): $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
|
||||
$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
|
||||
$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
|
||||
$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
|
||||
|
||||
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
|
||||
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
|
||||
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
|
||||
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
|
||||
|
||||
clean::
|
||||
@-erase /s $(DIROBJ)\$(DLLINC) 2> NUL
|
||||
!ELSE
|
||||
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
|
||||
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
|
||||
$(LNKLIB) /out:$@ $**
|
||||
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
|
||||
!ENDIF
|
||||
@@ -469,15 +440,22 @@ $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV):
|
||||
$(OUTPUT_DIRS):
|
||||
@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
|
||||
# File-specific flag builds. Note batch rules take precedence over wildcards,
|
||||
# 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
|
||||
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
|
||||
/Fo$(DIROBJ)\examples\ examples\$(@B).c
|
||||
$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c
|
||||
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
|
||||
/Fo$(DIROBJ)\examples\ examples\$(@B).c
|
||||
$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c
|
||||
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
|
||||
/Fo$(DIROBJ)\examples\ examples\$(@B).c
|
||||
@@ -494,8 +472,6 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
|
||||
{imageio}.c{$(DIROBJ)\imageio}.obj::
|
||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $<
|
||||
{sharpyuv}.c{$(DIROBJ)\sharpyuv}.obj::
|
||||
$(CC) $(CFLAGS) /Fd$(DIROBJ)\sharpyuv\ /Fo$(DIROBJ)\sharpyuv\ $<
|
||||
{src\dec}.c{$(DIROBJ)\dec}.obj::
|
||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
|
||||
{src\demux}.c{$(DIROBJ)\demux}.obj::
|
||||
@@ -509,16 +485,17 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
||||
{src\utils}.c{$(DIROBJ)\utils}.obj::
|
||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
|
||||
|
||||
LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib
|
||||
!IF "$(UNICODE)" == "1"
|
||||
LNKLIBS = $(LNKLIBS) Shell32.lib
|
||||
!ENDIF
|
||||
|
||||
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
|
||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
|
||||
ole32.lib windowscodecs.lib shlwapi.lib
|
||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
||||
del $@.manifest
|
||||
|
||||
{$(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::
|
||||
@-erase /s $(DIROBJ)\*.dll 2> NUL
|
||||
|
||||
189
NEWS
189
NEWS
@@ -1,192 +1,3 @@
|
||||
- 6/30/2025 version 1.6.0
|
||||
This is a binary compatible release.
|
||||
API changes:
|
||||
- libwebp: WebPValidateDecoderConfig
|
||||
* additional x86 (AVX2, SSE2), general optimizations and compression
|
||||
improvements for lossless
|
||||
* `-mt` returns same results as single-threaded lossless (regressed in
|
||||
1.5.0, #426506716)
|
||||
* miscellaneous warning, bug & build fixes (#393104377, #397130631,
|
||||
#398288323, #398066379, #427503509)
|
||||
Tool updates:
|
||||
* cwebp can restrict the use of `-resize` with `-resize_mode` (#405437935)
|
||||
|
||||
- 12/19/2024 version 1.5.0
|
||||
This is a binary compatible release.
|
||||
API changes:
|
||||
- `cross_color_transform_bits` added to WebPAuxStats
|
||||
* minor lossless encoder speed and compression improvements
|
||||
* lossless encoding does not use floats anymore
|
||||
* additional Arm optimizations for lossy & lossless + general code generation
|
||||
improvements
|
||||
* improvements to WASM performance (#643)
|
||||
* improvements and corrections in webp-container-spec.txt and
|
||||
webp-lossless-bitstream-spec.txt (#646, #355607636)
|
||||
* further security related hardening and increased fuzzing coverage w/fuzztest
|
||||
(oss-fuzz: #382816119, #70112, #70102, #69873, #69825, #69508, #69208)
|
||||
* miscellaneous warning, bug & build fixes (#499, #562, #381372617,
|
||||
#381109771, #42340561, #375011696, #372109644, chromium: #334120888)
|
||||
Tool updates:
|
||||
* gif2webp: add -sharp_yuv & -near_lossless
|
||||
* img2webp: add -exact & -noexact
|
||||
* exit codes normalized; running an example program with no
|
||||
arguments will output its help and exit with an error (#42340557,
|
||||
#381372617)
|
||||
|
||||
- 4/12/2024: version 1.4.0
|
||||
This is a binary compatible release.
|
||||
* API changes:
|
||||
- libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
|
||||
WebPAnimEncoderDeleteChunk
|
||||
- libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
|
||||
- extras: SharpYuvEstimate420Risk
|
||||
* further security related hardening in libwebp & examples
|
||||
* some minor optimizations in the lossless encoder
|
||||
* added WEBP_NODISCARD to report unused result warnings; enable with
|
||||
-DWEBP_ENABLE_NODISCARD=1
|
||||
* improvements and corrections in webp-container-spec.txt and
|
||||
webp-lossless-bitstream-spec.txt (#611)
|
||||
* miscellaneous warning, bug & build fixes (#615, #619, #632, #635)
|
||||
|
||||
- 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
|
||||
* lossless performance and compression improvements
|
||||
* miscellaneous performance improvements (SSE2, NEON, MSA)
|
||||
|
||||
245
PRESUBMIT.py
245
PRESUBMIT.py
@@ -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
|
||||
757
README
Normal file
757
README
Normal file
@@ -0,0 +1,757 @@
|
||||
__ __ ____ ____ ____
|
||||
/ \\/ \/ _ \/ _ )/ _ \
|
||||
\ / __/ _ \ __/
|
||||
\__\__/\____/\_____/__/ ____ ___
|
||||
/ _/ / \ \ / _ \/ _/
|
||||
/ \_/ / / \ \ __/ \__
|
||||
\____/____/\_____/_____/____/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:
|
||||
------
|
||||
With CMake, you can compile libwebp, cwebp, dwebp, gif2web, img2webp and the
|
||||
JS bindings.
|
||||
|
||||
Prerequisites:
|
||||
A compiler (e.g., gcc with autotools) and CMake.
|
||||
On a Debian-like system the following should install everything you need for a
|
||||
minimal build:
|
||||
$ sudo apt-get install build-essential cmake
|
||||
|
||||
When building from git sources, you will need to run cmake to generate the
|
||||
makefiles.
|
||||
|
||||
mkdir build && cd build && cmake ../
|
||||
make
|
||||
make install
|
||||
|
||||
If you also want any of the executables, you will need to enable them through
|
||||
CMake, e.g.:
|
||||
|
||||
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
|
||||
|
||||
or through your favorite interface (like ccmake or cmake-qt-gui).
|
||||
|
||||
Finally, once installed, you can also use WebP in your CMake project by doing:
|
||||
|
||||
find_package(WebP)
|
||||
|
||||
which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
|
||||
|
||||
Gradle:
|
||||
-------
|
||||
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
|
||||
dwebp and webpmux_example.
|
||||
|
||||
Prerequisites:
|
||||
A compiler (e.g., gcc with autotools) and gradle.
|
||||
On a Debian-like system the following should install everything you need for a
|
||||
minimal build:
|
||||
$ sudo apt-get install build-essential gradle
|
||||
|
||||
When building from git sources, you will need to run the Gradle wrapper with the
|
||||
appropriate target, e.g. :
|
||||
|
||||
./gradlew buildAllExecutables
|
||||
|
||||
SWIG bindings:
|
||||
--------------
|
||||
|
||||
To generate language bindings from swig/libwebp.swig at least swig-1.3
|
||||
(http://www.swig.org) is required.
|
||||
|
||||
Currently the following functions are mapped:
|
||||
Decode:
|
||||
WebPGetDecoderVersion
|
||||
WebPGetInfo
|
||||
WebPDecodeRGBA
|
||||
WebPDecodeARGB
|
||||
WebPDecodeBGRA
|
||||
WebPDecodeBGR
|
||||
WebPDecodeRGB
|
||||
|
||||
Encode:
|
||||
WebPGetEncoderVersion
|
||||
WebPEncodeRGBA
|
||||
WebPEncodeBGRA
|
||||
WebPEncodeRGB
|
||||
WebPEncodeBGR
|
||||
WebPEncodeLosslessRGBA
|
||||
WebPEncodeLosslessBGRA
|
||||
WebPEncodeLosslessRGB
|
||||
WebPEncodeLosslessBGR
|
||||
|
||||
See swig/README for more detailed build instructions.
|
||||
|
||||
Java bindings:
|
||||
|
||||
To build the swig-generated JNI wrapper code at least JDK-1.5 (or equivalent)
|
||||
is necessary for enum support. The output is intended to be a shared object /
|
||||
DLL that can be loaded via System.loadLibrary("webp_jni").
|
||||
|
||||
Python bindings:
|
||||
|
||||
To build the swig-generated Python extension code at least Python 2.6 is
|
||||
required. Python < 2.6 may build with some minor changes to libwebp.swig or the
|
||||
generated code, but is untested.
|
||||
|
||||
Encoding tool:
|
||||
==============
|
||||
|
||||
The examples/ directory contains tools for encoding (cwebp) and
|
||||
decoding (dwebp) images.
|
||||
|
||||
The easiest use should look like:
|
||||
cwebp input.png -q 80 -o output.webp
|
||||
which will convert the input file to a WebP file using a quality factor of 80
|
||||
on a 0->100 scale (0 being the lowest quality, 100 being the best. Default
|
||||
value is 75).
|
||||
You might want to try the -lossless flag too, which will compress the source
|
||||
(in RGBA format) without any loss. The -q quality parameter will in this case
|
||||
control the amount of processing time spent trying to make the output file as
|
||||
small as possible.
|
||||
|
||||
A longer list of options is available using the -longhelp command line flag:
|
||||
|
||||
> cwebp -longhelp
|
||||
Usage:
|
||||
cwebp [-preset <...>] [options] in_file [-o out_file]
|
||||
|
||||
If input size (-s) for an image is not specified, it is
|
||||
assumed to be a PNG, JPEG, TIFF or WebP file.
|
||||
|
||||
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
|
||||
54
README.md
54
README.md
@@ -1,54 +0,0 @@
|
||||
# WebP Codec
|
||||
|
||||
```
|
||||
__ __ ____ ____ ____
|
||||
/ \\/ \/ _ \/ _ )/ _ \
|
||||
\ / __/ _ \ __/
|
||||
\__\__/\____/\_____/__/ ____ ___
|
||||
/ _/ / \ \ / _ \/ _/
|
||||
/ \_/ / / \ \ __/ \__
|
||||
\____/____/\_____/_____/____/v1.6.0
|
||||
```
|
||||
|
||||
WebP codec is a library to encode and decode images in WebP format. This package
|
||||
contains the library that can be used in other programs to add WebP support, as
|
||||
well as the command line tools 'cwebp' and 'dwebp' to compress and decompress
|
||||
images respectively.
|
||||
|
||||
See https://developers.google.com/speed/webp for details on the image format.
|
||||
|
||||
The latest source tree is available at
|
||||
https://chromium.googlesource.com/webm/libwebp
|
||||
|
||||
It is released under the same license as the WebM project. See
|
||||
https://www.webmproject.org/license/software/ or the "COPYING" file for details.
|
||||
An additional intellectual property rights grant can be found in the file
|
||||
PATENTS.
|
||||
|
||||
## Building
|
||||
|
||||
See the [building documentation](doc/building.md).
|
||||
|
||||
## Encoding and Decoding Tools
|
||||
|
||||
The examples/ directory contains tools to encode and decode images and
|
||||
animations, view information about WebP images, and more. See the
|
||||
[tools documentation](doc/tools.md).
|
||||
|
||||
## APIs
|
||||
|
||||
See the [APIs documentation](doc/api.md), and API usage examples in the
|
||||
`examples/` directory.
|
||||
|
||||
## Bugs
|
||||
|
||||
Please report all bugs to the [issue tracker](https://issues.webmproject.org).
|
||||
For security reports, select 'Security report' from the Template dropdown.
|
||||
|
||||
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
223
README.mux
Normal 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
|
||||
91
README.wasm
Normal file
91
README.wasm
Normal file
@@ -0,0 +1,91 @@
|
||||
Description:
|
||||
============
|
||||
|
||||
This file describes the compilation of libwebp using portable intrinsics /
|
||||
WebAssembly (wasm) to native targets using clang and CMake.
|
||||
|
||||
Prerequisites:
|
||||
==============
|
||||
|
||||
- cmake 2.8+
|
||||
|
||||
- clang 3.9+ for portable intrinsics support; as wasm progresses a tip of tree
|
||||
build may be necessary.
|
||||
|
||||
Building:
|
||||
=========
|
||||
|
||||
- configure the project with CMake using:
|
||||
|
||||
$ mkdir -p build && \
|
||||
cd build && \
|
||||
cmake -DWEBP_BUILD_DWEBP=1 -DCMAKE_C_COMPILER=clang -DWEBP_ENABLE_WASM=1 ../
|
||||
|
||||
- compile dwebp using 'make'.
|
||||
|
||||
- Note this currently generates native executables only and is incompatible
|
||||
with -DWEBP_BUILD_WEBP_JS.
|
||||
|
||||
Build options:
|
||||
==============
|
||||
|
||||
- platform specific multiply high (mulhi) implementation, disabled by default.
|
||||
arm: -DCMAKE_C_FLAGS='-DENABLE_NEON_BUILTIN_MULHI_INT16X8 ...'
|
||||
x86: -DCMAKE_C_FLAGS='-DENABLE_X86_BUILTIN_MULHI_INT16X8 ...'
|
||||
|
||||
Cross compilation:
|
||||
==================
|
||||
|
||||
- arm toolchains can be obtained from:
|
||||
http://www.linaro.org/downloads/
|
||||
|
||||
- the android ndk can be obtained from:
|
||||
https://developer.android.com/ndk/downloads/index.html
|
||||
|
||||
armv7:
|
||||
------
|
||||
|
||||
Android:
|
||||
$ ./android-ndk-r15b/build/tools/make_standalone_toolchain.py \
|
||||
--arch arm --api 24 --stl gnustl --install-dir /opt/android-arm-24
|
||||
$ mkdir -p build && cd build
|
||||
$ cmake ../libwebp \
|
||||
-DWEBP_BUILD_DWEBP=1 \
|
||||
-DCMAKE_C_COMPILER=/opt/android-arm-24/bin/clang \
|
||||
-DCMAKE_PREFIX_PATH=/opt/android-arm-24/sysroot/usr/lib \
|
||||
-DCMAKE_C_FLAGS=-fPIE \
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DWEBP_ENABLE_WASM=1
|
||||
|
||||
Linux:
|
||||
$ gcc_arm=/opt/gcc-arm; target=arm-linux-gnueabihf
|
||||
$ mkdir -p build && cd build
|
||||
$ cmake ../libwebp -DWEBP_BUILD_DWEBP=1 -DWEBP_ENABLE_WASM=1 \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_C_FLAGS="--target=$target --gcc-toolchain=$gcc_arm --sysroot=$gcc_arm/$target/libc -march=armv7-a -mfpu=neon" \
|
||||
-DCMAKE_PREFIX_PATH=$gcc_arm/$target/libc/usr
|
||||
|
||||
aarch64 / arm64:
|
||||
----------------
|
||||
|
||||
Android:
|
||||
$ ./android-ndk-r15b/build/tools/make_standalone_toolchain.py \
|
||||
--arch arm64 --api 24 --stl gnustl --install-dir /opt/android-arm64-24
|
||||
$ mkdir -p build && cd build
|
||||
$ cmake ../libwebp \
|
||||
-DWEBP_BUILD_DWEBP=1 \
|
||||
-DCMAKE_C_COMPILER=/opt/android-arm64-24/bin/clang \
|
||||
-DCMAKE_PREFIX_PATH=/opt/android-arm64-24/sysroot/usr/lib \
|
||||
-DCMAKE_C_FLAGS=-fPIE \
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DWEBP_ENABLE_WASM=1
|
||||
|
||||
Linux:
|
||||
$ gcc_arm=/opt/gcc-aarch64; target=aarch64-linux-gnu
|
||||
$ mkdir -p build && cd build
|
||||
$ cmake ../libwebp -DWEBP_BUILD_DWEBP=1 -DWEBP_ENABLE_WASM=1 \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_C_FLAGS="--target=$target --gcc-toolchain=$gcc_arm --sysroot=$gcc_arm/$target/libc" \
|
||||
-DCMAKE_PREFIX_PATH=$gcc_arm/$target/libc/usr
|
||||
80
README.webp_js
Normal file
80
README.webp_js
Normal file
@@ -0,0 +1,80 @@
|
||||
__ __ ____ ____ ____ __ ____
|
||||
/ \\/ \ _ \ _ \ _ \ (__)/ __\
|
||||
\ / __/ _ \ __/ _) \_ \
|
||||
\__\__/_____/____/_/ /____/____/
|
||||
|
||||
Description:
|
||||
============
|
||||
|
||||
This file describes the compilation of libwebp into a JavaScript decoder
|
||||
using Emscripten and CMake.
|
||||
|
||||
- install the Emscripten SDK following the procedure described at:
|
||||
https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
|
||||
After installation, you should have some global variable positioned to the
|
||||
location of the SDK. In particular, $EMSCRIPTEN should point to the
|
||||
top-level directory containing Emscripten tools.
|
||||
|
||||
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
|
||||
accessible. This is the toolchain file used by CMake to invoke Emscripten.
|
||||
|
||||
- configure the project 'WEBP_JS' with CMake using:
|
||||
|
||||
cd webp_js && \
|
||||
cmake -DWEBP_BUILD_WEBP_JS=ON \
|
||||
-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
|
||||
../
|
||||
|
||||
- compile webp.js using 'make'.
|
||||
|
||||
- that's it! Upon completion, you should have the webp.js and
|
||||
webp.js.mem files generated.
|
||||
|
||||
- Note this generates both webp_js and webp_wasm without any SIMD enabled due
|
||||
to bugs with this toolchain associated with the SSE2 code.
|
||||
-DWEBP_ENABLE_WASM is currently meant to generate native (x86, arm)
|
||||
executables (dwebp, cwebp) and is incompatible with -DWEBP_BUILD_WEBP_JS.
|
||||
|
||||
The callable JavaScript function is WebPToSDL(), which decodes a raw WebP
|
||||
bitstream into a canvas. See webp_js/index.html for a simple usage sample.
|
||||
|
||||
Demo HTML page:
|
||||
===============
|
||||
|
||||
The HTML page webp_js/index.html requires an HTTP server to serve the WebP
|
||||
image example. It's easy to just use Python for that.
|
||||
|
||||
cd webp_js && python -m SimpleHTTPServer 8080
|
||||
|
||||
and then navigate to http://localhost:8080 in your favorite browser.
|
||||
|
||||
|
||||
Web-Assembly (WASM) version:
|
||||
============================
|
||||
|
||||
CMakeLists.txt is configured to build the WASM version when using
|
||||
the option WEBP_BUILD_WEBP_JS=ON. The compilation step will assemble
|
||||
the files 'webp_wasm.js', 'webp_wasm.wasm' in the webp_js/ directory.
|
||||
See webp_js/index_wasm.html for a simple demo page using the WASM version
|
||||
of the library.
|
||||
|
||||
You will need a fairly recent version of Emscripten (at least 1.37.8) and of
|
||||
your WASM-enabled browser to run this version. Consider it very experimental!
|
||||
|
||||
Caveat:
|
||||
=======
|
||||
|
||||
- First decoding using the library is usually slower, due to just-in-time
|
||||
compilation.
|
||||
|
||||
- Some versions of llvm produce the following compile error when SSE2 is
|
||||
enabled.
|
||||
|
||||
"Unsupported: %516 = bitcast <8 x i16> %481 to i128
|
||||
LLVM ERROR: BitCast Instruction not yet supported for integer types larger than 64 bits"
|
||||
|
||||
The corresponding Emscripten bug is at:
|
||||
https://github.com/kripken/emscripten/issues/3788
|
||||
|
||||
Therefore, SSE2 optimization is currently disabled in CMakeLists.txt.
|
||||
31
build.gradle
31
build.gradle
@@ -82,14 +82,12 @@ model {
|
||||
}
|
||||
}
|
||||
// Check for NEON usage.
|
||||
if (getTargetPlatform() == "arm") {
|
||||
if (getTargetPlatform() == "arm" || getTargetPlatform() == "arm64") {
|
||||
NEON = "c.neon"
|
||||
cCompiler.define "HAVE_CPU_FEATURES_H"
|
||||
} else {
|
||||
NEON = "c"
|
||||
}
|
||||
|
||||
cCompiler.args "-I" + file(".").absolutePath
|
||||
}
|
||||
// Link to pthread for shared libraries.
|
||||
withType(SharedLibraryBinarySpec) {
|
||||
@@ -105,14 +103,6 @@ model {
|
||||
sources {
|
||||
c {
|
||||
source {
|
||||
srcDir "sharpyuv"
|
||||
include "sharpyuv.c"
|
||||
include "sharpyuv_cpu.c"
|
||||
include "sharpyuv_csp.c"
|
||||
include "sharpyuv_dsp.c"
|
||||
include "sharpyuv_gamma.c"
|
||||
include "sharpyuv_neon.c"
|
||||
include "sharpyuv_sse2.c"
|
||||
srcDir "src/dec"
|
||||
include "alpha_dec.c"
|
||||
include "buffer_dec.c"
|
||||
@@ -130,6 +120,9 @@ model {
|
||||
include "alpha_processing_neon.$NEON"
|
||||
include "alpha_processing_sse2.c"
|
||||
include "alpha_processing_sse41.c"
|
||||
include "argb.c"
|
||||
include "argb_mips_dsp_r2.c"
|
||||
include "argb_sse2.c"
|
||||
include "cpu.c"
|
||||
include "dec.c"
|
||||
include "dec_clip_tables.c"
|
||||
@@ -149,7 +142,6 @@ model {
|
||||
include "lossless_msa.c"
|
||||
include "lossless_neon.$NEON"
|
||||
include "lossless_sse2.c"
|
||||
include "lossless_sse41.c"
|
||||
include "rescaler.c"
|
||||
include "rescaler_mips32.c"
|
||||
include "rescaler_mips_dsp_r2.c"
|
||||
@@ -161,19 +153,16 @@ model {
|
||||
include "upsampling_msa.c"
|
||||
include "upsampling_neon.$NEON"
|
||||
include "upsampling_sse2.c"
|
||||
include "upsampling_sse41.c"
|
||||
include "yuv.c"
|
||||
include "yuv_mips32.c"
|
||||
include "yuv_mips_dsp_r2.c"
|
||||
include "yuv_neon.$NEON"
|
||||
include "yuv_sse2.c"
|
||||
include "yuv_sse41.c"
|
||||
srcDir "src/utils"
|
||||
include "bit_reader_utils.c"
|
||||
include "color_cache_utils.c"
|
||||
include "filters_utils.c"
|
||||
include "huffman_utils.c"
|
||||
include "palette.c"
|
||||
include "quant_levels_dec_utils.c"
|
||||
include "random_utils.c"
|
||||
include "rescaler_utils.c"
|
||||
@@ -183,9 +172,9 @@ model {
|
||||
include "cost.c"
|
||||
include "cost_mips32.c"
|
||||
include "cost_mips_dsp_r2.c"
|
||||
include "cost_neon.$NEON"
|
||||
include "cost_sse2.c"
|
||||
include "enc.c"
|
||||
include "enc_avx2.c"
|
||||
include "enc_mips32.c"
|
||||
include "enc_mips_dsp_r2.c"
|
||||
include "enc_msa.c"
|
||||
@@ -208,6 +197,7 @@ model {
|
||||
include "backward_references_enc.c"
|
||||
include "config_enc.c"
|
||||
include "cost_enc.c"
|
||||
include "delta_palettization_enc.c"
|
||||
include "filter_enc.c"
|
||||
include "frame_enc.c"
|
||||
include "histogram_enc.c"
|
||||
@@ -299,7 +289,6 @@ model {
|
||||
imagedec(NativeLibrarySpec) {
|
||||
binaries {
|
||||
all {
|
||||
lib library: "webpdemux", linkage: "static"
|
||||
lib library: "webp", linkage: "static"
|
||||
}
|
||||
}
|
||||
@@ -342,7 +331,6 @@ model {
|
||||
lib library: "example_util", linkage: "static"
|
||||
lib library: "imagedec", linkage: "static"
|
||||
lib library: "imageio_util", linkage: "static"
|
||||
lib library: "webpdemux", linkage: "static"
|
||||
lib library: "webp", linkage: "static"
|
||||
}
|
||||
}
|
||||
@@ -363,7 +351,6 @@ model {
|
||||
lib library: "imagedec", linkage: "static"
|
||||
lib library: "imageenc", linkage: "static"
|
||||
lib library: "imageio_util", linkage: "static"
|
||||
lib library: "webpdemux", linkage: "static"
|
||||
lib library: "webp"
|
||||
}
|
||||
}
|
||||
@@ -403,7 +390,6 @@ model {
|
||||
lib library: "imagedec", linkage: "static"
|
||||
lib library: "imageio_util", linkage: "static"
|
||||
lib library: "webpmux", linkage: "static"
|
||||
lib library: "webpdemux", linkage: "static"
|
||||
lib library: "webp"
|
||||
}
|
||||
}
|
||||
@@ -442,3 +428,8 @@ model {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Task to generate the wrapper.
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.13'
|
||||
}
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
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_DIR})
|
||||
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
|
||||
set(WebP_INCLUDE_DIRS "webp")
|
||||
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
|
||||
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
|
||||
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
|
||||
|
||||
check_required_components(WebP)
|
||||
|
||||
151
cmake/config.h.cmake
Normal file
151
cmake/config.h.cmake
Normal file
@@ -0,0 +1,151 @@
|
||||
# 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)
|
||||
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()
|
||||
|
||||
# GIF detection, gifdec isn't part of the imageio lib.
|
||||
set(WEBP_DEP_GIF_LIBRARIES)
|
||||
set(WEBP_DEP_GIF_INCLUDE_DIRS)
|
||||
find_package(GIF)
|
||||
set(WEBP_HAVE_GIF ${GIF_FOUND})
|
||||
if(GIF_FOUND)
|
||||
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
|
||||
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
## Check for specific headers.
|
||||
include(CheckIncludeFiles)
|
||||
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||
check_include_files(dlfcn.h HAVE_DLFCN_H)
|
||||
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
|
||||
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
|
||||
check_include_files(inttypes.h HAVE_INTTYPES_H)
|
||||
check_include_files(memory.h HAVE_MEMORY_H)
|
||||
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
|
||||
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
|
||||
check_include_files(stdint.h HAVE_STDINT_H)
|
||||
check_include_files(stdlib.h HAVE_STDLIB_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_include_files(string.h HAVE_STRING_H)
|
||||
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
check_include_files(wincodec.h HAVE_WINCODEC_H)
|
||||
check_include_files(windows.h HAVE_WINDOWS_H)
|
||||
|
||||
# Windows specifics
|
||||
if(HAVE_WINCODEC_H)
|
||||
list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs)
|
||||
endif()
|
||||
|
||||
## Check for SIMD extensions.
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
|
||||
|
||||
## Define extra info.
|
||||
set(PACKAGE ${PROJECT_NAME})
|
||||
set(PACKAGE_NAME ${PROJECT_NAME})
|
||||
|
||||
# Read from configure.ac.
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
|
||||
string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]"
|
||||
CONFIGURE_AC_PACKAGE_INFO ${CONFIGURE_AC}
|
||||
)
|
||||
function(strip_bracket VAR)
|
||||
string(LENGTH ${${VAR}} TMP_LEN)
|
||||
math(EXPR TMP_LEN ${TMP_LEN}-2)
|
||||
string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB)
|
||||
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
|
||||
strip_bracket(PACKAGE_VERSION)
|
||||
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
|
||||
strip_bracket(PACKAGE_BUGREPORT)
|
||||
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
|
||||
strip_bracket(PACKAGE_URL)
|
||||
|
||||
# Build more info.
|
||||
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||
set(PACKAGE_TARNAME ${PACKAGE_NAME})
|
||||
set(VERSION ${PACKAGE_VERSION})
|
||||
|
||||
## 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
|
||||
)
|
||||
@@ -13,8 +13,8 @@
|
||||
/* Set to 1 if __builtin_bswap64 is available */
|
||||
#cmakedefine HAVE_BUILTIN_BSWAP64 1
|
||||
|
||||
/* Define to 1 if you have the <cpu-features.h> header file. */
|
||||
#cmakedefine HAVE_CPU_FEATURES_H 1
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#cmakedefine HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <GLUT/glut.h> header file. */
|
||||
#cmakedefine HAVE_GLUT_GLUT_H 1
|
||||
@@ -22,12 +22,39 @@
|
||||
/* Define to 1 if you have the <GL/glut.h> header file. */
|
||||
#cmakedefine HAVE_GL_GLUT_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#cmakedefine HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#cmakedefine HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the <OpenGL/glut.h> header file. */
|
||||
#cmakedefine HAVE_OPENGL_GLUT_H 1
|
||||
|
||||
/* Have PTHREAD_PRIO_INHERIT. */
|
||||
#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
|
||||
|
||||
/* Define to 1 if you have the <shlwapi.h> header file. */
|
||||
#cmakedefine HAVE_SHLWAPI_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#cmakedefine HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#cmakedefine HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#cmakedefine HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#cmakedefine HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#cmakedefine HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H 1
|
||||
|
||||
@@ -63,9 +90,22 @@
|
||||
/* Define to the version of this package. */
|
||||
#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 */
|
||||
#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 */
|
||||
#cmakedefine WEBP_HAVE_GIF 1
|
||||
|
||||
@@ -75,34 +115,18 @@
|
||||
/* Set to 1 if JPEG library is installed */
|
||||
#cmakedefine WEBP_HAVE_JPEG 1
|
||||
|
||||
/* Set to 1 if NEON is supported */
|
||||
#cmakedefine WEBP_HAVE_NEON
|
||||
|
||||
/* Set to 1 if runtime detection of NEON is enabled */
|
||||
/* TODO: handle properly in CMake */
|
||||
#cmakedefine WEBP_HAVE_NEON_RTCD
|
||||
|
||||
/* Set to 1 if PNG library is installed */
|
||||
#cmakedefine WEBP_HAVE_PNG 1
|
||||
|
||||
/* Set to 1 if SDL library is installed */
|
||||
#cmakedefine WEBP_HAVE_SDL 1
|
||||
|
||||
/* Set to 1 if SSE2 is supported */
|
||||
#cmakedefine WEBP_HAVE_SSE2 1
|
||||
|
||||
/* Set to 1 if SSE4.1 is supported */
|
||||
#cmakedefine WEBP_HAVE_SSE41 1
|
||||
|
||||
/* Set to 1 if AVX2 is supported */
|
||||
#cmakedefine WEBP_HAVE_AVX2 1
|
||||
|
||||
/* Set to 1 if TIFF library is installed */
|
||||
#cmakedefine WEBP_HAVE_TIFF 1
|
||||
|
||||
/* Enable near lossless encoding */
|
||||
#cmakedefine WEBP_NEAR_LOSSLESS 1
|
||||
|
||||
/* Undefine this to disable thread support. */
|
||||
#cmakedefine WEBP_USE_THREAD 1
|
||||
|
||||
|
||||
113
cmake/cpu.cmake
113
cmake/cpu.cmake
@@ -1,13 +1,4 @@
|
||||
# Copyright (c) 2021 Google LLC.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
# Check for SIMD extensions.
|
||||
include(CMakePushCheckState)
|
||||
## Check for SIMD extensions.
|
||||
|
||||
function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
|
||||
if(NOT ENABLE_SIMD)
|
||||
@@ -16,10 +7,7 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
|
||||
return()
|
||||
endif()
|
||||
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
check_c_source_compiles(
|
||||
"
|
||||
check_c_source_compiles("
|
||||
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
|
||||
int main(void) {
|
||||
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
|
||||
@@ -27,9 +15,8 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
"
|
||||
WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
|
||||
cmake_pop_check_state()
|
||||
" WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}
|
||||
)
|
||||
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
|
||||
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
|
||||
else()
|
||||
@@ -38,34 +25,28 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
|
||||
endfunction()
|
||||
|
||||
# those are included in the names of WEBP_USE_* in c++ code.
|
||||
set(WEBP_SIMD_FLAGS "AVX2;SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
|
||||
set(WEBP_SIMD_FILE_EXTENSIONS
|
||||
"_avx2.c;_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
|
||||
if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
# With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2
|
||||
# or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4
|
||||
# flag, but an AVX one. Using that with SSE4 code risks generating illegal
|
||||
# instructions when used on machines with SSE4 only. The flags are left for
|
||||
# older (untested) versions to avoid any potential compatibility issues.
|
||||
if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:")
|
||||
set(SIMD_ENABLE_FLAGS)
|
||||
else()
|
||||
set(SIMD_ENABLE_FLAGS "/arch:AVX2;/arch:AVX;/arch:SSE2;;;;")
|
||||
endif()
|
||||
set(WEBP_SIMD_FLAGS "SSE2;SSE41;AVX2;MIPS32;MIPS_DSP_R2;NEON;MSA")
|
||||
set(WEBP_SIMD_FILE_EXTENSIONS "_sse2.c;_sse41.c;_avx2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
|
||||
if(MSVC)
|
||||
# MSVC does not have a SSE4 flag but AVX2 support implies
|
||||
# SSE4 support.
|
||||
set(SIMD_ENABLE_FLAGS "/arch:SSE2;/arch:AVX2;/arch:AVX2;;;;")
|
||||
set(SIMD_DISABLE_FLAGS)
|
||||
else()
|
||||
set(SIMD_ENABLE_FLAGS "-mavx2;-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
|
||||
set(SIMD_DISABLE_FLAGS "-mno-avx2;-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
|
||||
set(SIMD_ENABLE_FLAGS "-msse2;-msse4.1;-mavx2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
|
||||
set(SIMD_DISABLE_FLAGS "-mno-sse2;-mno-sse4.1;-mno-avx2;;-mno-dspr2;;-mno-msa")
|
||||
endif()
|
||||
|
||||
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
|
||||
set(WEBP_SIMD_FILES_TO_INCLUDE)
|
||||
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
|
||||
|
||||
if(ANDROID AND ANDROID_ABI)
|
||||
if(${ANDROID})
|
||||
if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
|
||||
# This is because Android studio uses the configuration "-march=armv7-a
|
||||
# -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
|
||||
# optimizations but should (as this configuration does not exist anymore).
|
||||
# This is because Android studio uses the configuration
|
||||
# "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
|
||||
# that does not trigger neon optimizations but should
|
||||
# (as this configuration does not exist anymore).
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
|
||||
endif()
|
||||
endif()
|
||||
@@ -74,41 +55,25 @@ list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
|
||||
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
|
||||
|
||||
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
# With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source
|
||||
# will fail to compile.
|
||||
if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2)
|
||||
break()
|
||||
endif()
|
||||
|
||||
list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
|
||||
|
||||
# First try with no extra flag added as the compiler might have default flags
|
||||
# (especially on Android).
|
||||
unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_FLAGS)
|
||||
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
|
||||
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
|
||||
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||
if(EMSCRIPTEN)
|
||||
set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}")
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
|
||||
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
|
||||
else()
|
||||
if(MSVC AND SIMD_ENABLE_FLAGS)
|
||||
# The detection for SSE2/SSE4 support under MSVC is based on the compiler
|
||||
# version so e.g., clang-cl will require flags to enable the assembly.
|
||||
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||
else()
|
||||
set(SIMD_COMPILE_FLAG " ")
|
||||
endif()
|
||||
set(SIMD_COMPILE_FLAG " ")
|
||||
endif()
|
||||
# Check which files we should include or not.
|
||||
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
|
||||
file(GLOB SIMD_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../sharpyuv/*${WEBP_SIMD_FILE_EXTENSION}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
|
||||
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
|
||||
"src/dsp/*${WEBP_SIMD_FILE_EXTENSION}"
|
||||
)
|
||||
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
|
||||
# Memorize the file and flags.
|
||||
foreach(FILE ${SIMD_FILES})
|
||||
@@ -120,17 +85,14 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
foreach(FILE ${SIMD_FILES})
|
||||
list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
|
||||
endforeach()
|
||||
# Explicitly disable SIMD.
|
||||
if(SIMD_DISABLE_FLAGS)
|
||||
# Explicitly disable SIMD. Avoid this with WASM to avoid an ICE with clang:
|
||||
# https://bugs.chromium.org/p/webp/issues/detail?id=350
|
||||
# WASM overrides the native SIMD so building it in is harmless aside from
|
||||
# binary size.
|
||||
if(NOT WEBP_ENABLE_WASM AND SIMD_DISABLE_FLAGS)
|
||||
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
|
||||
include(CheckCCompilerFlag)
|
||||
if(SIMD_COMPILE_FLAG)
|
||||
# Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal
|
||||
# variable at parent scope while check_cxx_source_compiles() continues
|
||||
# to set an internal cache variable, so we unset both to avoid the
|
||||
# failure / success state persisting between checks. See
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/21207.
|
||||
unset(HAS_COMPILE_FLAG)
|
||||
unset(HAS_COMPILE_FLAG CACHE)
|
||||
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
|
||||
if(HAS_COMPILE_FLAG)
|
||||
@@ -142,11 +104,11 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
set(COMMON_PATTERNS)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
|
||||
check_c_source_compiles(
|
||||
"int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX
|
||||
"warning: argument unused during compilation:" ${COMMON_PATTERNS})
|
||||
if(NOT FLAG_${SIMD_COMPILE_FLAG})
|
||||
unset(HAS_COMPILE_FLAG)
|
||||
check_c_source_compiles("int main(void) {return 0;}" FLAG2
|
||||
FAIL_REGEX "warning: argument unused during compilation:"
|
||||
${COMMON_PATTERNS}
|
||||
)
|
||||
if(NOT FLAG2)
|
||||
unset(HAS_COMPILE_FLAG CACHE)
|
||||
endif()
|
||||
endif()
|
||||
@@ -156,5 +118,14 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
endforeach()
|
||||
|
||||
## Add *_wasm.c files if enabled.
|
||||
if(WEBP_ENABLE_WASM)
|
||||
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
|
||||
"src/dsp/*_wasm.c"
|
||||
)
|
||||
foreach(FILE ${SIMD_FILES})
|
||||
list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
172
cmake/deps.cmake
172
cmake/deps.cmake
@@ -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})
|
||||
@@ -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
|
||||
215
configure.ac
215
configure.ac
@@ -1,6 +1,6 @@
|
||||
AC_INIT([libwebp], [1.6.0],
|
||||
[https://issues.webmproject.org],,
|
||||
[https://developers.google.com/speed/webp])
|
||||
AC_INIT([libwebp], [0.6.0],
|
||||
[https://bugs.chromium.org/p/webp],,
|
||||
[http://developers.google.com/speed/webp])
|
||||
AC_CANONICAL_HOST
|
||||
AC_PREREQ([2.60])
|
||||
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).
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
|
||||
dnl === AC_PROG_LIBTOOL is deprecated.
|
||||
m4_ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL])
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_SED
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
@@ -28,46 +27,11 @@ AC_ARG_ENABLE([everything],
|
||||
AS_HELP_STRING([--enable-everything],
|
||||
[Enable all optional targets. These can still be
|
||||
disabled with --disable-target]),
|
||||
[SET_IF_UNSET([enable_libsharpyuv], [$enableval])
|
||||
SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
|
||||
[SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
|
||||
SET_IF_UNSET([enable_libwebpdemux], [$enableval])
|
||||
SET_IF_UNSET([enable_libwebpextras], [$enableval])
|
||||
SET_IF_UNSET([enable_libwebpmux], [$enableval])])
|
||||
|
||||
dnl === Check whether libwebpmux should be built
|
||||
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
||||
AC_ARG_ENABLE([libwebpmux],
|
||||
AS_HELP_STRING([--disable-libwebpmux],
|
||||
[Disable libwebpmux @<:@default=no@:>@]),
|
||||
[], [enable_libwebpmux=yes])
|
||||
AC_MSG_RESULT(${enable_libwebpmux-no})
|
||||
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpdemux should be built
|
||||
AC_MSG_CHECKING(whether libwebpdemux is to be built)
|
||||
AC_ARG_ENABLE([libwebpdemux],
|
||||
AS_HELP_STRING([--disable-libwebpdemux],
|
||||
[Disable libwebpdemux @<:@default=no@:>@]),
|
||||
[], [enable_libwebpdemux=yes])
|
||||
AC_MSG_RESULT(${enable_libwebpdemux-no})
|
||||
AM_CONDITIONAL([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"])
|
||||
|
||||
dnl === Check whether decoder library should be built.
|
||||
AC_MSG_CHECKING(whether decoder library is to be built)
|
||||
AC_ARG_ENABLE([libwebpdecoder],
|
||||
AS_HELP_STRING([--enable-libwebpdecoder],
|
||||
[Build libwebpdecoder @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpdecoder-no})
|
||||
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
|
||||
|
||||
dnl === Check whether libwebpextras should be built
|
||||
AC_MSG_CHECKING(whether libwebpextras is to be built)
|
||||
AC_ARG_ENABLE([libwebpextras],
|
||||
AS_HELP_STRING([--enable-libwebpextras],
|
||||
[Build libwebpextras @<:@default=no@:>@]))
|
||||
AC_MSG_RESULT(${enable_libwebpextras-no})
|
||||
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
|
||||
|
||||
dnl === If --enable-asserts is not defined, define NDEBUG
|
||||
|
||||
AC_MSG_CHECKING(whether asserts are enabled)
|
||||
@@ -106,7 +70,6 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra-semi-stmt])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-nonliteral])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
|
||||
@@ -116,9 +79,6 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wstrict-prototypes])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code-aggressive])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable])
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused])
|
||||
@@ -166,9 +126,9 @@ AC_ARG_ENABLE([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_FLAGS="$INTRINSICS_CFLAGS $AVX2_FLAGS"
|
||||
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
|
||||
@@ -176,7 +136,13 @@ AS_IF([test "x$enable_avx2" != "xno" -a "x$enable_sse4_1" != "xno"
|
||||
AC_CHECK_HEADER([immintrin.h],
|
||||
[AC_DEFINE(WEBP_HAVE_AVX2, [1],
|
||||
[Set to 1 if AVX2 is supported])],
|
||||
[AVX2_FLAGS=""])
|
||||
[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])])
|
||||
|
||||
@@ -282,9 +248,6 @@ AS_IF([test "x$enable_neon" != "xno"], [
|
||||
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
|
||||
esac
|
||||
;;
|
||||
aarch64*|arm64*)
|
||||
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
|
||||
;;
|
||||
esac
|
||||
AC_SUBST([NEON_FLAGS])])
|
||||
|
||||
@@ -383,8 +346,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
|
||||
# override with --with-gl*
|
||||
glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL"
|
||||
glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL"
|
||||
# quiet deprecation warnings for glut
|
||||
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wno-deprecated-declarations])
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -469,10 +430,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
|
||||
|
||||
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
|
||||
build_vwebp=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
m4_normalize([Not building vwebp.
|
||||
OpenGL libraries and --enable-libwebpdemux are required.]))
|
||||
fi
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
|
||||
@@ -485,53 +442,31 @@ AC_ARG_ENABLE([sdl],
|
||||
@<:@default=auto@:>@]))
|
||||
AS_IF([test "x$enable_sdl" != "xno"], [
|
||||
CLEAR_LIBVARS([SDL])
|
||||
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl2-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"
|
||||
$sdl_header = "no";
|
||||
LIBCHECK_PROLOGUE([SDL])
|
||||
AC_CHECK_HEADER([SDL2/SDL.h], [sdl_header="SDL2/SDL.h"],
|
||||
[AC_MSG_WARN(SDL2 library not available - no SDL.h)])
|
||||
if test x"$sdl_header" != "xno"; then
|
||||
AC_LANG_PUSH(C)
|
||||
SDL_SAVED_LIBS="$LIBS"
|
||||
for lib in "" "-lSDL2" "-lSDL2main -lSDL2"; 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
|
||||
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_CHECK_LIB(SDL, SDL_Init,
|
||||
[SDL_LIBS="-lSDL"
|
||||
SDL_INCLUDES="-DWEBP_HAVE_SDL"
|
||||
AC_DEFINE(WEBP_HAVE_SDL, [1],
|
||||
[Set to 1 if SDL library is installed])
|
||||
sdl_support=yes
|
||||
],
|
||||
AC_MSG_WARN(Optional SDL library not found),
|
||||
[$MATH_LIBS]),
|
||||
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
|
||||
if test "$sdl_support" = "yes" ; then
|
||||
build_vwebp_sdl=yes
|
||||
else
|
||||
AC_MSG_NOTICE([Not building vwebp-sdl. SDL library is required.])
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -654,36 +589,24 @@ AS_IF([test "x$enable_gif" != "xno"], [
|
||||
|
||||
if test "$gif_support" = "yes" -a \
|
||||
"$enable_libwebpdemux" = "yes"; then
|
||||
build_anim_diff=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
[Not building anim_diff. libgif and --enable-libwebpdemux are required.])
|
||||
build_animdiff=yes
|
||||
fi
|
||||
|
||||
if test "$gif_support" = "yes" -a \
|
||||
"$enable_libwebpmux" = "yes"; then
|
||||
build_gif2webp=yes
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
[Not building gif2webp. libgif and --enable-libwebpmux are required.])
|
||||
fi
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"])
|
||||
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_animdiff}" = "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
|
||||
else
|
||||
AC_MSG_NOTICE(
|
||||
m4_normalize([Not building img2webp.
|
||||
--enable-libwebpdemux & --enable-libwebpmux are required.]))
|
||||
fi
|
||||
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
|
||||
|
||||
if test "$enable_libwebpmux" = "yes"; then
|
||||
build_webpinfo=yes
|
||||
else
|
||||
AC_MSG_NOTICE([Not building webpinfo. --enable-libwebpdemux is required.])
|
||||
fi
|
||||
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
|
||||
|
||||
@@ -739,7 +662,7 @@ if test "$enable_wic" = "yes"; then
|
||||
fi
|
||||
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=""
|
||||
AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified)
|
||||
@@ -747,43 +670,69 @@ AC_ARG_ENABLE([swap-16bit-csp],
|
||||
AS_HELP_STRING([--enable-swap-16bit-csp],
|
||||
[Enable byte swap for 16 bit colorspaces]))
|
||||
if test "$enable_swap_16bit_csp" = "yes"; then
|
||||
USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP=1"
|
||||
USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP"
|
||||
fi
|
||||
AC_MSG_RESULT(${enable_swap_16bit_csp-no})
|
||||
AC_SUBST(USE_SWAP_16BIT_CSP)
|
||||
|
||||
dnl === If --disable-near-lossless is defined, add -DWEBP_NEAR_LOSSLESS=0
|
||||
dnl === If --enable-experimental is defined, add -DWEBP_EXPERIMENTAL_FEATURES
|
||||
|
||||
AC_DEFINE(WEBP_NEAR_LOSSLESS, [1], [Enable near lossless encoding])
|
||||
AC_MSG_CHECKING(if --disable-near-lossless option is specified)
|
||||
AC_ARG_ENABLE([near_lossless],
|
||||
AS_HELP_STRING([--disable-near-lossless],
|
||||
[Disable near lossless encoding]),
|
||||
[], [enable_near_lossless=yes])
|
||||
if test "$enable_near_lossless" = "no"; then
|
||||
AC_DEFINE(WEBP_NEAR_LOSSLESS, [0], [Enable near lossless encoding])
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
USE_EXPERIMENTAL_CODE=""
|
||||
AC_MSG_CHECKING(if --enable-experimental option is specified)
|
||||
AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental],
|
||||
[Activate experimental features]))
|
||||
if test "$enable_experimental" = "yes"; then
|
||||
AC_DEFINE(WEBP_EXPERIMENTAL_FEATURES, [1], [Enable experimental code])
|
||||
USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
|
||||
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 Add an empty webp_libname_prefix variable for use in *.pc.in.
|
||||
AC_SUBST([webp_libname_prefix])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([src/webp/config.h])
|
||||
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
|
||||
examples/Makefile extras/Makefile imageio/Makefile \
|
||||
sharpyuv/Makefile sharpyuv/libsharpyuv.pc \
|
||||
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \
|
||||
src/demux/Makefile src/mux/Makefile \
|
||||
src/utils/Makefile \
|
||||
src/libwebp.pc src/libwebpdecoder.pc \
|
||||
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
|
||||
|
||||
dnl fix exports from MinGW builds
|
||||
AC_CONFIG_COMMANDS_POST([$SED -i 's/-DDLL_EXPORT/-DWEBP_DLL/' config.status])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE([
|
||||
@@ -800,20 +749,20 @@ libwebpmux: ${enable_libwebpmux-no}
|
||||
libwebpextras: ${enable_libwebpextras-no}
|
||||
|
||||
Tools:
|
||||
cwebp : ${enable_libwebpdemux-no}
|
||||
cwebp : yes
|
||||
Input format support
|
||||
====================
|
||||
JPEG : ${jpeg_support-no}
|
||||
PNG : ${png_support-no}
|
||||
TIFF : ${tiff_support-no}
|
||||
WIC : ${wic_support-no}
|
||||
dwebp : ${enable_libwebpdemux-no}
|
||||
dwebp : yes
|
||||
Output format support
|
||||
=====================
|
||||
PNG : ${png_support-no}
|
||||
WIC : ${wic_support-no}
|
||||
GIF support : ${gif_support-no}
|
||||
anim_diff : ${build_anim_diff-no}
|
||||
anim_diff : ${build_animdiff-no}
|
||||
gif2webp : ${build_gif2webp-no}
|
||||
img2webp : ${build_img2webp-no}
|
||||
webpmux : ${enable_libwebpmux-no}
|
||||
|
||||
29
doc/README
Normal file
29
doc/README
Normal 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/
|
||||
386
doc/api.md
386
doc/api.md
@@ -1,386 +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: WebPIDelete(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;
|
||||
config_error = WebPValidateDecoderConfig(&config); // not mandatory, but useful
|
||||
|
||||
// E) Decode the WebP image. There are two variants w.r.t decoding image.
|
||||
// The first one (E.1) decodes the full image and the second one (E.2) is
|
||||
// used to incrementally decode the image using small input buffers.
|
||||
// Any one of these steps can be used to decode the WebP image.
|
||||
|
||||
// E.1) Decode full image.
|
||||
CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);
|
||||
|
||||
// E.2) Decode image incrementally.
|
||||
WebPIDecoder* const idec = WebPIDecode(NULL, NULL, &config);
|
||||
CHECK(idec != NULL);
|
||||
while (bytes_remaining > 0) {
|
||||
VP8StatusCode status = WebPIAppend(idec, input, bytes_read);
|
||||
if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
|
||||
bytes_remaining -= bytes_read;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
WebPIDelete(idec);
|
||||
|
||||
// F) Decoded image is now in config.output (and config.output.u.RGBA).
|
||||
// It can be saved, displayed or otherwise processed.
|
||||
|
||||
// G) Reclaim memory allocated in config's object. It's safe to call
|
||||
// this function even if the memory is external and wasn't allocated
|
||||
// by WebPDecode().
|
||||
WebPFreeDecBuffer(&config.output);
|
||||
```
|
||||
|
||||
## WebP Mux
|
||||
|
||||
WebPMux is a set of two libraries 'Mux' and 'Demux' for creation, extraction and
|
||||
manipulation of an extended format WebP file, which can have features like color
|
||||
profile, metadata and animation. Reference command-line tools `webpmux` and
|
||||
`vwebp` as well as the WebP container specification
|
||||
'doc/webp-container-spec.txt' are also provided in this package, see the
|
||||
[tools documentation](tools.md).
|
||||
|
||||
### Mux API
|
||||
|
||||
The Mux API contains methods for adding data to and reading data from WebP
|
||||
files. This API currently supports XMP/EXIF metadata, ICC profile and animation.
|
||||
Other features may be added in subsequent releases.
|
||||
|
||||
Example#1 (pseudo code): Creating a WebPMux object with image data, color
|
||||
profile and XMP metadata.
|
||||
|
||||
```c
|
||||
int copy_data = 0;
|
||||
WebPMux* mux = WebPMuxNew();
|
||||
// ... (Prepare image data).
|
||||
WebPMuxSetImage(mux, &image, copy_data);
|
||||
// ... (Prepare ICC profile data).
|
||||
WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
|
||||
// ... (Prepare XMP metadata).
|
||||
WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
|
||||
// Get data from mux in WebP RIFF format.
|
||||
WebPMuxAssemble(mux, &output_data);
|
||||
WebPMuxDelete(mux);
|
||||
// ... (Consume output_data; e.g. write output_data.bytes to file).
|
||||
WebPDataClear(&output_data);
|
||||
```
|
||||
|
||||
Example#2 (pseudo code): Get image and color profile data from a WebP file.
|
||||
|
||||
```c
|
||||
int copy_data = 0;
|
||||
// ... (Read data from file).
|
||||
WebPMux* mux = WebPMuxCreate(&data, copy_data);
|
||||
WebPMuxGetFrame(mux, 1, &image);
|
||||
// ... (Consume image; e.g. call WebPDecode() to decode the data).
|
||||
WebPMuxGetChunk(mux, "ICCP", &icc_profile);
|
||||
// ... (Consume icc_profile).
|
||||
WebPMuxDelete(mux);
|
||||
free(data);
|
||||
```
|
||||
|
||||
For a detailed Mux API reference, please refer to the header file
|
||||
(src/webp/mux.h).
|
||||
|
||||
### Demux API
|
||||
|
||||
The Demux API enables extraction of images and extended format data from WebP
|
||||
files. This API currently supports reading of XMP/EXIF metadata, ICC profile and
|
||||
animated images. Other features may be added in subsequent releases.
|
||||
|
||||
Code example: Demuxing WebP data to extract all the frames, ICC profile and
|
||||
EXIF/XMP metadata.
|
||||
|
||||
```c
|
||||
WebPDemuxer* demux = WebPDemux(&webp_data);
|
||||
uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
|
||||
uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
|
||||
// ... (Get information about the features present in the WebP file).
|
||||
uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
|
||||
|
||||
// ... (Iterate over all frames).
|
||||
WebPIterator iter;
|
||||
if (WebPDemuxGetFrame(demux, 1, &iter)) {
|
||||
do {
|
||||
// ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(),
|
||||
// ... and get other frame properties like width, height, offsets etc.
|
||||
// ... see 'struct WebPIterator' below for more info).
|
||||
} while (WebPDemuxNextFrame(&iter));
|
||||
WebPDemuxReleaseIterator(&iter);
|
||||
}
|
||||
|
||||
// ... (Extract metadata).
|
||||
WebPChunkIterator chunk_iter;
|
||||
if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter);
|
||||
// ... (Consume the ICC profile in 'chunk_iter.chunk').
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter);
|
||||
// ... (Consume the EXIF metadata in 'chunk_iter.chunk').
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter);
|
||||
// ... (Consume the XMP metadata in 'chunk_iter.chunk').
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
WebPDemuxDelete(demux);
|
||||
```
|
||||
|
||||
For a detailed Demux API reference, please refer to the header file
|
||||
(src/webp/demux.h).
|
||||
|
||||
## AnimEncoder API
|
||||
|
||||
The AnimEncoder API can be used to create animated WebP images.
|
||||
|
||||
Code example:
|
||||
|
||||
```c
|
||||
WebPAnimEncoderOptions enc_options;
|
||||
WebPAnimEncoderOptionsInit(&enc_options);
|
||||
// ... (Tune 'enc_options' as needed).
|
||||
WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
|
||||
while(<there are more frames>) {
|
||||
WebPConfig config;
|
||||
WebPConfigInit(&config);
|
||||
// ... (Tune 'config' as needed).
|
||||
WebPAnimEncoderAdd(enc, frame, duration, &config);
|
||||
}
|
||||
WebPAnimEncoderAssemble(enc, webp_data);
|
||||
WebPAnimEncoderDelete(enc);
|
||||
// ... (Write the 'webp_data' to a file, or re-mux it further).
|
||||
```
|
||||
|
||||
For a detailed AnimEncoder API reference, please refer to the header file
|
||||
(src/webp/mux.h).
|
||||
|
||||
## AnimDecoder API
|
||||
|
||||
This AnimDecoder API allows decoding (possibly) animated WebP images.
|
||||
|
||||
Code Example:
|
||||
|
||||
```c
|
||||
WebPAnimDecoderOptions dec_options;
|
||||
WebPAnimDecoderOptionsInit(&dec_options);
|
||||
// Tune 'dec_options' as needed.
|
||||
WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
|
||||
WebPAnimInfo anim_info;
|
||||
WebPAnimDecoderGetInfo(dec, &anim_info);
|
||||
for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
|
||||
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
||||
uint8_t* buf;
|
||||
int timestamp;
|
||||
WebPAnimDecoderGetNext(dec, &buf, ×tamp);
|
||||
// ... (Render 'buf' based on 'timestamp').
|
||||
// ... (Do NOT free 'buf', as it is owned by 'dec').
|
||||
}
|
||||
WebPAnimDecoderReset(dec);
|
||||
}
|
||||
const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
|
||||
// ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
|
||||
WebPAnimDecoderDelete(dec);
|
||||
```
|
||||
|
||||
For a detailed AnimDecoder API reference, please refer to the header file
|
||||
(src/webp/demux.h).
|
||||
231
doc/building.md
231
doc/building.md
@@ -1,231 +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
|
||||
```
|
||||
|
||||
## Building libwebp - Using vcpkg
|
||||
|
||||
You can download and install libwebp using the
|
||||
[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install libwebp
|
||||
```
|
||||
|
||||
The libwebp port in vcpkg is kept up to date by Microsoft team members and
|
||||
community contributors. If the version is out of date, please
|
||||
[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
|
||||
vcpkg repository.
|
||||
|
||||
## 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](../webp_js/README.md)
|
||||
@@ -1,27 +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 \
|
||||
-x syntax-coderay --syntax-highlighter coderay \
|
||||
--syntax-highlighter-opts "{default_lang: c, line_numbers: , css: style}" \
|
||||
> doc/output/webp-lossless-bitstream-spec.html
|
||||
```
|
||||
|
||||
Optimally, use kramdown 0.13.7 or newer if syntax highlighting desired.
|
||||
524
doc/tools.md
524
doc/tools.md
@@ -1,524 +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)
|
||||
-resize_mode <string> .. one of: up_only, down_only, always (default)
|
||||
-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> ............. compression method (0=fast, 6=slowest), default=4
|
||||
-exact, -noexact ..... preserve or alter RGB values in transparent area
|
||||
(default: -noexact, may cause artifacts
|
||||
with lossy animations)
|
||||
```
|
||||
|
||||
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
|
||||
-near_lossless <int> ... use near-lossless image preprocessing
|
||||
(0..100=off), default=100
|
||||
-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
|
||||
(lossy only)
|
||||
-q <float> ............. quality factor (0:small..100:big)
|
||||
-m <int> ............... compression method (0=fast, 6=slowest), default=4
|
||||
-min_size .............. minimize output size (default:off)
|
||||
lossless compression by default; can be
|
||||
combined with -q, -m, -lossy or -mixed
|
||||
options
|
||||
-kmin <int> ............ min distance between key frames
|
||||
-kmax <int> ............ max distance between key frames
|
||||
-f <int> ............... filter strength (0=off..100)
|
||||
-metadata <string> ..... comma separated list of metadata to
|
||||
copy from the input to the output if present
|
||||
Valid values: all, none, icc, xmp (default)
|
||||
-loop_compatibility .... use compatibility mode for Chrome
|
||||
version prior to M62 (inclusive)
|
||||
-mt .................... use multi-threading if available
|
||||
|
||||
-version ............... print version number and exit
|
||||
-v ..................... verbose
|
||||
-quiet ................. don't print anything
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
With the libgif development files installed, gif2webp can be built using
|
||||
makefile.unix:
|
||||
|
||||
```shell
|
||||
$ make -f makefile.unix examples/gif2webp
|
||||
```
|
||||
|
||||
or using autoconf:
|
||||
|
||||
```shell
|
||||
$ ./configure --enable-everything
|
||||
$ make
|
||||
```
|
||||
|
||||
## Comparison of animated images
|
||||
|
||||
Test utility anim_diff under examples/ can be used to compare two animated
|
||||
images (each can be GIF or WebP).
|
||||
|
||||
Usage:
|
||||
|
||||
```shell
|
||||
anim_diff <image1> <image2> [options]
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
```
|
||||
-dump_frames <folder> dump decoded frames in PAM format
|
||||
-min_psnr <float> ... minimum per-frame PSNR
|
||||
-raw_comparison ..... if this flag is not used, RGB is
|
||||
premultiplied before comparison
|
||||
-max_diff <int> ..... maximum allowed difference per channel
|
||||
between corresponding pixels in subsequent
|
||||
frames
|
||||
-h .................. this help
|
||||
-version ............ print version number and exit
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
With the libgif development files installed, anim_diff can be built using
|
||||
makefile.unix:
|
||||
|
||||
```shell
|
||||
$ make -f makefile.unix examples/anim_diff
|
||||
```
|
||||
|
||||
or using autoconf:
|
||||
|
||||
```shell
|
||||
$ ./configure --enable-everything
|
||||
$ make
|
||||
```
|
||||
|
||||
## WebP Mux tool
|
||||
|
||||
The examples/ directory contains a tool (webpmux) for manipulating WebP files.
|
||||
The webpmux tool can be used to create an extended format WebP file and also to
|
||||
extract or strip relevant data from such a file.
|
||||
|
||||
A list of options is available using the -help command line flag:
|
||||
|
||||
```shell
|
||||
> webpmux -help
|
||||
Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
|
||||
webpmux -set SET_OPTIONS INPUT -o OUTPUT
|
||||
webpmux -duration DURATION_OPTIONS [-duration ...]
|
||||
INPUT -o OUTPUT
|
||||
webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
|
||||
webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
|
||||
[-bgcolor BACKGROUND_COLOR] -o OUTPUT
|
||||
webpmux -info INPUT
|
||||
webpmux [-h|-help]
|
||||
webpmux -version
|
||||
webpmux argument_file_name
|
||||
|
||||
GET_OPTIONS:
|
||||
Extract relevant data:
|
||||
icc get ICC profile
|
||||
exif get EXIF metadata
|
||||
xmp get XMP metadata
|
||||
frame n get nth frame
|
||||
|
||||
SET_OPTIONS:
|
||||
Set color profile/metadata/parameters:
|
||||
loop LOOP_COUNT set the loop count
|
||||
bgcolor BACKGROUND_COLOR set the animation background color
|
||||
icc file.icc set ICC profile
|
||||
exif file.exif set EXIF metadata
|
||||
xmp file.xmp set XMP metadata
|
||||
where: 'file.icc' contains the ICC profile to be set,
|
||||
'file.exif' contains the EXIF metadata to be set
|
||||
'file.xmp' contains the XMP metadata to be set
|
||||
|
||||
DURATION_OPTIONS:
|
||||
Set duration of selected frames:
|
||||
duration set duration for all frames
|
||||
duration,frame set duration of a particular frame
|
||||
duration,start,end set duration of frames in the
|
||||
interval [start,end])
|
||||
where: 'duration' is the duration in milliseconds
|
||||
'start' is the start frame index
|
||||
'end' is the inclusive end frame index
|
||||
The special 'end' value '0' means: last frame.
|
||||
|
||||
STRIP_OPTIONS:
|
||||
Strip color profile/metadata:
|
||||
icc strip ICC profile
|
||||
exif strip EXIF metadata
|
||||
xmp strip XMP metadata
|
||||
|
||||
FRAME_OPTIONS(i):
|
||||
Create animation:
|
||||
file_i +di[+xi+yi[+mi[bi]]]
|
||||
where: 'file_i' is the i'th animation frame (WebP format),
|
||||
'di' is the pause duration before next frame,
|
||||
'xi','yi' specify the image offset for this frame,
|
||||
'mi' is the dispose method for this frame (0 or 1),
|
||||
'bi' is the blending method for this frame (+b or -b)
|
||||
|
||||
LOOP_COUNT:
|
||||
Number of times to repeat the animation.
|
||||
Valid range is 0 to 65535 [Default: 0 (infinite)].
|
||||
|
||||
BACKGROUND_COLOR:
|
||||
Background color of the canvas.
|
||||
A,R,G,B
|
||||
where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying
|
||||
the Alpha, Red, Green and Blue component values respectively
|
||||
[Default: 255,255,255,255]
|
||||
|
||||
INPUT & OUTPUT are in WebP format.
|
||||
|
||||
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
|
||||
valid.
|
||||
|
||||
Note: if a single file name is passed as the argument, the arguments will be
|
||||
tokenized from this file. The file name must not start with the character '-'.
|
||||
```
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
Although you may be viewing an alternate representation, this document
|
||||
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
|
||||
at the end of this file.
|
||||
See the accompanying README. External link targets are referenced at the
|
||||
end of this file.
|
||||
|
||||
-->
|
||||
|
||||
@@ -20,48 +20,50 @@ WebP Container Specification
|
||||
Introduction
|
||||
------------
|
||||
|
||||
WebP is an image format that uses either (i) the VP8 key frame encoding to
|
||||
compress image data in a lossy way or (ii) the WebP lossless encoding. These
|
||||
encoding schemes should make it more efficient than older formats, such as JPEG,
|
||||
GIF, and PNG. It is optimized for fast image transfer over the network (for
|
||||
example, for websites). The WebP format has feature parity (color profile,
|
||||
metadata, animation, etc.) with other formats as well. This document describes
|
||||
the structure of a WebP file.
|
||||
WebP is an image format that uses either (i) the VP8 key frame encoding
|
||||
to compress image data in a lossy way, or (ii) the WebP lossless encoding
|
||||
(and possibly other encodings in the future). These encoding schemes should
|
||||
make it more efficient than currently used formats. It is optimized for fast
|
||||
image transfer over the network (e.g., for websites). The WebP format has
|
||||
feature parity (color profile, metadata, animation etc) with other formats as
|
||||
well. This document describes the structure of a WebP file.
|
||||
|
||||
The WebP container (that is, the RIFF container for WebP) allows feature support
|
||||
over and above the basic use case of WebP (that is, a file containing a single
|
||||
image encoded as a VP8 key frame). The WebP container provides additional
|
||||
support for the following:
|
||||
The WebP container (i.e., RIFF container for WebP) allows feature support over
|
||||
and above the basic use case of WebP (i.e., a file containing a single image
|
||||
encoded as a VP8 key frame). The WebP container provides additional support
|
||||
for:
|
||||
|
||||
* Lossless Compression: An image can be losslessly compressed, using the
|
||||
* **Lossless compression.** An image can be losslessly compressed, using the
|
||||
WebP Lossless Format.
|
||||
|
||||
* Metadata: An image may have metadata stored in Exchangeable Image File
|
||||
Format (Exif) or Extensible Metadata Platform (XMP) format.
|
||||
* **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].
|
||||
|
||||
* 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.
|
||||
|
||||
Terminology & Basics
|
||||
--------------------
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][]
|
||||
when, and only when, they appear in all capitals, as shown here.
|
||||
|
||||
A WebP file contains either a still image (that is, an encoded matrix of pixels)
|
||||
or an [animation](#animation). Optionally, it can also contain transparency
|
||||
information, a color profile and metadata. We refer to the matrix of pixels as
|
||||
the _canvas_ of the image.
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [RFC 2119][].
|
||||
|
||||
Bit numbering in chunk diagrams starts at `0` for the most significant bit
|
||||
('MSB 0'), as described in [RFC 1166][].
|
||||
('MSB 0') as described in [RFC 1166][].
|
||||
|
||||
**Note:** Out of the features mentioned above, lossy compression, lossless
|
||||
compression, transparency, metadata, color profile and animation are finalized
|
||||
and are to be considered stable.
|
||||
|
||||
Terminology & Basics
|
||||
------------------------
|
||||
|
||||
A WebP file contains either a still image (i.e., an encoded matrix of pixels)
|
||||
or an [animation](#animation). Optionally, it can also contain transparency
|
||||
information, color profile and metadata. In case we need to refer only to the
|
||||
matrix of pixels, we will call it the _canvas_ of the image.
|
||||
|
||||
Below are additional terms used throughout this document:
|
||||
|
||||
@@ -84,25 +86,19 @@ _uint32_
|
||||
|
||||
_FourCC_
|
||||
|
||||
: A four-character code (FourCC) is a _uint32_ created by concatenating four
|
||||
ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and
|
||||
'AAAA' (0x41414141) are treated as different _FourCCs_.
|
||||
: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
|
||||
ASCII characters in little-endian order.
|
||||
|
||||
_1-based_
|
||||
|
||||
: An unsigned integer field storing values offset by `-1`, for example, such a
|
||||
field would store value _25_ as _24_.
|
||||
|
||||
_ChunkHeader('ABCD')_
|
||||
|
||||
: 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.
|
||||
: An unsigned integer field storing values offset by `-1`. e.g., Such a field
|
||||
would store value _25_ as _24_.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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 Payload :
|
||||
| Chunk Payload |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Chunk FourCC: 32 bits
|
||||
@@ -123,15 +119,21 @@ Chunk FourCC: 32 bits
|
||||
|
||||
Chunk Size: 32 bits (_uint32_)
|
||||
|
||||
: The size of the chunk in bytes, not including this field, the chunk
|
||||
identifier, or padding.
|
||||
: The size of the chunk not including this field, the chunk identifier or
|
||||
padding.
|
||||
|
||||
Chunk Payload: _Chunk Size_ bytes
|
||||
|
||||
: The data payload. If _Chunk Size_ is odd, a single padding byte -- which MUST
|
||||
be `0` to conform with RIFF -- is added.
|
||||
: The data payload. If _Chunk Size_ is odd, a single padding byte -- that
|
||||
SHOULD be `0` -- is added.
|
||||
|
||||
**Note**: RIFF has a convention that all-uppercase chunk FourCCs are standard
|
||||
_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
|
||||
chunks that apply to any RIFF file format, while FourCCs specific to a file
|
||||
format are all lowercase. WebP does not follow this convention.
|
||||
|
||||
@@ -151,25 +153,23 @@ WebP File Header
|
||||
|
||||
'RIFF': 32 bits
|
||||
|
||||
: The ASCII characters 'R', 'I', 'F', 'F'.
|
||||
: The ASCII characters 'R' 'I' 'F' 'F'.
|
||||
|
||||
File Size: 32 bits (_uint32_)
|
||||
|
||||
: The size of the file in bytes, starting at offset 8. The maximum value of
|
||||
: The size of the file in bytes starting at offset 8. The maximum value of
|
||||
this field is 2^32 minus 10 bytes and thus the size of the whole file is at
|
||||
most 4 GiB minus 2 bytes.
|
||||
most 4GiB minus 2 bytes.
|
||||
|
||||
'WEBP': 32 bits
|
||||
|
||||
: The ASCII characters 'W', 'E', 'B', 'P'.
|
||||
: The ASCII characters 'W' 'E' 'B' 'P'.
|
||||
|
||||
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
|
||||
in the header is the total size of the chunks that follow plus `4` bytes for
|
||||
the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data
|
||||
specified by _File Size_. Readers MAY parse such files, ignoring the trailing
|
||||
data. As the size of any chunk is even, the size given by the RIFF header is
|
||||
also even. The contents of individual chunks are described in the following
|
||||
sections.
|
||||
the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
|
||||
of any chunk is even, the size given by the RIFF header is also even. The
|
||||
contents of individual chunks will be described in the following sections.
|
||||
|
||||
|
||||
Simple File Format (Lossy)
|
||||
@@ -184,43 +184,37 @@ Simple WebP (lossy) file format:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| WebP file header (12 bytes) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: 'VP8 ' Chunk :
|
||||
| VP8 chunk |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
'VP8 ' Chunk:
|
||||
VP8 chunk:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('VP8 ') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: VP8 data :
|
||||
| VP8 data |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
VP8 data: _Chunk Size_ bytes
|
||||
|
||||
: VP8 bitstream data.
|
||||
|
||||
Note that the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
|
||||
|
||||
The VP8 bitstream format specification is described in [VP8 Data Format and
|
||||
Decoding Guide][rfc 6386]. Note that the VP8 frame header contains the VP8 frame
|
||||
The VP8 bitstream format specification can be found at [VP8 Data Format and
|
||||
Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
|
||||
width and height. That is assumed to be the width and height of the canvas.
|
||||
|
||||
The VP8 specification describes how to decode the image into Y'CbCr format. To
|
||||
convert to RGB, [Recommendation BT.601][rec601] SHOULD be used. Applications MAY
|
||||
use another conversion method, but visual results may differ among decoders.
|
||||
The VP8 specification describes how to decode the image into Y'CbCr
|
||||
format. To convert to RGB, Rec. 601 SHOULD be used.
|
||||
|
||||
|
||||
Simple File Format (Lossless)
|
||||
-----------------------------
|
||||
|
||||
**Note**: Older readers may not support files using the lossless format.
|
||||
**Note:** Older readers may not support files using the lossless format.
|
||||
|
||||
This layout SHOULD be used if the image requires _lossless_ encoding (with an
|
||||
optional transparency channel) and does not require advanced features provided
|
||||
@@ -231,22 +225,19 @@ Simple WebP (lossless) file format:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| WebP file header (12 bytes) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: 'VP8L' Chunk :
|
||||
| VP8L chunk |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
'VP8L' Chunk:
|
||||
VP8L chunk:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('VP8L') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: VP8L data :
|
||||
| VP8L data |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
VP8L data: _Chunk Size_ bytes
|
||||
@@ -262,23 +253,23 @@ and height of the canvas.
|
||||
Extended File Format
|
||||
--------------------
|
||||
|
||||
**Note**: Older readers may not support files using the extended format.
|
||||
**Note:** Older readers may not support files using the extended format.
|
||||
|
||||
An extended format file consists of:
|
||||
|
||||
* A 'VP8X' Chunk with information about features used in the file.
|
||||
* A 'VP8X' chunk with information about features used in the file.
|
||||
|
||||
* An optional 'ICCP' Chunk with a color profile.
|
||||
* An optional 'ICCP' chunk with color profile.
|
||||
|
||||
* An optional 'ANIM' Chunk with animation control data.
|
||||
* An optional 'ANIM' chunk with animation control 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
|
||||
up of:
|
||||
@@ -290,18 +281,15 @@ up of:
|
||||
For an _animated image_, the _image data_ consists of multiple frames. More
|
||||
details about frames can be found in the [Animation](#animation) section.
|
||||
|
||||
All chunks necessary for reconstruction and color correction, that is, 'VP8X',
|
||||
'ICCP', 'ANIM', 'ANMF', 'ALPH', 'VP8 ', and 'VP8L', MUST appear in the order
|
||||
described earlier. Readers SHOULD fail when chunks necessary for reconstruction
|
||||
and color correction are out of order.
|
||||
All chunks SHOULD be placed in the same order as listed above. If a chunk
|
||||
appears in the wrong place, the file is invalid, but readers MAY parse the
|
||||
file, ignoring the chunks that come too late.
|
||||
|
||||
[Metadata](#metadata) and [unknown chunks](#unknown-chunks) MAY appear out of
|
||||
order.
|
||||
|
||||
**Rationale:** The chunks necessary for reconstruction should appear first in
|
||||
the file to allow a reader to begin decoding an image before receiving all of
|
||||
the data. An application may benefit from varying the order of metadata and
|
||||
custom chunks to suit the implementation.
|
||||
**Rationale:** Setting the order of chunks should allow quicker file
|
||||
parsing. For example, if an 'ALPH' chunk does not appear in its required
|
||||
position, a decoder can choose to stop searching for it. The rule of
|
||||
ignoring late chunks should make programs that need to do a full search
|
||||
give the same results as the ones stopping early.
|
||||
|
||||
Extended WebP file header:
|
||||
{:#extended_header}
|
||||
@@ -309,12 +297,9 @@ Extended WebP file header:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| WebP file header (12 bytes) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('VP8X') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|Rsv|I|L|E|X|A|R| Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -325,20 +310,20 @@ Extended WebP file header:
|
||||
|
||||
Reserved (Rsv): 2 bits
|
||||
|
||||
: MUST be `0`. Readers MUST ignore this field.
|
||||
: SHOULD be `0`.
|
||||
|
||||
ICC profile (I): 1 bit
|
||||
|
||||
: Set if the file contains an 'ICCP' Chunk.
|
||||
: Set if the file contains an ICC profile.
|
||||
|
||||
Alpha (L): 1 bit
|
||||
|
||||
: Set if any of the frames of the image contain transparency information
|
||||
("alpha").
|
||||
|
||||
Exif metadata (E): 1 bit
|
||||
EXIF metadata (E): 1 bit
|
||||
|
||||
: Set if the file contains Exif metadata.
|
||||
: Set if the file contains EXIF metadata.
|
||||
|
||||
XMP metadata (X): 1 bit
|
||||
|
||||
@@ -346,38 +331,38 @@ XMP metadata (X): 1 bit
|
||||
|
||||
Animation (A): 1 bit
|
||||
|
||||
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' Chunks should be
|
||||
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
|
||||
used to control the animation.
|
||||
|
||||
Reserved (R): 1 bit
|
||||
|
||||
: MUST be `0`. Readers MUST ignore this field.
|
||||
: SHOULD be `0`.
|
||||
|
||||
Reserved: 24 bits
|
||||
|
||||
: MUST be `0`. Readers MUST ignore this field.
|
||||
: SHOULD be `0`.
|
||||
|
||||
Canvas Width Minus One: 24 bits
|
||||
|
||||
: _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
|
||||
|
||||
: _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`.
|
||||
|
||||
Future specifications may add more fields. Unknown fields MUST be ignored.
|
||||
Future specifications MAY add more fields.
|
||||
|
||||
### Chunks
|
||||
|
||||
#### Animation
|
||||
|
||||
An animation is controlled by 'ANIM' and 'ANMF' Chunks.
|
||||
An animation is controlled by ANIM and ANMF chunks.
|
||||
|
||||
'ANIM' Chunk:
|
||||
ANIM Chunk:
|
||||
{:#anim_chunk}
|
||||
|
||||
For an animated image, this chunk contains the _global parameters_ of the
|
||||
@@ -387,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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('ANIM') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Background Color |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -399,14 +383,14 @@ Background Color: 32 bits (_uint32_)
|
||||
: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
|
||||
byte order. This color MAY be used to fill the unused space on the canvas
|
||||
around the frames, as well as the transparent pixels of the first frame.
|
||||
The background color is also used when the Disposal method is `1`.
|
||||
Background color is also used when disposal method is `1`.
|
||||
|
||||
**Notes**:
|
||||
**Note**:
|
||||
|
||||
* The background color MAY contain a non-opaque alpha value, even if the
|
||||
_Alpha_ flag in the ['VP8X' Chunk](#extended_header) is unset.
|
||||
* Background color MAY contain a transparency value (alpha), even if the
|
||||
_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.
|
||||
|
||||
* The canvas is cleared at the start of each loop. The background color MAY be
|
||||
@@ -414,14 +398,13 @@ Background Color: 32 bits (_uint32_)
|
||||
|
||||
Loop Count: 16 bits (_uint16_)
|
||||
|
||||
: The number of times to loop the animation. If it is `0`, this 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.
|
||||
If the _Animation_ flag is not set and this chunk is present, it MUST be
|
||||
ignored.
|
||||
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
|
||||
SHOULD be ignored.
|
||||
|
||||
'ANMF' Chunk:
|
||||
ANMF chunk:
|
||||
|
||||
For animated images, this chunk contains information about a _single_ frame.
|
||||
If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
|
||||
@@ -430,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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('ANMF') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Frame X | ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -440,47 +422,46 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Frame Duration | Reserved |B|D|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: Frame Data :
|
||||
| Frame Data |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
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_)
|
||||
|
||||
: 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_)
|
||||
|
||||
: 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_)
|
||||
|
||||
: 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_)
|
||||
|
||||
: The time to wait before displaying the next frame, in 1-millisecond units.
|
||||
Note that the interpretation of the Frame Duration of 0 (and often <= 10) is
|
||||
defined by the implementation. Many tools and browsers assign a minimum
|
||||
duration similar to GIF.
|
||||
: The time to wait before displaying the next frame, in 1 millisecond units.
|
||||
In particular, frame duration of 0 is useful when one wants to update
|
||||
multiple areas of the canvas at once during the animation.
|
||||
|
||||
Reserved: 6 bits
|
||||
|
||||
: MUST be `0`. Readers MUST ignore this field.
|
||||
: SHOULD be 0.
|
||||
|
||||
Blending method (B): 1 bit
|
||||
|
||||
: Indicates how transparent pixels of _the current frame_ are to be blended
|
||||
with corresponding pixels of the previous canvas:
|
||||
|
||||
* `0`: Use alpha-blending. After disposing of the previous frame, render the
|
||||
* `0`: Use alpha blending. After disposing of the previous frame, render the
|
||||
current frame on the canvas using [alpha-blending](#alpha-blending). If
|
||||
the current frame does not have an alpha channel, assume the alpha value
|
||||
is 255, effectively replacing the rectangle.
|
||||
the current frame does not have an alpha channel, assume alpha value of
|
||||
255, effectively replacing the rectangle.
|
||||
|
||||
* `1`: Do not blend. After disposing of the previous frame, render the
|
||||
current frame on the canvas by overwriting the rectangle covered by the
|
||||
@@ -493,20 +474,20 @@ Disposal method (D): 1 bit
|
||||
|
||||
* `0`: Do not dispose. Leave the canvas as is.
|
||||
|
||||
* `1`: Dispose to the background color. Fill the _rectangle_ on the canvas
|
||||
covered by the _current frame_ with the background color specified in the
|
||||
['ANIM' Chunk](#anim_chunk).
|
||||
* `1`: Dispose to background color. Fill the _rectangle_ on the canvas
|
||||
covered by the _current frame_ with background color specified in the
|
||||
[ANIM chunk](#anim_chunk).
|
||||
|
||||
**Notes**:
|
||||
|
||||
* The frame disposal only applies to the _frame rectangle_, that is, the
|
||||
rectangle defined by _Frame X_, _Frame Y_, _frame width_, and _frame
|
||||
height_. It may or may not cover the whole canvas.
|
||||
rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
|
||||
It may or may not cover the whole canvas.
|
||||
|
||||
{:#alpha-blending}
|
||||
* Alpha-blending:
|
||||
* **Alpha-blending**:
|
||||
|
||||
Given that each of the R, G, B, and A channels is 8 bits, and the RGB
|
||||
Given that each of the R, G, B and A channels is 8-bit, and the RGB
|
||||
channels are _not premultiplied_ by alpha, the formula for blending
|
||||
'dst' onto 'src' is:
|
||||
|
||||
@@ -515,17 +496,16 @@ Disposal method (D): 1 bit
|
||||
if blend.A = 0 then
|
||||
blend.RGB = 0
|
||||
else
|
||||
blend.RGB =
|
||||
(src.RGB * src.A +
|
||||
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
|
||||
blend.RGB = (src.RGB * src.A +
|
||||
dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
|
||||
~~~~~
|
||||
|
||||
* Alpha-blending SHOULD be done in linear color space, by taking into account
|
||||
the [color profile](#color-profile) of the image. If the color profile is
|
||||
not present, standard RGB (sRGB) is to be assumed. (Note that sRGB also
|
||||
needs to be linearized due to a gamma of ~2.2.)
|
||||
not present, sRGB is to be assumed. (Note that sRGB also needs to be
|
||||
linearized due to a gamma of ~2.2).
|
||||
|
||||
Frame Data: _Chunk Size_ bytes - `16`
|
||||
Frame Data: _Chunk Size_ - `16` bytes
|
||||
|
||||
: Consists of:
|
||||
|
||||
@@ -535,8 +515,8 @@ Frame Data: _Chunk Size_ bytes - `16`
|
||||
|
||||
* An optional list of [unknown chunks](#unknown-chunks).
|
||||
|
||||
**Note**: The 'ANMF' payload, _Frame Data_, consists of individual
|
||||
_padded_ chunks, as described by the [RIFF file format](#riff-file-format).
|
||||
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
|
||||
_padded_ chunks as described by the [RIFF file format](#riff-file-format).
|
||||
|
||||
#### Alpha
|
||||
|
||||
@@ -544,29 +524,26 @@ _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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('ALPH') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|Rsv| P | F | C | Alpha Bitstream... |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Reserved (Rsv): 2 bits
|
||||
|
||||
: MUST be `0`. Readers MUST ignore this field.
|
||||
: SHOULD be `0`.
|
||||
|
||||
Preprocessing (P): 2 bits
|
||||
Pre-processing (P): 2 bits
|
||||
|
||||
: These _informative_ bits are used to signal the preprocessing 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
|
||||
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 preprocessing.
|
||||
* `1`: Level reduction.
|
||||
|
||||
Decoders are not required to use this information in any specified way.
|
||||
* `0`: no pre-processing
|
||||
* `1`: level reduction
|
||||
|
||||
Filtering method (F): 2 bits
|
||||
|
||||
: The filtering methods used are described as follows:
|
||||
: The filtering method used:
|
||||
|
||||
* `0`: None.
|
||||
* `1`: Horizontal filter.
|
||||
@@ -590,25 +567,27 @@ made depending on the filtering method:
|
||||
|
||||
where `clip(v)` is equal to:
|
||||
|
||||
* 0 if v < 0,
|
||||
* 255 if v > 255, or
|
||||
* 0 if v < 0
|
||||
* 255 if v > 255
|
||||
* v otherwise
|
||||
|
||||
The final value is derived by adding the decompressed value `X` to the
|
||||
predictor and using modulo-256 arithmetic to wrap the \[256..511\] range
|
||||
into the \[0..255\] one:
|
||||
predictor and using modulo-256 arithmetic to wrap the \[256-511\] range
|
||||
into the \[0-255\] one:
|
||||
|
||||
`alpha = (predictor + X) % 256`
|
||||
|
||||
There are special cases for the left-most and top-most pixel positions. For
|
||||
example, the top-left value at location (0, 0) uses 0 as the predictor value.
|
||||
Otherwise:
|
||||
There are special cases for left-most and top-most pixel positions:
|
||||
|
||||
* Top-left value at location (0,0) uses 0 as predictor value. Otherwise,
|
||||
* For horizontal or gradient filtering methods, the left-most pixels at
|
||||
location (0, y) are predicted using the location (0, y-1) just above.
|
||||
* For vertical or gradient filtering methods, the top-most pixels at
|
||||
location (x, 0) are predicted using the location (x-1, 0) on the left.
|
||||
|
||||
|
||||
Decoders are not required to use this information in any specified way.
|
||||
|
||||
Compression method (C): 2 bits
|
||||
|
||||
: The compression method used:
|
||||
@@ -616,37 +595,37 @@ Compression method (C): 2 bits
|
||||
* `0`: No compression.
|
||||
* `1`: Compressed using the WebP lossless format.
|
||||
|
||||
Alpha bitstream: _Chunk Size_ bytes - `1`
|
||||
Alpha bitstream: _Chunk Size_ - `1` bytes
|
||||
|
||||
: Encoded alpha bitstream.
|
||||
|
||||
This optional chunk contains encoded alpha data for this frame. A frame
|
||||
containing a 'VP8L' Chunk SHOULD NOT contain this chunk.
|
||||
containing a 'VP8L' chunk SHOULD NOT contain this chunk.
|
||||
|
||||
**Rationale**: The transparency information is already part of the 'VP8L'
|
||||
Chunk.
|
||||
chunk.
|
||||
|
||||
The alpha channel data is stored as uncompressed raw data (when the
|
||||
The alpha channel data is stored as uncompressed raw data (when
|
||||
compression method is '0') or compressed using the lossless format
|
||||
(when the compression method is '1').
|
||||
|
||||
* Raw data: This consists of a byte sequence of length = width * height,
|
||||
* Raw data: consists of a byte sequence of length width * height,
|
||||
containing all the 8-bit transparency values in scan order.
|
||||
|
||||
* Lossless format compression: The byte sequence is a compressed
|
||||
image-stream (as described in ["WebP Lossless Bitstream Format"]
|
||||
[webpllspec]) of implicit dimensions width x height. That is, this
|
||||
image-stream does NOT contain any headers describing the image dimensions.
|
||||
* Lossless format compression: the byte sequence is a compressed
|
||||
image-stream (as described in the [WebP Lossless Bitstream Format]
|
||||
[webpllspec]) of implicit dimension width x height. That is, this
|
||||
image-stream does NOT contain any headers describing the image dimension.
|
||||
|
||||
**Rationale**: The dimensions are already known from other sources,
|
||||
so storing them again would be redundant and prone to error.
|
||||
**Rationale**: the dimension is already known from other sources,
|
||||
so storing it again would be redundant and error-prone.
|
||||
|
||||
Once the image-stream is decoded into Alpha, Red, Green, Blue (ARGB) color
|
||||
values, following the process described in the lossless format
|
||||
specification, the transparency information must be extracted from the
|
||||
*green* channel of the ARGB quadruplet.
|
||||
Once the image-stream is decoded into ARGB color values, following
|
||||
the process described in the lossless format specification, the
|
||||
transparency information must be extracted from the *green* channel
|
||||
of the ARGB quadruplet.
|
||||
|
||||
**Rationale**: The green channel is allowed extra transformation
|
||||
**Rationale**: the green channel is allowed extra transformation
|
||||
steps in the specification -- unlike the other channels -- that can
|
||||
improve compression.
|
||||
|
||||
@@ -654,23 +633,22 @@ compression method is '0') or compressed using the lossless format
|
||||
|
||||
This chunk contains compressed bitstream data for a single frame.
|
||||
|
||||
A bitstream chunk may be either (i) a 'VP8 ' Chunk, using 'VP8 ' (note the
|
||||
significant fourth-character space) as its FourCC, _or_ (ii) a 'VP8L' Chunk,
|
||||
using 'VP8L' as its FourCC.
|
||||
A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
|
||||
significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
|
||||
"VP8L" as its tag.
|
||||
|
||||
The formats of 'VP8 ' and 'VP8L' Chunks are as described in sections
|
||||
The formats of VP8 and VP8L chunks are as described in sections
|
||||
[Simple File Format (Lossy)](#simple-file-format-lossy)
|
||||
and [Simple File Format (Lossless)](#simple-file-format-lossless), respectively.
|
||||
and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively.
|
||||
|
||||
#### Color Profile
|
||||
#### Color profile
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('ICCP') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: Color Profile :
|
||||
| Color Profile |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Color Profile: _Chunk Size_ bytes
|
||||
@@ -687,145 +665,114 @@ If this chunk is not present, sRGB SHOULD be assumed.
|
||||
|
||||
#### Metadata
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
'EXIF' Chunk:
|
||||
EXIF chunk:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('EXIF') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: Exif Metadata :
|
||||
| EXIF Metadata |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Exif Metadata: _Chunk Size_ bytes
|
||||
EXIF Metadata: _Chunk Size_ bytes
|
||||
|
||||
: Image metadata in Exif format.
|
||||
: image metadata in EXIF format.
|
||||
|
||||
'XMP ' Chunk:
|
||||
XMP chunk:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ChunkHeader('XMP ') |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
: XMP Metadata :
|
||||
| XMP Metadata |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
XMP Metadata: _Chunk Size_ bytes
|
||||
|
||||
: Image metadata in XMP format.
|
||||
|
||||
Note that the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
|
||||
: image metadata in XMP format.
|
||||
|
||||
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 the [RIFF File Format](#riff-file-format) section)
|
||||
whose FourCC is different from any of the chunks described in this document, is
|
||||
A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
|
||||
tag_ is different from any of the chunks described in this document, is
|
||||
considered an _unknown chunk_.
|
||||
|
||||
**Rationale**: Allowing unknown chunks gives a provision for future extension
|
||||
of the format and also allows storage of any application-specific data.
|
||||
of the format, and also allows storage of any application-specific data.
|
||||
|
||||
A file MAY contain unknown chunks:
|
||||
|
||||
* at the end of the file, as described in [Extended WebP file
|
||||
header](#extended_header) section, or
|
||||
* at the end of 'ANMF' Chunks, as described in the
|
||||
* At the end of the file as described in [Extended WebP file
|
||||
header](#extended_header) section.
|
||||
* At the end of ANMF chunks as described in the
|
||||
[Animation](#animation) section.
|
||||
|
||||
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
|
||||
original order (unless they specifically intend to modify these chunks).
|
||||
|
||||
### Canvas Assembly from Frames
|
||||
### Assembling the Canvas from frames
|
||||
|
||||
Here we provide an overview of how a reader MUST assemble a canvas in the case
|
||||
of an animated image.
|
||||
Here we provide an overview of how a reader should assemble a canvas in the
|
||||
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
|
||||
'VP8X' Chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus
|
||||
One + 1` pixels high. The `Loop Count` field from the 'ANIM' Chunk controls how
|
||||
many times the animation process is repeated. This is `Loop Count - 1` for
|
||||
nonzero `Loop Count` values or infinite if the `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.
|
||||
Displaying an _animated image_ canvas MUST be equivalent to the following
|
||||
pseudocode:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
VP8X.flags.hasAnimation MUST be TRUE
|
||||
assert VP8X.flags.hasAnimation
|
||||
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
|
||||
background color ANIM.background_color or
|
||||
application-defined color.
|
||||
background color ANIM.background_color.
|
||||
loop_count ← ANIM.loopCount
|
||||
dispose_method ← Dispose to background color
|
||||
dispose_method ← ANIM.disposeMethod
|
||||
if loop_count == 0:
|
||||
loop_count = ∞
|
||||
loop_count = ∞
|
||||
frame_params ← nil
|
||||
next chunk in image_data is ANMF MUST be TRUE
|
||||
assert next chunk in image_data is ANMF
|
||||
for loop = 0..loop_count - 1
|
||||
clear canvas to ANIM.background_color or application-defined color
|
||||
until eof or non-ANMF chunk
|
||||
frame_params.frameX = Frame X
|
||||
frame_params.frameY = Frame Y
|
||||
frame_params.frameWidth = Frame Width Minus One + 1
|
||||
frame_params.frameHeight = Frame Height Minus One + 1
|
||||
frame_params.frameDuration = Frame Duration
|
||||
frame_right = frame_params.frameX + frame_params.frameWidth
|
||||
frame_bottom = frame_params.frameY + frame_params.frameHeight
|
||||
VP8X.canvasWidth >= frame_right MUST be TRUE
|
||||
VP8X.canvasHeight >= frame_bottom MUST be TRUE
|
||||
for subchunk in 'Frame Data':
|
||||
if subchunk.tag == "ALPH":
|
||||
alpha subchunks not found in 'Frame Data' earlier MUST be
|
||||
TRUE
|
||||
frame_params.alpha = alpha_data
|
||||
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
|
||||
bitstream subchunks not found in 'Frame Data' earlier MUST
|
||||
be TRUE
|
||||
frame_params.bitstream = bitstream_data
|
||||
apply dispose_method.
|
||||
render frame with frame_params.alpha and frame_params.bitstream
|
||||
on canvas with top-left corner at (frame_params.frameX,
|
||||
frame_params.frameY), using Blending method
|
||||
frame_params.blendingMethod.
|
||||
canvas contains the decoded image.
|
||||
Show the contents of the canvas for
|
||||
frame_params.frameDuration * 1 ms.
|
||||
dispose_method = frame_params.disposeMethod
|
||||
clear canvas to ANIM.background_color or application defined color
|
||||
until eof or non-ANMF chunk
|
||||
frame_params.frameX = Frame X
|
||||
frame_params.frameY = Frame Y
|
||||
frame_params.frameWidth = Frame Width Minus One + 1
|
||||
frame_params.frameHeight = Frame Height Minus One + 1
|
||||
frame_params.frameDuration = Frame Duration
|
||||
frame_right = frame_params.frameX + frame_params.frameWidth
|
||||
frame_bottom = frame_params.frameY + frame_params.frameHeight
|
||||
assert VP8X.canvasWidth >= frame_right
|
||||
assert VP8X.canvasHeight >= frame_bottom
|
||||
for subchunk in 'Frame Data':
|
||||
if subchunk.tag == "ALPH":
|
||||
assert alpha subchunks not found in 'Frame Data' earlier
|
||||
frame_params.alpha = alpha_data
|
||||
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
|
||||
assert bitstream subchunks not found in 'Frame Data' earlier
|
||||
frame_params.bitstream = bitstream_data
|
||||
render frame with frame_params.alpha and frame_params.bitstream on
|
||||
canvas with top-left corner at (frame_params.frameX,
|
||||
frame_params.frameY), using dispose method dispose_method.
|
||||
canvas contains the decoded image.
|
||||
Show the contents of the canvas for frame_params.frameDuration * 1ms.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
Example File Layouts
|
||||
--------------------
|
||||
|
||||
A lossy-encoded image with alpha may look as follows:
|
||||
A lossy encoded image with alpha may look as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
RIFF/WEBP
|
||||
@@ -834,16 +781,16 @@ RIFF/WEBP
|
||||
+- VP8 (bitstream)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A lossless-encoded image may look as follows:
|
||||
A losslessly encoded image may look as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
RIFF/WEBP
|
||||
+- VP8X (descriptions of features used)
|
||||
+- VP8L (lossless bitstream)
|
||||
+- XYZW (unknown chunk)
|
||||
+- VP8L (lossless bitstream)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A lossless image with an ICC profile and XMP metadata may
|
||||
A lossless image with ICC profile and XMP metadata may
|
||||
look as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -854,7 +801,7 @@ RIFF/WEBP
|
||||
+- XMP (metadata)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An animated image with Exif metadata may look as follows:
|
||||
An animated image with EXIF metadata may look as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
RIFF/WEBP
|
||||
@@ -867,11 +814,9 @@ RIFF/WEBP
|
||||
+- EXIF (metadata)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
|
||||
[iccspec]: https://www.color.org/icc_specs2.xalter
|
||||
[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
||||
[rec601]: https://www.itu.int/rec/R-REC-BT.601
|
||||
[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166
|
||||
[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119
|
||||
[rfc 6386]: https://datatracker.ietf.org/doc/html/rfc6386
|
||||
[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174
|
||||
[vp8spec]: http://tools.ietf.org/html/rfc6386
|
||||
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
|
||||
[iccspec]: http://www.color.org/icc_specs2.xalter
|
||||
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
||||
[rfc 1166]: http://tools.ietf.org/html/rfc1166
|
||||
[rfc 2119]: http://tools.ietf.org/html/rfc2119
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,3 @@
|
||||
# Ignore this file during non-NDK builds.
|
||||
ifdef NDK_ROOT
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
################################################################################
|
||||
@@ -28,7 +26,8 @@ LOCAL_SRC_FILES := \
|
||||
cwebp.c \
|
||||
|
||||
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
|
||||
|
||||
@@ -43,7 +42,9 @@ LOCAL_SRC_FILES := \
|
||||
dwebp.c \
|
||||
|
||||
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
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -57,6 +58,7 @@ LOCAL_SRC_FILES := \
|
||||
webpmux.c \
|
||||
|
||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||
LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp
|
||||
|
||||
LOCAL_MODULE := webpmux_example
|
||||
@@ -72,8 +74,8 @@ LOCAL_SRC_FILES := \
|
||||
img2webp.c \
|
||||
|
||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webpdemux \
|
||||
webp
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webp
|
||||
|
||||
LOCAL_MODULE := img2webp_example
|
||||
|
||||
@@ -88,9 +90,9 @@ LOCAL_SRC_FILES := \
|
||||
webpinfo.c \
|
||||
|
||||
LOCAL_CFLAGS := $(WEBP_CFLAGS)
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
|
||||
LOCAL_STATIC_LIBRARIES := example_util imageio_util webp
|
||||
|
||||
LOCAL_MODULE := webpinfo_example
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
endif # NDK_ROOT
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||
|
||||
bin_PROGRAMS =
|
||||
if BUILD_DEMUX
|
||||
bin_PROGRAMS += dwebp cwebp
|
||||
endif
|
||||
bin_PROGRAMS = dwebp cwebp
|
||||
if BUILD_ANIMDIFF
|
||||
noinst_PROGRAMS = anim_diff anim_dump
|
||||
noinst_PROGRAMS = anim_diff
|
||||
endif
|
||||
if BUILD_GIF2WEBP
|
||||
bin_PROGRAMS += gif2webp
|
||||
@@ -13,7 +10,7 @@ endif
|
||||
if BUILD_IMG2WEBP
|
||||
bin_PROGRAMS += img2webp
|
||||
endif
|
||||
if BUILD_MUX
|
||||
if WANT_MUX
|
||||
bin_PROGRAMS += webpmux
|
||||
endif
|
||||
if BUILD_VWEBP
|
||||
@@ -28,38 +25,22 @@ noinst_LTLIBRARIES = libexample_util.la
|
||||
libexample_util_la_SOURCES = example_util.c example_util.h
|
||||
libexample_util_la_LIBADD = ../src/libwebp.la
|
||||
|
||||
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h gifdec.c gifdec.h
|
||||
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES)
|
||||
anim_diff_LDADD =
|
||||
anim_diff_LDADD += ../src/demux/libwebpdemux.la
|
||||
anim_diff_LDADD += libexample_util.la
|
||||
anim_diff_LDADD += ../imageio/libimageio_util.la
|
||||
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h
|
||||
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
||||
anim_diff_LDADD = ../src/demux/libwebpdemux.la
|
||||
anim_diff_LDADD += libexample_util.la ../imageio/libimageio_util.la
|
||||
anim_diff_LDADD += $(GIF_LIBS) -lm
|
||||
|
||||
anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h gifdec.c gifdec.h
|
||||
anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES)
|
||||
anim_dump_CPPFLAGS += $(GIF_INCLUDES)
|
||||
anim_dump_LDADD =
|
||||
anim_dump_LDADD += ../src/demux/libwebpdemux.la
|
||||
anim_dump_LDADD += libexample_util.la
|
||||
anim_dump_LDADD += ../imageio/libimageio_util.la
|
||||
anim_dump_LDADD += ../imageio/libimageenc.la
|
||||
anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm
|
||||
|
||||
cwebp_SOURCES = cwebp.c stopwatch.h
|
||||
cwebp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)
|
||||
cwebp_LDADD =
|
||||
cwebp_LDADD += libexample_util.la
|
||||
cwebp_LDADD += ../imageio/libimageio_util.la
|
||||
cwebp_LDADD += ../imageio/libimagedec.la
|
||||
cwebp_LDADD += ../src/libwebp.la
|
||||
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
cwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
cwebp_LDADD += ../imageio/libimagedec.la ../src/libwebp.la
|
||||
cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
|
||||
|
||||
dwebp_SOURCES = dwebp.c stopwatch.h
|
||||
dwebp_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
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/libimageenc.la
|
||||
dwebp_LDADD += ../imageio/libimageio_util.la
|
||||
@@ -67,53 +48,36 @@ dwebp_LDADD += ../src/libwebp.la
|
||||
dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS)
|
||||
|
||||
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
|
||||
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) -I$(top_srcdir)
|
||||
gif2webp_LDADD =
|
||||
gif2webp_LDADD += libexample_util.la
|
||||
gif2webp_LDADD += ../imageio/libimageio_util.la
|
||||
gif2webp_LDADD += ../src/mux/libwebpmux.la
|
||||
gif2webp_LDADD += ../src/libwebp.la
|
||||
gif2webp_LDADD += $(GIF_LIBS)
|
||||
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
|
||||
gif2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
gif2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la $(GIF_LIBS)
|
||||
|
||||
vwebp_SOURCES = vwebp.c
|
||||
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(GL_INCLUDES)
|
||||
vwebp_LDADD =
|
||||
vwebp_LDADD += libexample_util.la
|
||||
vwebp_LDADD += ../imageio/libimageio_util.la
|
||||
vwebp_LDADD += ../src/demux/libwebpdemux.la
|
||||
vwebp_LDADD += $(GL_LIBS)
|
||||
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
|
||||
vwebp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
vwebp_LDADD += ../src/demux/libwebpdemux.la $(GL_LIBS)
|
||||
|
||||
webpmux_SOURCES = webpmux.c
|
||||
webpmux_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
webpmux_LDADD =
|
||||
webpmux_LDADD += libexample_util.la
|
||||
webpmux_LDADD += ../imageio/libimageio_util.la
|
||||
webpmux_LDADD += ../src/mux/libwebpmux.la
|
||||
webpmux_LDADD += ../src/libwebp.la
|
||||
webpmux_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
webpmux_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
webpmux_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
|
||||
|
||||
img2webp_SOURCES = img2webp.c
|
||||
img2webp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)
|
||||
img2webp_LDADD =
|
||||
img2webp_LDADD += libexample_util.la
|
||||
img2webp_LDADD += ../imageio/libimageio_util.la
|
||||
img2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
img2webp_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
img2webp_LDADD += ../imageio/libimagedec.la
|
||||
img2webp_LDADD += ../src/mux/libwebpmux.la
|
||||
img2webp_LDADD += ../src/libwebp.la
|
||||
img2webp_LDADD += ../src/mux/libwebpmux.la ../src/libwebp.la
|
||||
img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
|
||||
|
||||
webpinfo_SOURCES = webpinfo.c
|
||||
webpinfo_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
webpinfo_LDADD =
|
||||
webpinfo_LDADD += libexample_util.la
|
||||
webpinfo_LDADD += ../imageio/libimageio_util.la
|
||||
webpinfo_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
webpinfo_LDADD = libexample_util.la ../imageio/libimageio_util.la
|
||||
webpinfo_LDADD += ../src/libwebp.la
|
||||
|
||||
if BUILD_LIBWEBPDECODER
|
||||
anim_diff_LDADD += ../src/libwebpdecoder.la
|
||||
anim_dump_LDADD += ../src/libwebpdecoder.la
|
||||
vwebp_LDADD += ../src/libwebpdecoder.la
|
||||
else
|
||||
anim_diff_LDADD += ../src/libwebp.la
|
||||
anim_dump_LDADD += ../src/libwebp.la
|
||||
vwebp_LDADD += ../src/libwebp.la
|
||||
endif
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h> // for 'strtod'.
|
||||
#include <string.h> // for 'strcmp'.
|
||||
|
||||
#include "./anim_util.h"
|
||||
#include "./example_util.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
@@ -146,18 +143,8 @@ static int CompareAnimatedImagePair(const AnimatedImage* const img1,
|
||||
if (!ok) return 0; // These are fatal failures, can't proceed.
|
||||
|
||||
if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
|
||||
int max_loop_count_workaround = 0;
|
||||
// Transcodes to webp increase the gif loop count by 1 for compatibility.
|
||||
// When the gif has the maximum value the webp value will be off by one.
|
||||
if ((img1->format == ANIM_GIF && img1->loop_count == 65536 &&
|
||||
img2->format == ANIM_WEBP && img2->loop_count == 65535) ||
|
||||
(img1->format == ANIM_WEBP && img1->loop_count == 65535 &&
|
||||
img2->format == ANIM_GIF && img2->loop_count == 65536)) {
|
||||
max_loop_count_workaround = 1;
|
||||
}
|
||||
ok = (max_loop_count_workaround ||
|
||||
CompareValues(img1->loop_count, img2->loop_count,
|
||||
"Loop count mismatch")) && ok;
|
||||
ok = CompareValues(img1->loop_count, img2->loop_count,
|
||||
"Loop count mismatch") && ok;
|
||||
ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor,
|
||||
premultiply) && ok;
|
||||
}
|
||||
@@ -200,16 +187,15 @@ static void Help(void) {
|
||||
printf(" -min_psnr <float> ... minimum per-frame PSNR\n");
|
||||
printf(" -raw_comparison ..... if this flag is not used, RGB is\n");
|
||||
printf(" premultiplied before comparison\n");
|
||||
printf(" -max_diff <int> ..... maximum allowed difference per channel\n"
|
||||
" between corresponding pixels in subsequent\n"
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
printf(" -max_diff <int> ..... maximum allowed difference per channel "
|
||||
" between corresponding pixels in subsequent"
|
||||
" frames\n");
|
||||
printf(" -h .................. this help\n");
|
||||
printf(" -version ............ print version number and exit\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns 0 on success, 1 if animation files differ, and 2 for any error.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int return_code = 2;
|
||||
int return_code = -1;
|
||||
int dump_frames = 0;
|
||||
const char* dump_folder = NULL;
|
||||
double min_psnr = 0.;
|
||||
@@ -221,49 +207,56 @@ int main(int argc, const char* argv[]) {
|
||||
const char* files[2] = { NULL, NULL };
|
||||
AnimatedImage images[2];
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
if (argc < 3) {
|
||||
Help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-dump_frames")) {
|
||||
if (c < argc - 1) {
|
||||
dump_frames = 1;
|
||||
dump_folder = (const char*)GET_WARGV(argv, ++c);
|
||||
dump_folder = argv[++c];
|
||||
} else {
|
||||
parse_error = 1;
|
||||
}
|
||||
} else if (!strcmp(argv[c], "-min_psnr")) {
|
||||
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 {
|
||||
parse_error = 1;
|
||||
}
|
||||
} else if (!strcmp(argv[c], "-raw_comparison")) {
|
||||
premultiply = 0;
|
||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||
} else if (!strcmp(argv[c], "-max_diff")) {
|
||||
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 {
|
||||
parse_error = 1;
|
||||
}
|
||||
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(0);
|
||||
} else if (!strcmp(argv[c], "-version")) {
|
||||
int dec_version, demux_version;
|
||||
GetAnimatedImageVersions(&dec_version, &demux_version);
|
||||
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
|
||||
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
|
||||
(dec_version >> 0) & 0xff,
|
||||
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
|
||||
(demux_version >> 0) & 0xff);
|
||||
FREE_WARGV_AND_RETURN(0);
|
||||
#endif
|
||||
} else {
|
||||
if (!got_input1) {
|
||||
files[0] = (const char*)GET_WARGV(argv, c);
|
||||
files[0] = argv[c];
|
||||
got_input1 = 1;
|
||||
} else if (!got_input2) {
|
||||
files[1] = (const char*)GET_WARGV(argv, c);
|
||||
files[1] = argv[c];
|
||||
got_input2 = 1;
|
||||
} else {
|
||||
parse_error = 1;
|
||||
@@ -271,31 +264,24 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
if (parse_error) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(return_code);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (argc < 3) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(return_code);
|
||||
}
|
||||
|
||||
|
||||
if (!got_input2) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(return_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
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)) {
|
||||
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n",
|
||||
(const W_CHAR*)files[i]);
|
||||
return_code = 2;
|
||||
fprintf(stderr, "Error decoding file: %s\n Aborting.\n", files[i]);
|
||||
return_code = -2;
|
||||
goto End;
|
||||
} else {
|
||||
MinimizeAnimationFrames(&images[i], max_diff);
|
||||
@@ -304,16 +290,14 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
if (!CompareAnimatedImagePair(&images[0], &images[1],
|
||||
premultiply, min_psnr)) {
|
||||
WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0],
|
||||
(const W_CHAR*)files[1]);
|
||||
return_code = 1;
|
||||
fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]);
|
||||
return_code = -3;
|
||||
} else {
|
||||
WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0],
|
||||
(const W_CHAR*)files[1]);
|
||||
printf("\nFiles %s and %s are identical.\n", files[0], files[1]);
|
||||
return_code = 0;
|
||||
}
|
||||
End:
|
||||
ClearAnimatedImage(&images[0]);
|
||||
ClearAnimatedImage(&images[1]);
|
||||
FREE_WARGV_AND_RETURN(return_code);
|
||||
return return_code;
|
||||
}
|
||||
|
||||
@@ -1,128 +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 <stdlib.h>
|
||||
#include <string.h> // for 'strcmp'.
|
||||
|
||||
#include "../imageio/image_enc.h"
|
||||
#include "./anim_util.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/types.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");
|
||||
}
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
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(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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(EXIT_SUCCESS);
|
||||
} 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(EXIT_SUCCESS);
|
||||
} 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;
|
||||
if (!WebPInitDecBuffer(&buffer)) {
|
||||
fprintf(stderr, "Cannot init dec buffer\n");
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
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 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
@@ -16,19 +16,13 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(WEBP_HAVE_GIF)
|
||||
#ifdef WEBP_HAVE_GIF
|
||||
#include <gif_lib.h>
|
||||
#endif
|
||||
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./gifdec.h"
|
||||
#include "./unicode.h"
|
||||
#include "./unicode_gif.h"
|
||||
#include "webp/format_constants.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/demux.h"
|
||||
#include "webp/format_constants.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
@@ -39,13 +33,11 @@ static const int kNumChannels = 4;
|
||||
// -----------------------------------------------------------------------------
|
||||
// Common utilities.
|
||||
|
||||
#if defined(WEBP_HAVE_GIF)
|
||||
// Returns true if the frame covers the full canvas.
|
||||
static int IsFullFrame(int width, int height,
|
||||
int canvas_width, int canvas_height) {
|
||||
return (width == canvas_width && height == canvas_height);
|
||||
}
|
||||
#endif // WEBP_HAVE_GIF
|
||||
|
||||
static int CheckSizeForOverflow(uint64_t size) {
|
||||
return (size == (size_t)size);
|
||||
@@ -63,15 +55,15 @@ static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
|
||||
!CheckSizeForOverflow(total_frame_size)) {
|
||||
return 0;
|
||||
}
|
||||
mem = (uint8_t*)WebPMalloc((size_t)total_size);
|
||||
frames = (DecodedFrame*)WebPMalloc((size_t)total_frame_size);
|
||||
mem = (uint8_t*)malloc((size_t)total_size);
|
||||
frames = (DecodedFrame*)malloc((size_t)total_frame_size);
|
||||
|
||||
if (mem == NULL || frames == NULL) {
|
||||
WebPFree(mem);
|
||||
WebPFree(frames);
|
||||
free(mem);
|
||||
free(frames);
|
||||
return 0;
|
||||
}
|
||||
WebPFree(image->raw_mem);
|
||||
free(image->raw_mem);
|
||||
image->num_frames = num_frames;
|
||||
image->frames = frames;
|
||||
for (i = 0; i < num_frames; ++i) {
|
||||
@@ -85,15 +77,14 @@ static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
|
||||
|
||||
void ClearAnimatedImage(AnimatedImage* const image) {
|
||||
if (image != NULL) {
|
||||
WebPFree(image->raw_mem);
|
||||
WebPFree(image->frames);
|
||||
free(image->raw_mem);
|
||||
free(image->frames);
|
||||
image->num_frames = 0;
|
||||
image->frames = NULL;
|
||||
image->raw_mem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBP_HAVE_GIF)
|
||||
// Clear the canvas to transparent.
|
||||
static void ZeroFillCanvas(uint8_t* rgba,
|
||||
uint32_t canvas_width, uint32_t canvas_height) {
|
||||
@@ -135,7 +126,6 @@ static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride,
|
||||
dst += stride;
|
||||
}
|
||||
}
|
||||
#endif // WEBP_HAVE_GIF
|
||||
|
||||
// Canonicalize all transparent pixels to transparent black to aid comparison.
|
||||
static void CleanupTransparentPixels(uint32_t* rgba,
|
||||
@@ -157,42 +147,40 @@ static int DumpFrame(const char filename[], const char dump_folder[],
|
||||
int ok = 0;
|
||||
size_t max_len;
|
||||
int y;
|
||||
const W_CHAR* base_name = NULL;
|
||||
W_CHAR* file_name = NULL;
|
||||
const char* base_name = NULL;
|
||||
char* file_name = NULL;
|
||||
FILE* f = NULL;
|
||||
const char* row;
|
||||
|
||||
if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR(".");
|
||||
|
||||
base_name = WSTRRCHR(filename, '/');
|
||||
base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1;
|
||||
max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name)
|
||||
base_name = strrchr(filename, '/');
|
||||
base_name = (base_name == NULL) ? filename : base_name + 1;
|
||||
max_len = strlen(dump_folder) + 1 + strlen(base_name)
|
||||
+ 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 (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam",
|
||||
(const W_CHAR*)dump_folder, base_name, frame_num) < 0) {
|
||||
if (snprintf(file_name, max_len, "%s/%s_frame_%d.pam",
|
||||
dump_folder, base_name, frame_num) < 0) {
|
||||
fprintf(stderr, "Error while generating file name\n");
|
||||
goto End;
|
||||
}
|
||||
|
||||
f = WFOPEN(file_name, "wb");
|
||||
f = fopen(file_name, "wb");
|
||||
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;
|
||||
goto End;
|
||||
}
|
||||
if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n"
|
||||
"DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
|
||||
canvas_width, canvas_height) < 0) {
|
||||
WFPRINTF(stderr, "Write error for file %s\n", file_name);
|
||||
fprintf(stderr, "Write error for file %s\n", file_name);
|
||||
goto End;
|
||||
}
|
||||
row = (const char*)rgba;
|
||||
for (y = 0; y < canvas_height; ++y) {
|
||||
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
|
||||
WFPRINTF(stderr, "Error writing to file: %s\n", file_name);
|
||||
fprintf(stderr, "Error writing to file: %s\n", file_name);
|
||||
goto End;
|
||||
}
|
||||
row += canvas_width * kNumChannels;
|
||||
@@ -200,7 +188,7 @@ static int DumpFrame(const char filename[], const char dump_folder[],
|
||||
ok = 1;
|
||||
End:
|
||||
if (f != NULL) fclose(f);
|
||||
WebPFree(file_name);
|
||||
free(file_name);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -212,7 +200,7 @@ static int IsWebP(const WebPData* const webp_data) {
|
||||
return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0);
|
||||
}
|
||||
|
||||
// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct.
|
||||
// Read animated WebP bitstream 'file_str' into 'AnimatedImage' struct.
|
||||
static int ReadAnimatedWebP(const char filename[],
|
||||
const WebPData* const webp_data,
|
||||
AnimatedImage* const image, int dump_frames,
|
||||
@@ -228,7 +216,7 @@ static int ReadAnimatedWebP(const char filename[],
|
||||
|
||||
dec = WebPAnimDecoderNew(webp_data, 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;
|
||||
}
|
||||
|
||||
@@ -244,7 +232,7 @@ static int ReadAnimatedWebP(const char filename[],
|
||||
image->bgcolor = anim_info.bgcolor;
|
||||
|
||||
// Allocate frames.
|
||||
if (!AllocateFrames(image, anim_info.frame_count)) goto End;
|
||||
if (!AllocateFrames(image, anim_info.frame_count)) return 0;
|
||||
|
||||
// Decode frames.
|
||||
while (WebPAnimDecoderHasMoreFrames(dec)) {
|
||||
@@ -281,7 +269,6 @@ static int ReadAnimatedWebP(const char filename[],
|
||||
prev_frame_timestamp = timestamp;
|
||||
}
|
||||
ok = dump_ok;
|
||||
if (ok) image->format = ANIM_WEBP;
|
||||
|
||||
End:
|
||||
WebPAnimDecoderDelete(dec);
|
||||
@@ -291,7 +278,7 @@ static int ReadAnimatedWebP(const char filename[],
|
||||
// -----------------------------------------------------------------------------
|
||||
// GIF Decoding.
|
||||
|
||||
#if defined(WEBP_HAVE_GIF)
|
||||
#ifdef WEBP_HAVE_GIF
|
||||
|
||||
// Returns true if this is a valid GIF bitstream.
|
||||
static int IsGIF(const WebPData* const data) {
|
||||
@@ -376,6 +363,26 @@ static int DGifSavedExtensionToGCB(GifFileType* GifFile, int ImageIndex,
|
||||
#define DGifCloseFile(a, b) DGifCloseFile(a)
|
||||
#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,
|
||||
const DecodedFrame* const prev_frame,
|
||||
int canvas_width, int canvas_height) {
|
||||
@@ -408,7 +415,7 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
|
||||
return 0xffffffff; // Invalid: assume white.
|
||||
} else {
|
||||
const GifColorType color = color_map->Colors[gif->SBackGroundColor];
|
||||
return (0xffu << 24) |
|
||||
return (0xff << 24) |
|
||||
(color.Red << 16) |
|
||||
(color.Green << 8) |
|
||||
(color.Blue << 0);
|
||||
@@ -416,11 +423,6 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
|
||||
}
|
||||
|
||||
// Find appropriate app extension and get loop count from the next extension.
|
||||
// We use Chrome's interpretation of the 'loop_count' semantics:
|
||||
// if not present -> loop once
|
||||
// if present and loop_count == 0, return 0 ('infinite').
|
||||
// if present and loop_count != 0, it's the number of *extra* loops
|
||||
// so we need to return loop_count + 1 as total loop number.
|
||||
static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
|
||||
int i;
|
||||
for (i = 0; i < gif->ImageCount; ++i) {
|
||||
@@ -438,13 +440,12 @@ static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
|
||||
if (signature_is_ok &&
|
||||
eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 &&
|
||||
eb2->Bytes[0] == 1) {
|
||||
const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) +
|
||||
((uint32_t)(eb2->Bytes[1]) << 0);
|
||||
return (extra_loop > 0) ? extra_loop + 1 : 0;
|
||||
return ((uint32_t)(eb2->Bytes[2]) << 8) +
|
||||
((uint32_t)(eb2->Bytes[1]) << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1; // Default.
|
||||
return 0; // Default.
|
||||
}
|
||||
|
||||
// Get duration of 'n'th frame in milliseconds.
|
||||
@@ -516,15 +517,15 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
||||
int gif_error;
|
||||
GifFileType* gif;
|
||||
|
||||
gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL);
|
||||
gif = DGifOpenFileName(filename, 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;
|
||||
}
|
||||
|
||||
gif_error = DGifSlurp(gif);
|
||||
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);
|
||||
DGifCloseFile(gif, NULL);
|
||||
return 0;
|
||||
@@ -561,10 +562,7 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
||||
}
|
||||
}
|
||||
// Allocate frames.
|
||||
if (!AllocateFrames(image, frame_count)) {
|
||||
DGifCloseFile(gif, NULL);
|
||||
return 0;
|
||||
}
|
||||
AllocateFrames(image, frame_count);
|
||||
|
||||
canvas_width = image->canvas_width;
|
||||
canvas_height = image->canvas_height;
|
||||
@@ -583,9 +581,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
||||
curr_frame = &image->frames[i];
|
||||
curr_rgba = curr_frame->rgba;
|
||||
curr_frame->duration = GetFrameDurationGIF(gif, i);
|
||||
// Force frames with a small or no duration to 100ms to be consistent
|
||||
// with web browsers and other transcoding tools (like gif2webp itself).
|
||||
if (curr_frame->duration <= 10) curr_frame->duration = 100;
|
||||
|
||||
if (i == 0) { // Initialize as transparent.
|
||||
curr_frame->is_key_frame = 1;
|
||||
@@ -677,7 +672,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
||||
}
|
||||
}
|
||||
}
|
||||
image->format = ANIM_GIF;
|
||||
DGifCloseFile(gif, NULL);
|
||||
return 1;
|
||||
}
|
||||
@@ -713,7 +707,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
|
||||
memset(image, 0, sizeof(*image));
|
||||
|
||||
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
|
||||
WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename);
|
||||
fprintf(stderr, "Error reading file: %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -723,9 +717,9 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
|
||||
} else if (IsGIF(&webp_data)) {
|
||||
ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder);
|
||||
} else {
|
||||
WFPRINTF(stderr,
|
||||
"Unknown file type: %s. Supported file types are WebP and GIF\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr,
|
||||
"Unknown file type: %s. Supported file types are WebP and GIF\n",
|
||||
filename);
|
||||
ok = 0;
|
||||
}
|
||||
if (!ok) ClearAnimatedImage(image);
|
||||
@@ -774,13 +768,6 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
|
||||
*psnr = 99.; // PSNR when images are identical.
|
||||
} else {
|
||||
sse /= stride * height;
|
||||
assert(sse != 0.0);
|
||||
*psnr = 4.3429448 * log(255. * 255. / sse);
|
||||
}
|
||||
}
|
||||
|
||||
void GetAnimatedImageVersions(int* const decoder_version,
|
||||
int* const demux_version) {
|
||||
*decoder_version = WebPGetDecoderVersion();
|
||||
*demux_version = WebPGetDemuxVersion();
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ANIM_GIF,
|
||||
ANIM_WEBP
|
||||
} AnimatedFileFormat;
|
||||
|
||||
typedef struct {
|
||||
uint8_t* rgba; // Decoded and reconstructed full frame.
|
||||
int duration; // Frame duration in milliseconds.
|
||||
@@ -34,7 +29,6 @@ typedef struct {
|
||||
} DecodedFrame;
|
||||
|
||||
typedef struct {
|
||||
AnimatedFileFormat format;
|
||||
uint32_t canvas_width;
|
||||
uint32_t canvas_height;
|
||||
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,
|
||||
int* const max_diff, double* const psnr);
|
||||
|
||||
// Return library versions used by anim_util.
|
||||
void GetAnimatedImageVersions(int* const decoder_version,
|
||||
int* const demux_version);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
424
examples/cwebp.c
424
examples/cwebp.c
@@ -12,7 +12,6 @@
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -24,13 +23,8 @@
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/image_dec.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "../imageio/webpdec.h"
|
||||
#include "./stopwatch.h"
|
||||
#include "./unicode.h"
|
||||
#include "imageio/metadata.h"
|
||||
#include "sharpyuv/sharpyuv.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifndef WEBP_DLL
|
||||
#ifdef __cplusplus
|
||||
@@ -94,10 +88,9 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
||||
}
|
||||
WebPFree((void*)data);
|
||||
free((void*)data);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -121,10 +114,9 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||
}
|
||||
End:
|
||||
if (!ok) {
|
||||
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
||||
}
|
||||
WebPFree((void*)data);
|
||||
free((void*)data);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -133,8 +125,7 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||
static void AllocExtraInfo(WebPPicture* const pic) {
|
||||
const int mb_w = (pic->width + 15) / 16;
|
||||
const int mb_h = (pic->height + 15) / 16;
|
||||
pic->extra_info =
|
||||
(uint8_t*)WebPMalloc(mb_w * mb_h * sizeof(*pic->extra_info));
|
||||
pic->extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(*pic->extra_info));
|
||||
}
|
||||
|
||||
static void PrintByteCount(const int bytes[4], int total_size,
|
||||
@@ -149,11 +140,10 @@ static void PrintByteCount(const int bytes[4], int 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;
|
||||
const int total = counts[0] + counts[1] + counts[2] + counts[3];
|
||||
for (s = 0; s < 4; ++s) {
|
||||
fprintf(stderr, "| %3d%%", (int)(100. * counts[s] / total + .5));
|
||||
fprintf(stderr, "| %2d%%", 100 * counts[s] / total);
|
||||
}
|
||||
fprintf(stderr, "| %7d\n", total);
|
||||
}
|
||||
@@ -180,14 +170,8 @@ static void PrintFullLosslessInfo(const WebPAuxStats* const stats,
|
||||
if (stats->lossless_features & 8) fprintf(stderr, " PALETTE");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, " * Precision Bits: histogram=%d", stats->histogram_bits);
|
||||
if (stats->lossless_features & 1) {
|
||||
fprintf(stderr, " prediction=%d", stats->transform_bits);
|
||||
}
|
||||
if (stats->lossless_features & 2) {
|
||||
fprintf(stderr, " cross-color=%d", stats->cross_color_transform_bits);
|
||||
}
|
||||
fprintf(stderr, " cache=%d\n", stats->cache_bits);
|
||||
fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n",
|
||||
stats->histogram_bits, stats->transform_bits, stats->cache_bits);
|
||||
if (stats->palette_size > 0) {
|
||||
fprintf(stderr, " * Palette size: %d\n", stats->palette_size);
|
||||
}
|
||||
@@ -200,10 +184,9 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic,
|
||||
if (short_output) {
|
||||
fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
|
||||
} else {
|
||||
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
|
||||
fprintf(stderr, "File: %s\n", file_name);
|
||||
fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
|
||||
fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size,
|
||||
8.f * stats->coded_size / pic->width / pic->height);
|
||||
fprintf(stderr, "Output: %d bytes\n", stats->coded_size);
|
||||
PrintFullLosslessInfo(stats, "ARGB");
|
||||
}
|
||||
}
|
||||
@@ -219,23 +202,20 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
|
||||
const int num_i16 = stats->block_count[1];
|
||||
const int num_skip = stats->block_count[2];
|
||||
const int total = num_i4 + num_i16;
|
||||
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
|
||||
fprintf(stderr, "File: %s\n", file_name);
|
||||
fprintf(stderr, "Dimension: %d x %d%s\n",
|
||||
pic->width, pic->height,
|
||||
stats->alpha_data_size ? " (with alpha)" : "");
|
||||
fprintf(stderr, "Output: "
|
||||
"%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n"
|
||||
" (%.2f bpp)\n",
|
||||
"%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n",
|
||||
stats->coded_size,
|
||||
stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3],
|
||||
8.f * stats->coded_size / pic->width / pic->height);
|
||||
stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3]);
|
||||
if (total > 0) {
|
||||
int totals[4] = { 0, 0, 0, 0 };
|
||||
fprintf(stderr, "block count: intra4: %6d (%.2f%%)\n"
|
||||
" intra16: %6d (%.2f%%)\n"
|
||||
" skipped: %6d (%.2f%%)\n",
|
||||
num_i4, 100.f * num_i4 / total,
|
||||
num_i16, 100.f * num_i16 / total,
|
||||
fprintf(stderr, "block count: intra4: %d\n"
|
||||
" intra16: %d (-> %.2f%%)\n",
|
||||
num_i4, num_i16, 100.f * num_i16 / total);
|
||||
fprintf(stderr, " skipped block: %d (%.2f%%)\n",
|
||||
num_skip, 100.f * num_skip / total);
|
||||
fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
|
||||
" mode-partition: %6d (%.1f%%)\n",
|
||||
@@ -259,7 +239,7 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
|
||||
PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
|
||||
}
|
||||
fprintf(stderr, " macroblocks: ");
|
||||
PrintPercents(stats->segment_size);
|
||||
PrintPercents(stats->segment_size, total);
|
||||
fprintf(stderr, " quantizer: ");
|
||||
PrintValues(stats->segment_quant);
|
||||
fprintf(stderr, " filter level: ");
|
||||
@@ -314,7 +294,6 @@ static int MyWriter(const uint8_t* data, size_t data_size,
|
||||
// Dumps a picture as a PGM file using the IMC4 layout.
|
||||
static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
||||
int y;
|
||||
int ok = 0;
|
||||
const int uv_width = (picture->width + 1) / 2;
|
||||
const int uv_height = (picture->height + 1) / 2;
|
||||
const int stride = (picture->width + 1) & ~1;
|
||||
@@ -325,30 +304,27 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
||||
const int alpha_height =
|
||||
WebPPictureHasTransparency(picture) ? picture->height : 0;
|
||||
const int height = picture->height + uv_height + alpha_height;
|
||||
FILE* const f = WFOPEN(PGM_name, "wb");
|
||||
FILE* const f = fopen(PGM_name, "wb");
|
||||
if (f == NULL) return 0;
|
||||
fprintf(f, "P5\n%d %d\n255\n", stride, height);
|
||||
for (y = 0; y < picture->height; ++y) {
|
||||
if (fwrite(src_y, picture->width, 1, f) != 1) goto Error;
|
||||
if (fwrite(src_y, picture->width, 1, f) != 1) return 0;
|
||||
if (picture->width & 1) fputc(0, f); // pad
|
||||
src_y += picture->y_stride;
|
||||
}
|
||||
for (y = 0; y < uv_height; ++y) {
|
||||
if (fwrite(src_u, uv_width, 1, f) != 1) goto Error;
|
||||
if (fwrite(src_v, uv_width, 1, f) != 1) goto Error;
|
||||
if (fwrite(src_u, uv_width, 1, f) != 1) return 0;
|
||||
if (fwrite(src_v, uv_width, 1, f) != 1) return 0;
|
||||
src_u += picture->uv_stride;
|
||||
src_v += picture->uv_stride;
|
||||
}
|
||||
for (y = 0; y < alpha_height; ++y) {
|
||||
if (fwrite(src_a, picture->width, 1, f) != 1) goto Error;
|
||||
if (fwrite(src_a, picture->width, 1, f) != 1) return 0;
|
||||
if (picture->width & 1) fputc(0, f); // pad
|
||||
src_a += picture->a_stride;
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
fclose(f);
|
||||
return ok;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -487,9 +463,8 @@ static int WriteWebPWithMetadata(FILE* const out,
|
||||
} else {
|
||||
const int is_lossless = !memcmp(webp, "VP8L", kTagSize);
|
||||
if (is_lossless) {
|
||||
// Presence of alpha is stored in the 37th bit (29th after the
|
||||
// signature) of VP8L data.
|
||||
if (webp[kChunkHeaderSize + 4] & (1 << 4)) flags |= kAlphaFlag;
|
||||
// Presence of alpha is stored in the 29th bit of VP8L data.
|
||||
if (webp[kChunkHeaderSize + 3] & (1 << 5)) flags |= kAlphaFlag;
|
||||
}
|
||||
ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1);
|
||||
ok = ok && WriteLE32(out, flags);
|
||||
@@ -511,40 +486,9 @@ static int WriteWebPWithMetadata(FILE* const out,
|
||||
*metadata_written |= METADATA_XMP;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// No metadata, just write the original image file.
|
||||
return (fwrite(webp, webp_size, 1, out) == 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Resize
|
||||
|
||||
enum {
|
||||
RESIZE_MODE_DOWN_ONLY,
|
||||
RESIZE_MODE_UP_ONLY,
|
||||
RESIZE_MODE_ALWAYS,
|
||||
RESIZE_MODE_DEFAULT = RESIZE_MODE_ALWAYS
|
||||
};
|
||||
|
||||
static void ApplyResizeMode(const int resize_mode,
|
||||
const WebPPicture* const pic,
|
||||
int* const resize_w, int* const resize_h) {
|
||||
const int src_w = pic->width;
|
||||
const int src_h = pic->height;
|
||||
const int dst_w = *resize_w;
|
||||
const int dst_h = *resize_h;
|
||||
|
||||
if (resize_mode == RESIZE_MODE_DOWN_ONLY) {
|
||||
if ((dst_w == 0 && src_h <= dst_h) ||
|
||||
(dst_h == 0 && src_w <= dst_w) ||
|
||||
(src_w <= dst_w && src_h <= dst_h)) {
|
||||
*resize_w = *resize_h = 0;
|
||||
}
|
||||
} else if (resize_mode == RESIZE_MODE_UP_ONLY) {
|
||||
if (src_w >= dst_w && src_h >= dst_h) {
|
||||
*resize_w = *resize_h = 0;
|
||||
}
|
||||
} else {
|
||||
// No metadata, just write the original image file.
|
||||
return (fwrite(webp, webp_size, 1, out) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +515,6 @@ static void HelpLong(void) {
|
||||
printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n");
|
||||
printf("If input size (-s) for an image is not specified, it is\n"
|
||||
"assumed to be a PNG, JPEG, TIFF or WebP file.\n");
|
||||
printf("Note: Animated PNG and WebP files are not supported.\n");
|
||||
#ifdef HAVE_WINCODEC_H
|
||||
printf("Windows builds can take as input any of the files handled by WIC.\n");
|
||||
#endif
|
||||
@@ -612,12 +555,8 @@ static void HelpLong(void) {
|
||||
printf(" "
|
||||
"the first partition (0=no degradation ... 100=full)\n");
|
||||
printf(" -pass <int> ............ analysis pass number (1..10)\n");
|
||||
printf(" -qrange <min> <max> .... specifies the permissible quality range\n"
|
||||
" (default: 0 100)\n");
|
||||
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
|
||||
printf(" -resize <w> <h> ........ resize picture (*after* any cropping)\n");
|
||||
printf(" -resize_mode <string> .. one of: up_only, down_only,"
|
||||
" always (default)\n");
|
||||
printf(" -resize <w> <h> ........ resize picture (after any cropping)\n");
|
||||
printf(" -mt .................... use multi-threading if available\n");
|
||||
printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
|
||||
printf(" -map <int> ............. print map of extra info\n");
|
||||
@@ -637,8 +576,12 @@ static void HelpLong(void) {
|
||||
" green=0xe0 and blue=0xd0\n");
|
||||
printf(" -noalpha ............... discard any transparency information\n");
|
||||
printf(" -lossless .............. encode image losslessly, default=off\n");
|
||||
printf(" -near_lossless <int> ... use near-lossless image preprocessing\n"
|
||||
" (0..100=off), default=100\n");
|
||||
printf(" -near_lossless <int> ... use near-lossless image\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(" one of: photo, picture or graph\n");
|
||||
|
||||
@@ -665,7 +608,6 @@ static void HelpLong(void) {
|
||||
printf(" -af .................... auto-adjust filter strength\n");
|
||||
printf(" -pre <int> ............. pre-processing filter\n");
|
||||
printf("\n");
|
||||
printf("Supported input formats:\n %s\n", WebPGetEnabledInputFileFormats());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -692,11 +634,10 @@ static const char* const kErrorMessages[VP8_ENC_ERROR_LAST] = {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int return_value = EXIT_FAILURE;
|
||||
const char* in_file = NULL, *out_file = NULL, *dump_file = NULL;
|
||||
FILE* out = NULL;
|
||||
int main(int argc, const char *argv[]) {
|
||||
int return_value = -1;
|
||||
const char *in_file = NULL, *out_file = NULL, *dump_file = NULL;
|
||||
FILE *out = NULL;
|
||||
int c;
|
||||
int short_output = 0;
|
||||
int quiet = 0;
|
||||
@@ -705,7 +646,6 @@ int main(int argc, const char* argv[]) {
|
||||
uint32_t background_color = 0xffffffu;
|
||||
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
|
||||
int resize_w = 0, resize_h = 0;
|
||||
int resize_mode = RESIZE_MODE_DEFAULT;
|
||||
int lossless_preset = 6;
|
||||
int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it
|
||||
int show_progress = 0;
|
||||
@@ -717,38 +657,35 @@ int main(int argc, const char* argv[]) {
|
||||
WebPConfig config;
|
||||
WebPAuxStats stats;
|
||||
WebPMemoryWriter memory_writer;
|
||||
int use_memory_writer;
|
||||
Metadata metadata;
|
||||
Stopwatch stop_watch;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
MetadataInit(&metadata);
|
||||
WebPMemoryWriterInit(&memory_writer);
|
||||
if (!WebPPictureInit(&picture) ||
|
||||
!WebPPictureInit(&original_picture) ||
|
||||
!WebPConfigInit(&config)) {
|
||||
fprintf(stderr, "Error! Version mismatch!\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
HelpShort();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
HelpShort();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||
HelpLong();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
} else if (!strcmp(argv[c], "-o") && c + 1 < argc) {
|
||||
out_file = (const char*)GET_WARGV(argv, ++c);
|
||||
} else if (!strcmp(argv[c], "-d") && c + 1 < argc) {
|
||||
dump_file = (const char*)GET_WARGV(argv, ++c);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
||||
out_file = argv[++c];
|
||||
} else if (!strcmp(argv[c], "-d") && c < argc - 1) {
|
||||
dump_file = argv[++c];
|
||||
config.show_compressed = 1;
|
||||
} else if (!strcmp(argv[c], "-print_psnr")) {
|
||||
config.show_compressed = 1;
|
||||
@@ -761,7 +698,7 @@ int main(int argc, const char* argv[]) {
|
||||
print_distortion = 2;
|
||||
} else if (!strcmp(argv[c], "-short")) {
|
||||
++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.height = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 ||
|
||||
@@ -771,30 +708,30 @@ int main(int argc, const char* argv[]) {
|
||||
picture.width, picture.height);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
} 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);
|
||||
} else if (!strcmp(argv[c], "-alpha_cleanup")) {
|
||||
// This flag is obsolete, does opposite of -exact.
|
||||
config.exact = 0;
|
||||
} else if (!strcmp(argv[c], "-exact")) {
|
||||
config.exact = 1;
|
||||
} else if (!strcmp(argv[c], "-blend_alpha") && c + 1 < argc) {
|
||||
} else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 1) {
|
||||
blend_alpha = 1;
|
||||
// background color is given in hex with an optional '0x' prefix
|
||||
background_color = ExUtilGetInt(argv[++c], 16, &parse_error);
|
||||
background_color = background_color & 0x00ffffffu;
|
||||
} else if (!strcmp(argv[c], "-alpha_filter") && c + 1 < argc) {
|
||||
} else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) {
|
||||
++c;
|
||||
if (!strcmp(argv[c], "none")) {
|
||||
config.alpha_filtering = 0;
|
||||
@@ -810,10 +747,15 @@ int main(int argc, const char* argv[]) {
|
||||
keep_alpha = 0;
|
||||
} else if (!strcmp(argv[c], "-lossless")) {
|
||||
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.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;
|
||||
if (!strcmp(argv[c], "photo")) {
|
||||
config.image_hint = WEBP_HINT_PHOTO;
|
||||
@@ -825,13 +767,13 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]);
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
} 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);
|
||||
} else if (!strcmp(argv[c], "-af")) {
|
||||
config.autofilter = 1;
|
||||
@@ -845,64 +787,43 @@ int main(int argc, const char* argv[]) {
|
||||
config.filter_type = 1;
|
||||
} else if (!strcmp(argv[c], "-nostrong")) {
|
||||
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);
|
||||
} else if (!strcmp(argv[c], "-sharp_yuv")) {
|
||||
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);
|
||||
} else if (!strcmp(argv[c], "-qrange") && c + 2 < argc) {
|
||||
config.qmin = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
config.qmax = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
if (config.qmin < 0) config.qmin = 0;
|
||||
if (config.qmax > 100) config.qmax = 100;
|
||||
} else if (!strcmp(argv[c], "-pre") && c + 1 < argc) {
|
||||
} else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
} else if (!strcmp(argv[c], "-crop") && c + 4 < argc) {
|
||||
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
|
||||
crop = 1;
|
||||
crop_x = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
crop_y = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
crop_w = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
crop_h = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
} else if (!strcmp(argv[c], "-resize") && c + 2 < argc) {
|
||||
} else if (!strcmp(argv[c], "-resize") && c < argc - 2) {
|
||||
resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
} else if (!strcmp(argv[c], "-resize_mode") && c + 1 < argc) {
|
||||
++c;
|
||||
if (!strcmp(argv[c], "down_only")) {
|
||||
resize_mode = RESIZE_MODE_DOWN_ONLY;
|
||||
} else if (!strcmp(argv[c], "up_only")) {
|
||||
resize_mode = RESIZE_MODE_UP_ONLY;
|
||||
} else if (!strcmp(argv[c], "always")) {
|
||||
resize_mode = RESIZE_MODE_ALWAYS;
|
||||
} else {
|
||||
fprintf(stderr, "Error! Unrecognized resize mode: %s\n", argv[c]);
|
||||
goto Error;
|
||||
}
|
||||
#ifndef WEBP_DLL
|
||||
} else if (!strcmp(argv[c], "-noasm")) {
|
||||
VP8GetCPUInfo = NULL;
|
||||
#endif
|
||||
} else if (!strcmp(argv[c], "-version")) {
|
||||
const int version = WebPGetEncoderVersion();
|
||||
const int sharpyuv_version = SharpYuvGetVersion();
|
||||
printf("%d.%d.%d\n",
|
||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||
printf("libsharpyuv: %d.%d.%d\n",
|
||||
(sharpyuv_version >> 24) & 0xff, (sharpyuv_version >> 16) & 0xffff,
|
||||
sharpyuv_version & 0xff);
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-progress")) {
|
||||
show_progress = 1;
|
||||
} else if (!strcmp(argv[c], "-quiet")) {
|
||||
quiet = 1;
|
||||
} else if (!strcmp(argv[c], "-preset") && c + 1 < argc) {
|
||||
} else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
|
||||
WebPPreset preset;
|
||||
++c;
|
||||
if (!strcmp(argv[c], "default")) {
|
||||
@@ -925,7 +846,7 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Error! Could initialize configuration with preset.\n");
|
||||
goto Error;
|
||||
}
|
||||
} else if (!strcmp(argv[c], "-metadata") && c + 1 < argc) {
|
||||
} else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
|
||||
static const struct {
|
||||
const char* option;
|
||||
int flag;
|
||||
@@ -959,7 +880,8 @@ int main(int argc, const char* argv[]) {
|
||||
if (i == kNumTokens) {
|
||||
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
||||
(int)(token - start), start);
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
HelpLong();
|
||||
return -1;
|
||||
}
|
||||
start = token + 1;
|
||||
}
|
||||
@@ -973,19 +895,19 @@ int main(int argc, const char* argv[]) {
|
||||
} else if (!strcmp(argv[c], "-v")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(argv[c], "--")) {
|
||||
if (c + 1 < argc) in_file = (const char*)GET_WARGV(argv, ++c);
|
||||
if (c < argc - 1) in_file = argv[++c];
|
||||
break;
|
||||
} else if (argv[c][0] == '-') {
|
||||
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
||||
HelpLong();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
} else {
|
||||
in_file = (const char*)GET_WARGV(argv, c);
|
||||
in_file = argv[c];
|
||||
}
|
||||
|
||||
if (parse_error) {
|
||||
HelpLong();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (in_file == NULL) {
|
||||
@@ -1035,8 +957,7 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
if (!ReadPicture(in_file, &picture, keep_alpha,
|
||||
(keep_metadata == 0) ? NULL : &metadata)) {
|
||||
WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n",
|
||||
(const W_CHAR*)in_file);
|
||||
fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
|
||||
goto Error;
|
||||
}
|
||||
picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
|
||||
@@ -1049,41 +970,28 @@ int main(int argc, const char* argv[]) {
|
||||
const double read_time = StopwatchReadAndReset(&stop_watch);
|
||||
fprintf(stderr, "Time to read input: %.3fs\n", read_time);
|
||||
}
|
||||
// The bitstream should be kept in memory when metadata must be appended
|
||||
// before writing it to a file/stream, and/or when the near-losslessly encoded
|
||||
// bitstream must be decoded for distortion computation (lossy will modify the
|
||||
// 'picture' but not the lossless pipeline).
|
||||
// Otherwise directly write the bitstream to a file.
|
||||
use_memory_writer = (out_file != NULL && keep_metadata) ||
|
||||
(!quiet && print_distortion >= 0 && config.lossless &&
|
||||
config.near_lossless < 100);
|
||||
|
||||
// Open the output
|
||||
if (out_file != NULL) {
|
||||
const int use_stdout = !WSTRCMP(out_file, "-");
|
||||
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb");
|
||||
const int use_stdout = !strcmp(out_file, "-");
|
||||
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
||||
if (out == NULL) {
|
||||
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
|
||||
(const W_CHAR*)out_file);
|
||||
fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
|
||||
goto Error;
|
||||
} else {
|
||||
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) {
|
||||
picture.writer = WebPMemoryWrite;
|
||||
picture.custom_ptr = (void*)&memory_writer;
|
||||
} else {
|
||||
if (keep_metadata == 0) {
|
||||
picture.writer = MyWriter;
|
||||
picture.custom_ptr = (void*)out;
|
||||
} else {
|
||||
picture.writer = WebPMemoryWrite;
|
||||
picture.custom_ptr = (void*)&memory_writer;
|
||||
}
|
||||
} else {
|
||||
out = NULL;
|
||||
if (use_memory_writer) {
|
||||
picture.writer = WebPMemoryWrite;
|
||||
picture.custom_ptr = (void*)&memory_writer;
|
||||
}
|
||||
if (!quiet && !short_output) {
|
||||
fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
|
||||
fprintf(stderr, "be performed, but its results discarded.\n\n");
|
||||
@@ -1105,55 +1013,11 @@ int main(int argc, const char* argv[]) {
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
ApplyResizeMode(resize_mode, &picture, &resize_w, &resize_h);
|
||||
if ((resize_w | resize_h) > 0) {
|
||||
WebPPicture picture_no_alpha;
|
||||
if (config.exact) {
|
||||
// If -exact, we can't premultiply RGB by A otherwise RGB is lost if A=0.
|
||||
// We rescale an opaque copy and assemble scaled A and non-premultiplied
|
||||
// RGB channels. This is slower but it's a very uncommon use case. Color
|
||||
// leak at sharp alpha edges is possible.
|
||||
if (!WebPPictureCopy(&picture, &picture_no_alpha)) {
|
||||
fprintf(stderr, "Error! Cannot copy temporary picture\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// We enforced picture.use_argb = 1 above. Now, remove the alpha values.
|
||||
{
|
||||
int x, y;
|
||||
uint32_t* argb_no_alpha = picture_no_alpha.argb;
|
||||
for (y = 0; y < picture_no_alpha.height; ++y) {
|
||||
for (x = 0; x < picture_no_alpha.width; ++x) {
|
||||
argb_no_alpha[x] |= 0xff000000; // Opaque copy.
|
||||
}
|
||||
argb_no_alpha += picture_no_alpha.argb_stride;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WebPPictureRescale(&picture_no_alpha, resize_w, resize_h)) {
|
||||
fprintf(stderr, "Error! Cannot resize temporary picture\n");
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
|
||||
fprintf(stderr, "Error! Cannot resize picture\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (config.exact) { // Put back the alpha information.
|
||||
int x, y;
|
||||
uint32_t* argb_no_alpha = picture_no_alpha.argb;
|
||||
uint32_t* argb = picture.argb;
|
||||
for (y = 0; y < picture_no_alpha.height; ++y) {
|
||||
for (x = 0; x < picture_no_alpha.width; ++x) {
|
||||
argb[x] = (argb[x] & 0xff000000) | (argb_no_alpha[x] & 0x00ffffff);
|
||||
}
|
||||
argb_no_alpha += picture_no_alpha.argb_stride;
|
||||
argb += picture.argb_stride;
|
||||
}
|
||||
WebPPictureFree(&picture_no_alpha);
|
||||
}
|
||||
}
|
||||
if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) {
|
||||
const double preproc_time = StopwatchReadAndReset(&stop_watch);
|
||||
@@ -1163,12 +1027,8 @@ int main(int argc, const char* argv[]) {
|
||||
if (picture.extra_info_type > 0) {
|
||||
AllocExtraInfo(&picture);
|
||||
}
|
||||
// Save original picture for later comparison. Only for lossy as lossless does
|
||||
// not modify 'picture' (even near-lossless).
|
||||
if (print_distortion >= 0 && !config.lossless &&
|
||||
!WebPPictureCopy(&picture, &original_picture)) {
|
||||
fprintf(stderr, "Error! Cannot copy temporary picture\n");
|
||||
goto Error;
|
||||
if (print_distortion >= 0) { // Save original picture for later comparison
|
||||
WebPPictureCopy(&picture, &original_picture);
|
||||
}
|
||||
|
||||
// Compress.
|
||||
@@ -1186,72 +1046,40 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time);
|
||||
}
|
||||
|
||||
// Get the decompressed image for the lossless pipeline.
|
||||
if (!quiet && print_distortion >= 0 && config.lossless) {
|
||||
if (config.near_lossless == 100) {
|
||||
// Pure lossless: image was not modified, make 'original_picture' a view
|
||||
// of 'picture' by copying all members except the freeable pointers.
|
||||
original_picture = picture;
|
||||
original_picture.memory_ = original_picture.memory_argb_ = NULL;
|
||||
} else {
|
||||
// Decode the bitstream stored in 'memory_writer' to get the altered image
|
||||
// to 'picture'; save the 'original_picture' beforehand.
|
||||
assert(use_memory_writer);
|
||||
original_picture = picture;
|
||||
if (!WebPPictureInit(&picture)) { // Do not free 'picture'.
|
||||
fprintf(stderr, "Error! Version mismatch!\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
picture.use_argb = 1;
|
||||
if (!ReadWebP(
|
||||
memory_writer.mem, memory_writer.size, &picture,
|
||||
/*keep_alpha=*/WebPPictureHasTransparency(&original_picture),
|
||||
/*metadata=*/NULL)) {
|
||||
fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n");
|
||||
fprintf(stderr, "Error code: %d (%s)\n", picture.error_code,
|
||||
kErrorMessages[picture.error_code]);
|
||||
goto Error;
|
||||
}
|
||||
picture.stats = original_picture.stats;
|
||||
}
|
||||
original_picture.stats = NULL;
|
||||
}
|
||||
|
||||
// Write the YUV planes to a PGM file. Only available for lossy.
|
||||
// Write info
|
||||
if (dump_file) {
|
||||
if (picture.use_argb) {
|
||||
fprintf(stderr, "Warning: can't dump file (-d option) "
|
||||
"in lossless mode.\n");
|
||||
fprintf(stderr, "Warning: can't dump file (-d option) in lossless mode.");
|
||||
} else if (!DumpPicture(&picture, dump_file)) {
|
||||
WFPRINTF(stderr, "Warning, couldn't dump picture %s\n",
|
||||
(const W_CHAR*)dump_file);
|
||||
fprintf(stderr, "Warning, couldn't dump picture %s\n", dump_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_memory_writer && out != NULL &&
|
||||
!WriteWebPWithMetadata(out, &picture, &memory_writer, &metadata,
|
||||
keep_metadata, &metadata_written)) {
|
||||
fprintf(stderr, "Error writing WebP file!\n");
|
||||
goto Error;
|
||||
}
|
||||
if (keep_metadata != 0) {
|
||||
if (out != NULL) {
|
||||
if (!WriteWebPWithMetadata(out, &picture, &memory_writer,
|
||||
&metadata, keep_metadata, &metadata_written)) {
|
||||
fprintf(stderr, "Error writing WebP file with metadata!\n");
|
||||
goto Error;
|
||||
}
|
||||
} else { // output is disabled, just display the metadata stats.
|
||||
const struct {
|
||||
const MetadataPayload* const payload;
|
||||
int flag;
|
||||
} *iter, info[] = {
|
||||
{ &metadata.exif, METADATA_EXIF },
|
||||
{ &metadata.iccp, METADATA_ICC },
|
||||
{ &metadata.xmp, METADATA_XMP },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
uint32_t unused1 = 0;
|
||||
uint64_t unused2 = 0;
|
||||
|
||||
if (out == NULL && keep_metadata) {
|
||||
// output is disabled, just display the metadata stats.
|
||||
const struct {
|
||||
const MetadataPayload* const payload;
|
||||
int flag;
|
||||
} *iter, info[] = {{&metadata.exif, METADATA_EXIF},
|
||||
{&metadata.iccp, METADATA_ICC},
|
||||
{&metadata.xmp, METADATA_XMP},
|
||||
{NULL, 0}};
|
||||
uint32_t unused1 = 0;
|
||||
uint64_t unused2 = 0;
|
||||
|
||||
for (iter = info; iter->payload != NULL; ++iter) {
|
||||
if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
|
||||
/*flag=*/0, &unused1, &unused2)) {
|
||||
metadata_written |= iter->flag;
|
||||
for (iter = info; iter->payload != NULL; ++iter) {
|
||||
if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
|
||||
0, &unused1, &unused2)) {
|
||||
metadata_written |= iter->flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1287,11 +1115,11 @@ int main(int argc, const char* argv[]) {
|
||||
PrintMetadataInfo(&metadata, metadata_written);
|
||||
}
|
||||
}
|
||||
return_value = EXIT_SUCCESS;
|
||||
return_value = 0;
|
||||
|
||||
Error:
|
||||
WebPMemoryWriterClear(&memory_writer);
|
||||
WebPFree(picture.extra_info);
|
||||
free(picture.extra_info);
|
||||
MetadataFree(&metadata);
|
||||
WebPPictureFree(&picture);
|
||||
WebPPictureFree(&original_picture);
|
||||
@@ -1299,7 +1127,7 @@ int main(int argc, const char* argv[]) {
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
FREE_WARGV_AND_RETURN(return_value);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
#include "../imageio/image_enc.h"
|
||||
#include "../imageio/webpdec.h"
|
||||
#include "./stopwatch.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
static int verbose = 0;
|
||||
static int quiet = 0;
|
||||
@@ -45,7 +42,7 @@ extern void* VP8GetCPUInfo; // opaque forward declaration.
|
||||
|
||||
static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||
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;
|
||||
Stopwatch stop_watch;
|
||||
|
||||
@@ -59,7 +56,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||
if (use_stdout) {
|
||||
fprintf(stderr, "Saved to stdout\n");
|
||||
} else {
|
||||
WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file);
|
||||
fprintf(stderr, "Saved file %s\n", out_file);
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
@@ -70,7 +67,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||
if (use_stdout) {
|
||||
fprintf(stderr, "Error writing to stdout !!\n");
|
||||
} else {
|
||||
WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file);
|
||||
fprintf(stderr, "Error writing file %s !!\n", out_file);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
@@ -78,8 +75,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||
|
||||
static void Help(void) {
|
||||
printf("Usage: dwebp in_file [options] [-o out_file]\n\n"
|
||||
"Decodes the WebP image file to PNG format [Default].\n"
|
||||
"Note: Animated WebP files are not supported.\n\n"
|
||||
"Decodes the WebP image file to PNG format [Default]\n"
|
||||
"Use following options to convert into alternate image formats:\n"
|
||||
" -pam ......... save the raw RGBA samples as a color PAM\n"
|
||||
" -ppm ......... save the raw RGB samples as a color PPM\n"
|
||||
@@ -98,7 +94,7 @@ static void Help(void) {
|
||||
" -alpha_dither use alpha-plane dithering if needed\n"
|
||||
" -mt .......... use multi-threading\n"
|
||||
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
|
||||
" -resize <w> <h> ......... resize output (*after* any cropping)\n"
|
||||
" -resize <w> <h> ......... scale the output (*after* any cropping)\n"
|
||||
" -flip ........ flip the output vertically\n"
|
||||
" -alpha ....... only save the alpha plane\n"
|
||||
" -incremental . use incremental decoding (useful for tests)\n"
|
||||
@@ -135,7 +131,7 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
|
||||
format == RGB_565) ? 2
|
||||
: 4;
|
||||
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;
|
||||
output_buffer->u.RGBA.stride = stride;
|
||||
output_buffer->u.RGBA.size = stride * h;
|
||||
@@ -148,7 +144,7 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
|
||||
uint32_t total_size = stride * h * (has_alpha ? 2 : 1)
|
||||
+ 2 * uv_stride * (h + 1) / 2;
|
||||
assert(format >= YUV && format <= YUVA);
|
||||
external_buffer = (uint8_t*)WebPMalloc(total_size);
|
||||
external_buffer = (uint8_t*)malloc(total_size);
|
||||
if (external_buffer == NULL) return NULL;
|
||||
tmp = external_buffer;
|
||||
output_buffer->u.YUVA.y = tmp;
|
||||
@@ -179,11 +175,10 @@ static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
|
||||
return external_buffer;
|
||||
}
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
int ok = 0;
|
||||
const char* in_file = NULL;
|
||||
const char* out_file = NULL;
|
||||
const char *in_file = NULL;
|
||||
const char *out_file = NULL;
|
||||
|
||||
WebPDecoderConfig config;
|
||||
WebPDecBuffer* const output_buffer = &config.output;
|
||||
@@ -196,20 +191,18 @@ int main(int argc, const char* argv[]) {
|
||||
int incremental = 0;
|
||||
int c;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (!WebPInitDecoderConfig(&config)) {
|
||||
fprintf(stderr, "Library version mismatch!\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} 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")) {
|
||||
format = ALPHA_PLANE_ONLY;
|
||||
} else if (!strcmp(argv[c], "-nofancy")) {
|
||||
@@ -230,7 +223,7 @@ int main(int argc, const char* argv[]) {
|
||||
const int version = WebPGetDecoderVersion();
|
||||
printf("%d.%d.%d\n",
|
||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-pgm")) {
|
||||
format = PGM;
|
||||
} else if (!strcmp(argv[c], "-yuv")) {
|
||||
@@ -291,26 +284,26 @@ int main(int argc, const char* argv[]) {
|
||||
} else if (!strcmp(argv[c], "-incremental")) {
|
||||
incremental = 1;
|
||||
} else if (!strcmp(argv[c], "--")) {
|
||||
if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c);
|
||||
if (c < argc - 1) in_file = argv[++c];
|
||||
break;
|
||||
} else if (argv[c][0] == '-') {
|
||||
fprintf(stderr, "Unknown option '%s'\n", argv[c]);
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
} else {
|
||||
in_file = (const char*)GET_WARGV(argv, c);
|
||||
in_file = argv[c];
|
||||
}
|
||||
|
||||
if (parse_error) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_file == NULL) {
|
||||
fprintf(stderr, "missing input file!!\n");
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (quiet) verbose = 0;
|
||||
@@ -319,7 +312,7 @@ int main(int argc, const char* argv[]) {
|
||||
VP8StatusCode status = VP8_STATUS_OK;
|
||||
size_t data_size = 0;
|
||||
if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
@@ -396,18 +389,18 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
if (out_file != NULL) {
|
||||
if (!quiet) {
|
||||
WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file);
|
||||
fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n",
|
||||
output_buffer->width, output_buffer->height,
|
||||
fprintf(stderr, "Decoded %s. Dimensions: %d x %d %s. Format: %s. "
|
||||
"Now saving...\n",
|
||||
in_file, output_buffer->width, output_buffer->height,
|
||||
bitstream->has_alpha ? " (with alpha)" : "",
|
||||
kFormatType[bitstream->format]);
|
||||
}
|
||||
ok = SaveOutput(output_buffer, format, out_file);
|
||||
} else {
|
||||
if (!quiet) {
|
||||
WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file);
|
||||
fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n",
|
||||
output_buffer->width, output_buffer->height,
|
||||
fprintf(stderr, "File %s can be decoded "
|
||||
"(dimensions: %d x %d %s. Format: %s).\n",
|
||||
in_file, output_buffer->width, output_buffer->height,
|
||||
bitstream->has_alpha ? " (with alpha)" : "",
|
||||
kFormatType[bitstream->format]);
|
||||
fprintf(stderr, "Nothing written; "
|
||||
@@ -416,9 +409,9 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
Exit:
|
||||
WebPFreeDecBuffer(output_buffer);
|
||||
WebPFree((void*)external_buffer);
|
||||
WebPFree((void*)data);
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
free((void*)external_buffer);
|
||||
free((void*)data);
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -12,15 +12,10 @@
|
||||
|
||||
#include "./example_util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// String parsing
|
||||
|
||||
@@ -61,80 +56,3 @@ float ExUtilGetFloat(const char* const v, int* const error) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
|
||||
|
||||
#include "webp/types.h"
|
||||
#include "webp/mux_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
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.
|
||||
int ExUtilGetInts(const char* v, int base, int max_output, int output[]);
|
||||
|
||||
// Reads a file named 'filename' into a WebPData structure. The content of
|
||||
// webp_data is overwritten. Returns false in case of error.
|
||||
int ExUtilReadFileToWebPData(const char* const filename,
|
||||
WebPData* const webp_data);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Command-line arguments
|
||||
|
||||
typedef struct {
|
||||
int argc;
|
||||
const char** argv;
|
||||
WebPData argv_data;
|
||||
int own_argv;
|
||||
} CommandLineArguments;
|
||||
|
||||
// Initializes the structure from the command-line parameters. If there is
|
||||
// only one parameter and it does not start with a '-', then it is assumed to
|
||||
// be a file name. This file will be read and tokenized into command-line
|
||||
// arguments. The content of 'args' is overwritten.
|
||||
// Returns false in case of error (memory allocation failure, non
|
||||
// existing file, too many arguments, ...).
|
||||
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
|
||||
CommandLineArguments* const args);
|
||||
|
||||
// Deallocate all memory and reset 'args'.
|
||||
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@@ -23,23 +23,12 @@
|
||||
|
||||
#ifdef WEBP_HAVE_GIF
|
||||
|
||||
#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <gif_lib.h>
|
||||
#include "sharpyuv/sharpyuv.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/mux.h"
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./gifdec.h"
|
||||
#include "./unicode.h"
|
||||
#include "./unicode_gif.h"
|
||||
|
||||
#if !defined(STDIN_FILENO)
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -71,14 +60,8 @@ static void Help(void) {
|
||||
printf(" -lossy ................. encode image using lossy compression\n");
|
||||
printf(" -mixed ................. for each frame in the image, pick lossy\n"
|
||||
" or lossless compression heuristically\n");
|
||||
printf(" -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(" -q <float> ............. quality factor (0:small..100:big)\n");
|
||||
printf(" -m <int> ............... compression method (0=fast, 6=slowest), "
|
||||
"default=4\n");
|
||||
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
|
||||
printf(" -min_size .............. minimize output size (default:off)\n"
|
||||
" lossless compression by default; can be\n"
|
||||
" combined with -q, -m, -lossy or -mixed\n"
|
||||
@@ -89,10 +72,8 @@ static void Help(void) {
|
||||
printf(" -metadata <string> ..... comma separated list of metadata to\n");
|
||||
printf(" ");
|
||||
printf("copy from the input to the output if present\n");
|
||||
printf(" ");
|
||||
printf("Valid values: all, none, icc, xmp (default)\n");
|
||||
printf(" -loop_compatibility .... use compatibility mode for Chrome\n");
|
||||
printf(" version prior to M62 (inclusive)\n");
|
||||
printf(" "
|
||||
"Valid values: all, none, icc, xmp (default)\n");
|
||||
printf(" -mt .................... use multi-threading if available\n");
|
||||
printf("\n");
|
||||
printf(" -version ............... print version number and exit\n");
|
||||
@@ -103,13 +84,13 @@ static void Help(void) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
int verbose = 0;
|
||||
int gif_error = GIF_ERROR;
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
int ok = 0;
|
||||
const W_CHAR* in_file = NULL, *out_file = NULL;
|
||||
const char *in_file = NULL, *out_file = NULL;
|
||||
FILE* out = NULL;
|
||||
GifFileType* gif = NULL;
|
||||
int frame_duration = 0;
|
||||
int frame_timestamp = 0;
|
||||
@@ -123,7 +104,7 @@ int main(int argc, const char* argv[]) {
|
||||
WebPAnimEncoderOptions enc_options;
|
||||
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 c;
|
||||
int quiet = 0;
|
||||
@@ -134,21 +115,18 @@ int main(int argc, const char* argv[]) {
|
||||
int stored_icc = 0; // Whether we have already stored an ICC profile.
|
||||
WebPData xmp_data;
|
||||
int stored_xmp = 0; // Whether we have already stored an XMP profile.
|
||||
int loop_count = 0; // default: infinite
|
||||
int loop_count = 0;
|
||||
int stored_loop_count = 0; // Whether we have found an explicit loop count.
|
||||
int loop_compatibility = 0;
|
||||
WebPMux* mux = NULL;
|
||||
|
||||
int default_kmin = 1; // Whether to use default kmin value.
|
||||
int default_kmax = 1;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) ||
|
||||
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
|
||||
!WebPPictureInit(&prev_canvas)) {
|
||||
fprintf(stderr, "Error! Version mismatch!\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
config.lossless = 1; // Use lossless compression by default.
|
||||
|
||||
@@ -158,27 +136,21 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
if (argc == 1) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} 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")) {
|
||||
config.lossless = 0;
|
||||
} else if (!strcmp(argv[c], "-mixed")) {
|
||||
enc_options.allow_mixed = 1;
|
||||
config.lossless = 0;
|
||||
} else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
|
||||
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], "-loop_compatibility")) {
|
||||
loop_compatibility = 1;
|
||||
} else if (!strcmp(argv[c], "-q") && c < argc - 1) {
|
||||
config.quality = ExUtilGetFloat(argv[++c], &parse_error);
|
||||
} else if (!strcmp(argv[c], "-m") && c < argc - 1) {
|
||||
@@ -228,7 +200,7 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
||||
(int)(token - start), start);
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
start = token + 1;
|
||||
}
|
||||
@@ -237,14 +209,11 @@ int main(int argc, const char* argv[]) {
|
||||
} 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);
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-quiet")) {
|
||||
quiet = 1;
|
||||
enc_options.verbose = 0;
|
||||
@@ -252,19 +221,19 @@ int main(int argc, const char* argv[]) {
|
||||
verbose = 1;
|
||||
enc_options.verbose = 1;
|
||||
} else if (!strcmp(argv[c], "--")) {
|
||||
if (c < argc - 1) in_file = GET_WARGV(argv, ++c);
|
||||
if (c < argc - 1) in_file = argv[++c];
|
||||
break;
|
||||
} else if (argv[c][0] == '-') {
|
||||
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
} else {
|
||||
in_file = GET_WARGV(argv, c);
|
||||
in_file = argv[c];
|
||||
}
|
||||
|
||||
if (parse_error) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +257,11 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Loop over GIF images
|
||||
@@ -304,7 +277,7 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
if (!DGifGetImageDesc(gif)) goto End;
|
||||
|
||||
if (frame_number == 0) {
|
||||
if (is_first_frame) {
|
||||
if (verbose) {
|
||||
printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight);
|
||||
}
|
||||
@@ -329,11 +302,8 @@ int main(int argc, const char* argv[]) {
|
||||
frame.use_argb = 1;
|
||||
if (!WebPPictureAlloc(&frame)) goto End;
|
||||
GIFClearPic(&frame, NULL);
|
||||
if (!(WebPPictureCopy(&frame, &curr_canvas) &&
|
||||
WebPPictureCopy(&frame, &prev_canvas))) {
|
||||
fprintf(stderr, "Error allocating canvas.\n");
|
||||
goto End;
|
||||
}
|
||||
WebPPictureCopy(&frame, &curr_canvas);
|
||||
WebPPictureCopy(&frame, &prev_canvas);
|
||||
|
||||
// Background color.
|
||||
GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
|
||||
@@ -349,6 +319,7 @@ int main(int argc, const char* argv[]) {
|
||||
"a memory error.\n");
|
||||
goto End;
|
||||
}
|
||||
is_first_frame = 0;
|
||||
}
|
||||
|
||||
// Some even more broken GIF can have sub-rect with zero width/height.
|
||||
@@ -365,25 +336,13 @@ int main(int argc, const char* argv[]) {
|
||||
GIFBlendFrames(&frame, &gif_rect, &curr_canvas);
|
||||
|
||||
if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) {
|
||||
fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number,
|
||||
WebPAnimEncoderGetError(enc));
|
||||
goto End;
|
||||
} else {
|
||||
++frame_number;
|
||||
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
|
||||
}
|
||||
|
||||
// Update canvases.
|
||||
GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas);
|
||||
GIFCopyPixels(&curr_canvas, &prev_canvas);
|
||||
|
||||
// Force frames with a small or no duration to 100ms to be consistent
|
||||
// with web browsers and other transcoding tools. This also avoids
|
||||
// incorrect durations between frames when padding frames are
|
||||
// discarded.
|
||||
if (frame_duration <= 10) {
|
||||
frame_duration = 100;
|
||||
}
|
||||
|
||||
// Update timestamp (for next frame).
|
||||
frame_timestamp += frame_duration;
|
||||
|
||||
@@ -397,7 +356,7 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
case EXTENSION_RECORD_TYPE: {
|
||||
int extension;
|
||||
GifByteType* data = NULL;
|
||||
GifByteType *data = NULL;
|
||||
if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) {
|
||||
goto End;
|
||||
}
|
||||
@@ -427,7 +386,7 @@ int main(int argc, const char* argv[]) {
|
||||
if (verbose) {
|
||||
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.
|
||||
// We only store the first encountered chunk of each type, and
|
||||
// only if requested by the user.
|
||||
@@ -483,25 +442,6 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
|
||||
goto End;
|
||||
}
|
||||
// If there's only one frame, we don't need to handle loop count.
|
||||
if (frame_number == 1) {
|
||||
loop_count = 0;
|
||||
} else if (!loop_compatibility) {
|
||||
if (!stored_loop_count) {
|
||||
// if no loop-count element is seen, the default is '1' (loop-once)
|
||||
// and we need to signal it explicitly in WebP. Note however that
|
||||
// in case there's a single frame, we still don't need to store it.
|
||||
if (frame_number > 1) {
|
||||
stored_loop_count = 1;
|
||||
loop_count = 1;
|
||||
}
|
||||
} else if (loop_count > 0 && loop_count < 65535) {
|
||||
// adapt GIF's semantic to WebP's (except in the infinite-loop case)
|
||||
loop_count += 1;
|
||||
}
|
||||
}
|
||||
// loop_count of 0 is the default (infinite), so no need to signal it
|
||||
if (loop_count == 0) stored_loop_count = 0;
|
||||
|
||||
if (stored_loop_count || stored_icc || stored_xmp) {
|
||||
// Re-mux to add loop count and/or metadata as needed.
|
||||
@@ -562,19 +502,13 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
if (out_file != NULL) {
|
||||
if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes,
|
||||
webp_data.size)) {
|
||||
WFPRINTF(stderr, "Error writing output file: %s\n", out_file);
|
||||
if (!ImgIoUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
|
||||
fprintf(stderr, "Error writing output file: %s\n", out_file);
|
||||
goto End;
|
||||
}
|
||||
if (!quiet) {
|
||||
if (!WSTRCMP(out_file, "-")) {
|
||||
fprintf(stderr, "Saved %d bytes to STDIO\n",
|
||||
(int)webp_data.size);
|
||||
} else {
|
||||
WFPRINTF(stderr, "Saved output file (%d bytes): %s\n",
|
||||
(int)webp_data.size, out_file);
|
||||
}
|
||||
fprintf(stderr, "Saved output file (%d bytes): %s\n",
|
||||
(int)webp_data.size, out_file);
|
||||
}
|
||||
} else {
|
||||
if (!quiet) {
|
||||
@@ -596,6 +530,7 @@ int main(int argc, const char* argv[]) {
|
||||
WebPPictureFree(&curr_canvas);
|
||||
WebPPictureFree(&prev_canvas);
|
||||
WebPAnimEncoderDelete(enc);
|
||||
if (out != NULL && out_file != NULL) fclose(out);
|
||||
|
||||
if (gif_error != GIF_OK) {
|
||||
GIFDisplayError(gif, gif_error);
|
||||
@@ -608,15 +543,15 @@ int main(int argc, const char* argv[]) {
|
||||
#endif
|
||||
}
|
||||
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return !ok;
|
||||
}
|
||||
|
||||
#else // !WEBP_HAVE_GIF
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]);
|
||||
(void)argc;
|
||||
return EXIT_FAILURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
#include "webp/mux_types.h"
|
||||
|
||||
#define GIF_TRANSPARENT_COLOR 0x00000000u
|
||||
@@ -138,7 +137,7 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
||||
}
|
||||
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 (image_desc->Interlace) { // Interlaced image.
|
||||
@@ -169,7 +168,7 @@ int GIFReadFrame(GifFileType* const gif, int transparent_index,
|
||||
End:
|
||||
if (!ok) picture->error_code = sub_image.error_code;
|
||||
WebPPictureFree(&sub_image);
|
||||
WebPFree(tmp);
|
||||
free(tmp);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -318,7 +317,7 @@ void GIFDisplayError(const GifFileType* const gif, int gif_error) {
|
||||
|
||||
#else // !WEBP_HAVE_GIF
|
||||
|
||||
static void ErrorGIFNotAvailable(void) {
|
||||
static void ErrorGIFNotAvailable() {
|
||||
fprintf(stderr, "GIF support not compiled. Please install the libgif-dev "
|
||||
"package before building.\n");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#define WEBP_EXAMPLES_GIFDEC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
||||
@@ -27,59 +27,39 @@
|
||||
#include "../imageio/image_dec.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./stopwatch.h"
|
||||
#include "./unicode.h"
|
||||
#include "sharpyuv/sharpyuv.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/mux.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void Help(void) {
|
||||
printf("Usage:\n\n");
|
||||
printf(" img2webp [file_options] [[frame_options] frame_file]...");
|
||||
printf(" [-o webp_file]\n\n");
|
||||
printf(" img2webp [file-level options] [image files...] "
|
||||
"[per-frame options...]\n");
|
||||
printf("\n");
|
||||
|
||||
printf("File-level options (only used at the start of compression):\n");
|
||||
printf(" -min_size ............ minimize size\n");
|
||||
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
|
||||
printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
|
||||
" (0=only keyframes)\n");
|
||||
printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
|
||||
" (0=disable key-frames altogether)\n");
|
||||
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
|
||||
printf(" -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(" -h ................... this help\n");
|
||||
printf(" -version ............. print version number and exit\n");
|
||||
printf("\n");
|
||||
|
||||
printf("Per-frame options (only used for subsequent images input):\n");
|
||||
printf(" -d <int> ............. frame duration in ms (default: 100)\n");
|
||||
printf(" -lossless ............ use lossless mode (default)\n");
|
||||
printf(" -lossy ............... use lossy mode\n");
|
||||
printf(" -lossless ........... use lossless mode (default)\n");
|
||||
printf(" -lossy ... ........... use lossy mode\n");
|
||||
printf(" -q <float> ........... quality\n");
|
||||
printf(" -m <int> ............. compression method (0=fast, 6=slowest), "
|
||||
"default=4\n");
|
||||
printf(" -exact, -noexact ..... preserve or alter RGB values in transparent "
|
||||
"area\n"
|
||||
" (default: -noexact, may cause artifacts\n"
|
||||
" with lossy animations)\n");
|
||||
printf(" -m <int> ............. method to use\n");
|
||||
|
||||
printf("\n");
|
||||
printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n"
|
||||
" -d 80 in2.tiff -o out.webp\n");
|
||||
printf("\nNote: if a single file name is passed as the argument, the "
|
||||
"arguments will be\n");
|
||||
printf("tokenized from this file. The file name must not start with "
|
||||
"the character '-'.\n");
|
||||
printf("\nSupported input formats:\n %s\n",
|
||||
WebPGetEnabledInputFileFormats());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -98,7 +78,7 @@ static int ReadImage(const char filename[], WebPPicture* const pic) {
|
||||
if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0;
|
||||
reader = WebPGuessImageReader(data, data_size);
|
||||
ok = reader(data, data_size, pic, 1, NULL);
|
||||
WebPFree((void*)data);
|
||||
free((void*)data);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -137,14 +117,14 @@ static int SetLoopCount(int loop_count, WebPData* const webp_data) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, char* argv[]) {
|
||||
const char* output = NULL;
|
||||
WebPAnimEncoder* enc = NULL;
|
||||
int verbose = 0;
|
||||
int pic_num = 0;
|
||||
int duration = 100;
|
||||
int timestamp_ms = 0;
|
||||
int ok = 1;
|
||||
int loop_count = 0;
|
||||
int width = 0, height = 0;
|
||||
WebPAnimEncoderOptions anim_config;
|
||||
@@ -153,34 +133,22 @@ int main(int argc, const char* argv[]) {
|
||||
WebPData webp_data;
|
||||
int c;
|
||||
int have_input = 0;
|
||||
int last_input_index = 0;
|
||||
CommandLineArguments cmd_args;
|
||||
int ok;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
|
||||
if (!ok) FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
|
||||
argc = cmd_args.argc;
|
||||
argv = cmd_args.argv;
|
||||
|
||||
WebPDataInit(&webp_data);
|
||||
if (!WebPAnimEncoderOptionsInit(&anim_config) ||
|
||||
!WebPConfigInit(&config) ||
|
||||
!WebPPictureInit(&pic)) {
|
||||
fprintf(stderr, "Library version mismatch!\n");
|
||||
ok = 0;
|
||||
goto End;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1st pass of option parsing
|
||||
for (c = 0; ok && c < argc; ++c) {
|
||||
for (c = 1; ok && c < argc; ++c) {
|
||||
if (argv[c][0] == '-') {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-o") && c + 1 < argc) {
|
||||
argv[c] = NULL;
|
||||
output = (const char*)GET_WARGV_SHIFTED(argv, ++c);
|
||||
output = argv[++c];
|
||||
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
|
||||
argv[c] = NULL;
|
||||
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
@@ -199,27 +167,11 @@ int main(int argc, const char* argv[]) {
|
||||
} else if (!strcmp(argv[c], "-mixed")) {
|
||||
anim_config.allow_mixed = 1;
|
||||
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")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
} 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;
|
||||
return 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -232,15 +184,13 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
if (!have_input) {
|
||||
fprintf(stderr, "No input file(s) for generating animation!\n");
|
||||
ok = 0;
|
||||
Help();
|
||||
goto End;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// image-reading pass
|
||||
pic_num = 0;
|
||||
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][0] == '-') { // parse local options
|
||||
int parse_error = 0;
|
||||
@@ -258,10 +208,6 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Invalid negative duration (%d)\n", duration);
|
||||
parse_error = 1;
|
||||
}
|
||||
} else if (!strcmp(argv[c], "-exact")) {
|
||||
config.exact = 1;
|
||||
} else if (!strcmp(argv[c], "-noexact")) {
|
||||
config.exact = 0;
|
||||
} else {
|
||||
parse_error = 1; // shouldn't be here.
|
||||
fprintf(stderr, "Unknown option [%s]\n", argv[c]);
|
||||
@@ -281,8 +227,7 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
// read next input image
|
||||
pic.use_argb = 1;
|
||||
ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic);
|
||||
last_input_index = c;
|
||||
ok = ReadImage(argv[c], &pic);
|
||||
if (!ok) goto End;
|
||||
|
||||
if (enc == NULL) {
|
||||
@@ -314,20 +259,13 @@ int main(int argc, const char* argv[]) {
|
||||
if (!ok) goto End;
|
||||
|
||||
if (verbose) {
|
||||
WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n",
|
||||
pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c));
|
||||
fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n",
|
||||
pic_num, timestamp_ms, argv[c]);
|
||||
}
|
||||
timestamp_ms += duration;
|
||||
++pic_num;
|
||||
}
|
||||
|
||||
for (c = last_input_index + 1; c < argc; ++c) {
|
||||
if (argv[c] != NULL) {
|
||||
fprintf(stderr, "Warning: unused option [%s]!"
|
||||
" Frame options go before the input frame.\n", argv[c]);
|
||||
}
|
||||
}
|
||||
|
||||
// add a last fake frame to signal the last duration
|
||||
ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
|
||||
ok = ok && WebPAnimEncoderAssemble(enc, &webp_data);
|
||||
@@ -346,7 +284,7 @@ int main(int argc, const char* argv[]) {
|
||||
if (ok) {
|
||||
if (output != NULL) {
|
||||
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
|
||||
if (ok) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)output);
|
||||
if (ok) fprintf(stderr, "output file: %s ", output);
|
||||
} else {
|
||||
fprintf(stderr, "[no output file specified] ");
|
||||
}
|
||||
@@ -356,7 +294,7 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "[%d frames, %u bytes].\n",
|
||||
pic_num, (unsigned int)webp_data.size);
|
||||
}
|
||||
|
||||
WebPDataClear(&webp_data);
|
||||
ExUtilDeleteCommandLineArguments(&cmd_args);
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -60,4 +60,4 @@ static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif // WEBP_EXAMPLES_STOPWATCH_H_
|
||||
#endif /* WEBP_EXAMPLES_STOPWATCH_H_ */
|
||||
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
239
examples/vwebp.c
239
examples/vwebp.c
@@ -18,7 +18,6 @@
|
||||
#define _POSIX_C_SOURCE 200112L // for setenv
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,7 +42,6 @@
|
||||
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./unicode.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
@@ -58,7 +56,6 @@ static struct {
|
||||
int print_info;
|
||||
int only_deltas;
|
||||
int use_color_profile;
|
||||
int draw_anim_background_color;
|
||||
|
||||
int canvas_width, canvas_height;
|
||||
int loop_count;
|
||||
@@ -208,11 +205,6 @@ static void decode_callback(int what) {
|
||||
}
|
||||
}
|
||||
duration = curr->duration;
|
||||
// Behavior copied from Chrome, cf:
|
||||
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/
|
||||
// platform/graphics/DeferredImageDecoder.cpp?
|
||||
// rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246
|
||||
if (duration <= 10) duration = 100;
|
||||
}
|
||||
if (!Decode()) {
|
||||
kParams.decoding_error = 1;
|
||||
@@ -228,9 +220,6 @@ static void decode_callback(int what) {
|
||||
// Callbacks
|
||||
|
||||
static void HandleKey(unsigned char key, int pos_x, int pos_y) {
|
||||
// Note: rescaling the window or toggling some features during an animation
|
||||
// generates visual artifacts. This is not fixed because refreshing the frame
|
||||
// may require rendering the whole animation from start till current frame.
|
||||
(void)pos_x;
|
||||
(void)pos_y;
|
||||
if (key == 'q' || key == 'Q' || key == 27 /* Esc */) {
|
||||
@@ -258,12 +247,10 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
|
||||
glutPostRedisplay();
|
||||
}
|
||||
}
|
||||
} else if (key == 'b') {
|
||||
kParams.draw_anim_background_color = 1 - kParams.draw_anim_background_color;
|
||||
if (!kParams.has_animation) ClearPreviousFrame();
|
||||
glutPostRedisplay();
|
||||
} else if (key == 'i') {
|
||||
kParams.print_info = 1 - kParams.print_info;
|
||||
// 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();
|
||||
glutPostRedisplay();
|
||||
} else if (key == 'd') {
|
||||
@@ -273,8 +260,8 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
|
||||
}
|
||||
|
||||
static void HandleReshape(int width, int height) {
|
||||
// Note: reshape doesn't preserve aspect ratio, and might
|
||||
// be handling larger-than-screen pictures incorrectly.
|
||||
// TODO(skal): should we preserve aspect ratio?
|
||||
// Also: handle larger-than-screen pictures correctly.
|
||||
glViewport(0, 0, width, height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
@@ -293,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) {
|
||||
return ((color >> shift) & 0xff) / 255.f;
|
||||
return (color >> shift) / 255.f;
|
||||
}
|
||||
|
||||
static void DrawCheckerBoard(void) {
|
||||
@@ -330,43 +304,6 @@ static void DrawCheckerBoard(void) {
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void DrawBackground(void) {
|
||||
// Whole window cleared with clear color, checkerboard rendered on top of it.
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
DrawCheckerBoard();
|
||||
|
||||
// ANIM background color rendered (blend) on top. Default is white for still
|
||||
// images (without ANIM chunk). glClear() can't be used for that (no blend).
|
||||
if (kParams.draw_anim_background_color) {
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glColor4f(GetColorf(kParams.bg_color, 16), // BGRA from spec
|
||||
GetColorf(kParams.bg_color, 8),
|
||||
GetColorf(kParams.bg_color, 0),
|
||||
GetColorf(kParams.bg_color, 24));
|
||||
glRecti(-1, -1, +1, +1);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw background in a scissored rectangle.
|
||||
static void DrawBackgroundScissored(int window_x, int window_y, int frame_w,
|
||||
int frame_h) {
|
||||
// Only update the requested area, not the whole canvas.
|
||||
window_x = window_x * kParams.viewport_width / kParams.canvas_width;
|
||||
window_y = window_y * kParams.viewport_height / kParams.canvas_height;
|
||||
frame_w = frame_w * kParams.viewport_width / kParams.canvas_width;
|
||||
frame_h = frame_h * kParams.viewport_height / kParams.canvas_height;
|
||||
|
||||
// glScissor() takes window coordinates (0,0 at bottom left).
|
||||
window_y = kParams.viewport_height - window_y - frame_h;
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(window_x, window_y, frame_w, frame_h);
|
||||
DrawBackground();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
static void HandleDisplay(void) {
|
||||
const WebPDecBuffer* const pic = kParams.pic;
|
||||
const WebPIterator* const curr = &kParams.curr_frame;
|
||||
@@ -383,21 +320,38 @@ static void HandleDisplay(void) {
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
|
||||
|
||||
if (kParams.only_deltas) {
|
||||
DrawBackground();
|
||||
} else {
|
||||
// The rectangle of the previous frame might be different than the current
|
||||
// frame, so we may need to DrawBackgroundScissored for both.
|
||||
DrawCheckerBoard();
|
||||
} else if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
|
||||
curr->blend_method == WEBP_MUX_NO_BLEND) {
|
||||
// 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) {
|
||||
// Clear the previous frame rectangle.
|
||||
DrawBackgroundScissored(prev->x_offset, prev->y_offset, prev->width,
|
||||
prev->height);
|
||||
}
|
||||
if (curr->blend_method == WEBP_MUX_NO_BLEND) {
|
||||
window_x = prev->x_offset;
|
||||
window_y = kParams.canvas_height - prev->y_offset - prev->height;
|
||||
frame_w = prev->width;
|
||||
frame_h = prev->height;
|
||||
} else { // curr->blend_method == WEBP_MUX_NO_BLEND.
|
||||
// We simulate no-blending behavior by first clearing the current frame
|
||||
// rectangle and then alpha-blending against it.
|
||||
DrawBackgroundScissored(curr->x_offset, curr->y_offset, curr->width,
|
||||
curr->height);
|
||||
// rectangle (to a checker-board) and then alpha-blending against it.
|
||||
window_x = curr->x_offset;
|
||||
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;
|
||||
@@ -410,7 +364,7 @@ static void HandleDisplay(void) {
|
||||
|
||||
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
||||
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);
|
||||
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
||||
@@ -424,101 +378,72 @@ static void HandleDisplay(void) {
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
glFlush();
|
||||
#else
|
||||
glutSwapBuffers();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void StartDisplay(const char* filename) {
|
||||
int width = kParams.canvas_width;
|
||||
int height = kParams.canvas_height;
|
||||
int screen_width, screen_height;
|
||||
const char viewername[] = " - WebP viewer";
|
||||
// max linux file len + viewername string
|
||||
char title[4096 + sizeof(viewername)] = "";
|
||||
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
|
||||
// partially displayed with animated webp + alpha.
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
glutInitDisplayMode(GLUT_RGBA);
|
||||
#else
|
||||
static void StartDisplay(void) {
|
||||
const int width = kParams.canvas_width;
|
||||
const int height = kParams.canvas_height;
|
||||
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;
|
||||
}
|
||||
}
|
||||
snprintf(title, sizeof(title), "%s%s", filename, viewername);
|
||||
glutInitWindowSize(width, height);
|
||||
glutCreateWindow(title);
|
||||
glutCreateWindow("WebP viewer");
|
||||
glutDisplayFunc(HandleDisplay);
|
||||
glutReshapeFunc(HandleReshape);
|
||||
glutIdleFunc(NULL);
|
||||
glutKeyboardFunc(HandleKey);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glClearColor(0, 0, 0, 0); // window will be cleared to black (no blend)
|
||||
DrawBackground();
|
||||
glClearColor(GetColorf(kParams.bg_color, 0),
|
||||
GetColorf(kParams.bg_color, 8),
|
||||
GetColorf(kParams.bg_color, 16),
|
||||
GetColorf(kParams.bg_color, 24));
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
DrawCheckerBoard();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main
|
||||
|
||||
static void Help(void) {
|
||||
printf(
|
||||
"Usage: vwebp in_file [options]\n\n"
|
||||
"Decodes the WebP image file and visualize it using OpenGL\n"
|
||||
"Options are:\n"
|
||||
" -version ..... print version number and exit\n"
|
||||
" -noicc ....... don't use the icc profile if present\n"
|
||||
" -nofancy ..... don't use the fancy YUV420 upscaler\n"
|
||||
" -nofilter .... disable in-loop filtering\n"
|
||||
" -dither <int> dithering strength (0..100), default=50\n"
|
||||
" -noalphadither disable alpha plane dithering\n"
|
||||
" -usebgcolor .. display background color\n"
|
||||
" -mt .......... use multi-threading\n"
|
||||
" -info ........ print info\n"
|
||||
" -h ........... this help message\n"
|
||||
"\n"
|
||||
"Keyboard shortcuts:\n"
|
||||
" 'c' ................ toggle use of color profile\n"
|
||||
" 'b' ................ toggle background color display\n"
|
||||
" 'i' ................ overlay file information\n"
|
||||
" 'd' ................ disable blending & disposal (debug)\n"
|
||||
" 'q' / 'Q' / ESC .... quit\n");
|
||||
printf("Usage: vwebp in_file [options]\n\n"
|
||||
"Decodes the WebP image file and visualize it using OpenGL\n"
|
||||
"Options are:\n"
|
||||
" -version ..... print version number and exit\n"
|
||||
" -noicc ....... don't use the icc profile if present\n"
|
||||
" -nofancy ..... don't use the fancy YUV420 upscaler\n"
|
||||
" -nofilter .... disable in-loop filtering\n"
|
||||
" -dither <int> dithering strength (0..100), default=50\n"
|
||||
" -noalphadither disable alpha plane dithering\n"
|
||||
" -mt .......... use multi-threading\n"
|
||||
" -info ........ print info\n"
|
||||
" -h ........... this help message\n"
|
||||
"\n"
|
||||
"Keyboard shortcuts:\n"
|
||||
" 'c' ................ toggle use of color profile\n"
|
||||
" 'i' ................ overlay file information\n"
|
||||
" 'd' ................ disable blending & disposal (debug)\n"
|
||||
" 'q' / 'Q' / ESC .... quit\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int c, file_name_argv_index = 1;
|
||||
int main(int argc, char *argv[]) {
|
||||
int c;
|
||||
WebPDecoderConfig* const config = &kParams.config;
|
||||
WebPIterator* const curr = &kParams.curr_frame;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (!WebPInitDecoderConfig(config)) {
|
||||
fprintf(stderr, "Library version mismatch!\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
config->options.dithering_strength = 50;
|
||||
config->options.alpha_dithering_strength = 100;
|
||||
kParams.use_color_profile = 1;
|
||||
// Background color hidden by default to see transparent areas.
|
||||
kParams.draw_anim_background_color = 0;
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
int parse_error = 0;
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-noicc")) {
|
||||
kParams.use_color_profile = 0;
|
||||
} else if (!strcmp(argv[c], "-nofancy")) {
|
||||
@@ -527,8 +452,6 @@ int main(int argc, char* argv[]) {
|
||||
config->options.bypass_filtering = 1;
|
||||
} else if (!strcmp(argv[c], "-noalphadither")) {
|
||||
config->options.alpha_dithering_strength = 0;
|
||||
} else if (!strcmp(argv[c], "-usebgcolor")) {
|
||||
kParams.draw_anim_background_color = 1;
|
||||
} else if (!strcmp(argv[c], "-dither") && c + 1 < argc) {
|
||||
config->options.dithering_strength =
|
||||
ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||
@@ -541,34 +464,30 @@ int main(int argc, char* argv[]) {
|
||||
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
|
||||
dec_version & 0xff, (dmux_version >> 16) & 0xff,
|
||||
(dmux_version >> 8) & 0xff, dmux_version & 0xff);
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[c], "-mt")) {
|
||||
config->options.use_threads = 1;
|
||||
} else if (!strcmp(argv[c], "--")) {
|
||||
if (c < argc - 1) {
|
||||
kParams.file_name = (const char*)GET_WARGV(argv, ++c);
|
||||
file_name_argv_index = c;
|
||||
}
|
||||
if (c < argc - 1) kParams.file_name = argv[++c];
|
||||
break;
|
||||
} else if (argv[c][0] == '-') {
|
||||
printf("Unknown option '%s'\n", argv[c]);
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
} else {
|
||||
kParams.file_name = (const char*)GET_WARGV(argv, c);
|
||||
file_name_argv_index = c;
|
||||
kParams.file_name = argv[c];
|
||||
}
|
||||
|
||||
if (parse_error) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (kParams.file_name == NULL) {
|
||||
printf("missing input file!!\n");
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ImgIoUtilReadFile(kParams.file_name,
|
||||
@@ -622,7 +541,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
|
||||
// We take this into account by bumping up loop_count.
|
||||
if (!WebPDemuxGetFrame(kParams.dmux, 0, curr)) goto Error;
|
||||
WebPDemuxGetFrame(kParams.dmux, 0, curr);
|
||||
if (kParams.loop_count) ++kParams.loop_count;
|
||||
|
||||
#if defined(__unix__) || defined(__CYGWIN__)
|
||||
@@ -636,26 +555,26 @@ int main(int argc, char* argv[]) {
|
||||
#ifdef FREEGLUT
|
||||
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
|
||||
#endif
|
||||
StartDisplay(argv[file_name_argv_index]);
|
||||
StartDisplay();
|
||||
|
||||
if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0);
|
||||
glutMainLoop();
|
||||
|
||||
// Should only be reached when using FREEGLUT:
|
||||
ClearParams();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
ClearParams();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else // !WEBP_HAVE_GL
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]);
|
||||
(void)argc;
|
||||
return EXIT_FAILURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,19 +14,15 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "webp/config.h"
|
||||
#endif
|
||||
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/format_constants.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
@@ -34,17 +30,16 @@
|
||||
|
||||
#define LOG_ERROR(MESSAGE) \
|
||||
do { \
|
||||
if (webp_info->show_diagnosis) { \
|
||||
if (webp_info->show_diagnosis_) { \
|
||||
fprintf(stderr, "Error: %s\n", MESSAGE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LOG_WARN(MESSAGE) \
|
||||
do { \
|
||||
if (webp_info->show_diagnosis) { \
|
||||
if (webp_info->show_diagnosis_) { \
|
||||
fprintf(stderr, "Warning: %s\n", MESSAGE); \
|
||||
} \
|
||||
++webp_info->num_warnings; \
|
||||
} while (0)
|
||||
|
||||
static const char* const kFormats[3] = {
|
||||
@@ -92,52 +87,51 @@ typedef enum ChunkID {
|
||||
} ChunkID;
|
||||
|
||||
typedef struct {
|
||||
size_t start;
|
||||
size_t end;
|
||||
const uint8_t* buf;
|
||||
size_t start_;
|
||||
size_t end_;
|
||||
const uint8_t* buf_;
|
||||
} MemBuffer;
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
const uint8_t* payload;
|
||||
ChunkID id;
|
||||
size_t offset_;
|
||||
size_t size_;
|
||||
const uint8_t* payload_;
|
||||
ChunkID id_;
|
||||
} ChunkData;
|
||||
|
||||
typedef struct WebPInfo {
|
||||
int canvas_width;
|
||||
int canvas_height;
|
||||
int loop_count;
|
||||
int num_frames;
|
||||
int chunk_counts[CHUNK_TYPES];
|
||||
int anmf_subchunk_counts[3]; // 0 VP8; 1 VP8L; 2 ALPH.
|
||||
uint32_t bgcolor;
|
||||
int feature_flags;
|
||||
int has_alpha;
|
||||
int canvas_width_;
|
||||
int canvas_height_;
|
||||
int loop_count_;
|
||||
int num_frames_;
|
||||
int chunk_counts_[CHUNK_TYPES];
|
||||
int anmf_subchunk_counts_[3]; // 0 VP8; 1 VP8L; 2 ALPH.
|
||||
uint32_t bgcolor_;
|
||||
int feature_flags_;
|
||||
int has_alpha_;
|
||||
// Used for parsing ANMF chunks.
|
||||
int frame_width, frame_height;
|
||||
size_t anim_frame_data_size;
|
||||
int is_processing_anim_frame, seen_alpha_subchunk, seen_image_subchunk;
|
||||
int frame_width_, frame_height_;
|
||||
size_t anim_frame_data_size_;
|
||||
int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_;
|
||||
// Print output control.
|
||||
int quiet, show_diagnosis, show_summary;
|
||||
int num_warnings;
|
||||
int parse_bitstream;
|
||||
int quiet_, show_diagnosis_, show_summary_;
|
||||
int parse_bitstream_;
|
||||
} WebPInfo;
|
||||
|
||||
static void WebPInfoInit(WebPInfo* const webp_info) {
|
||||
memset(webp_info, 0, sizeof(*webp_info));
|
||||
}
|
||||
|
||||
static const uint32_t kWebPChunkTags[CHUNK_TYPES] = {
|
||||
MKFOURCC('V', 'P', '8', ' '),
|
||||
MKFOURCC('V', 'P', '8', 'L'),
|
||||
MKFOURCC('V', 'P', '8', 'X'),
|
||||
MKFOURCC('A', 'L', 'P', 'H'),
|
||||
MKFOURCC('A', 'N', 'I', 'M'),
|
||||
MKFOURCC('A', 'N', 'M', 'F'),
|
||||
MKFOURCC('I', 'C', 'C', 'P'),
|
||||
MKFOURCC('E', 'X', 'I', 'F'),
|
||||
MKFOURCC('X', 'M', 'P', ' '),
|
||||
static const char kWebPChunkTags[CHUNK_TYPES][4] = {
|
||||
{ 'V', 'P', '8', ' ' },
|
||||
{ 'V', 'P', '8', 'L' },
|
||||
{ 'V', 'P', '8', 'X' },
|
||||
{ 'A', 'L', 'P', 'H' },
|
||||
{ 'A', 'N', 'I', 'M' },
|
||||
{ 'A', 'N', 'M', 'F' },
|
||||
{ 'I', 'C', 'C', 'P' },
|
||||
{ 'E', 'X', 'I', 'F' },
|
||||
{ 'X', 'M', 'P', ' ' },
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -187,25 +181,25 @@ static int ReadFileToWebPData(const char* const filename,
|
||||
// MemBuffer object.
|
||||
|
||||
static void InitMemBuffer(MemBuffer* const mem, const WebPData* webp_data) {
|
||||
mem->buf = webp_data->bytes;
|
||||
mem->start = 0;
|
||||
mem->end = webp_data->size;
|
||||
mem->buf_ = webp_data->bytes;
|
||||
mem->start_ = 0;
|
||||
mem->end_ = webp_data->size;
|
||||
}
|
||||
|
||||
static size_t MemDataSize(const MemBuffer* const mem) {
|
||||
return (mem->end - mem->start);
|
||||
return (mem->end_ - mem->start_);
|
||||
}
|
||||
|
||||
static const uint8_t* GetBuffer(MemBuffer* const mem) {
|
||||
return mem->buf + mem->start;
|
||||
return mem->buf_ + mem->start_;
|
||||
}
|
||||
|
||||
static void Skip(MemBuffer* const mem, size_t size) {
|
||||
mem->start += size;
|
||||
mem->start_ += size;
|
||||
}
|
||||
|
||||
static uint32_t ReadMemBufLE32(MemBuffer* const mem) {
|
||||
const uint8_t* const data = mem->buf + mem->start;
|
||||
const uint8_t* const data = mem->buf_ + mem->start_;
|
||||
const uint32_t val = GetLE32(data);
|
||||
assert(MemDataSize(mem) >= 4);
|
||||
Skip(mem, 4);
|
||||
@@ -239,20 +233,20 @@ static int GetSignedBits(const uint8_t* const data, size_t data_size, size_t nb,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define GET_BITS(v, n) \
|
||||
do { \
|
||||
if (!GetBits(data, data_size, n, &(v), bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossy bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
#define GET_BITS(v, n) \
|
||||
do { \
|
||||
if (!GetBits(data, data_size, n, &v, bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossy bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GET_SIGNED_BITS(v, n) \
|
||||
do { \
|
||||
if (!GetSignedBits(data, data_size, n, &(v), bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossy bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
#define GET_SIGNED_BITS(v, n) \
|
||||
do { \
|
||||
if (!GetSignedBits(data, data_size, n, &v, bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossy bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static WebPInfoStatus ParseLossySegmentHeader(const WebPInfo* const webp_info,
|
||||
@@ -336,8 +330,8 @@ static WebPInfoStatus ParseLossyFilterHeader(const WebPInfo* const webp_info,
|
||||
|
||||
static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
|
||||
const WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
|
||||
const uint32_t bits = (uint32_t)data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
const int key_frame = !(bits & 1);
|
||||
const int profile = (bits >> 1) & 7;
|
||||
@@ -346,10 +340,10 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
|
||||
WebPInfoStatus status = WEBP_INFO_OK;
|
||||
uint64_t bit_position = 0;
|
||||
uint64_t* const bit_pos = &bit_position;
|
||||
int colorspace, clamp_type;
|
||||
int color_space, clamp_type;
|
||||
printf(" Parsing lossy bitstream...\n");
|
||||
// Calling WebPGetFeatures() in ProcessImageChunk() should ensure this.
|
||||
assert(chunk_data->size >= CHUNK_HEADER_SIZE + 10);
|
||||
assert(chunk_data->size_ >= CHUNK_HEADER_SIZE + 10);
|
||||
if (profile > 3) {
|
||||
LOG_ERROR("Unknown profile.");
|
||||
return WEBP_INFO_BITSTREAM_ERROR;
|
||||
@@ -360,12 +354,12 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
|
||||
}
|
||||
data += 3;
|
||||
data_size -= 3;
|
||||
printf(
|
||||
" Key frame: %s\n"
|
||||
" Profile: %d\n"
|
||||
" Display: Yes\n"
|
||||
" Part. 0 length: %d\n",
|
||||
key_frame ? "Yes" : "No", profile, partition0_length);
|
||||
printf(" Key frame: %s\n"
|
||||
" Profile: %d\n"
|
||||
" Display: %s\n"
|
||||
" Part. 0 length: %d\n",
|
||||
key_frame ? "Yes" : "No", profile,
|
||||
display ? "Yes" : "No", partition0_length);
|
||||
if (key_frame) {
|
||||
if (!(data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a)) {
|
||||
LOG_ERROR("Invalid lossy bitstream signature.");
|
||||
@@ -387,9 +381,9 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
|
||||
LOG_ERROR("Bad partition length.");
|
||||
return WEBP_INFO_BITSTREAM_ERROR;
|
||||
}
|
||||
GET_BITS(colorspace, 1);
|
||||
GET_BITS(color_space, 1);
|
||||
GET_BITS(clamp_type, 1);
|
||||
printf(" Color space: %d\n", colorspace);
|
||||
printf(" Color space: %d\n", color_space);
|
||||
printf(" Clamp type: %d\n", clamp_type);
|
||||
status = ParseLossySegmentHeader(webp_info, data, data_size, bit_pos);
|
||||
if (status != WEBP_INFO_OK) return status;
|
||||
@@ -468,12 +462,12 @@ static int LLGetBits(const uint8_t* const data, size_t data_size, size_t nb,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LL_GET_BITS(v, n) \
|
||||
do { \
|
||||
if (!LLGetBits(data, data_size, n, &(v), bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossless bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
#define LL_GET_BITS(v, n) \
|
||||
do { \
|
||||
if (!LLGetBits(data, data_size, n, &v, bit_pos)) { \
|
||||
LOG_ERROR("Truncated lossless bitstream."); \
|
||||
return WEBP_INFO_TRUNCATED_DATA; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info,
|
||||
@@ -507,8 +501,8 @@ static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info,
|
||||
|
||||
static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
|
||||
uint64_t bit_position = 0;
|
||||
uint64_t* const bit_pos = &bit_position;
|
||||
WebPInfoStatus status;
|
||||
@@ -543,8 +537,8 @@ static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
|
||||
|
||||
static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
size_t data_size = chunk_data->size - CHUNK_HEADER_SIZE;
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
|
||||
if (data_size <= ALPHA_HEADER_LEN) {
|
||||
LOG_ERROR("Truncated ALPH chunk.");
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
@@ -585,7 +579,7 @@ static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
|
||||
// -----------------------------------------------------------------------------
|
||||
// Chunk parsing.
|
||||
|
||||
static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info,
|
||||
static WebPInfoStatus ParseRIFFHeader(const WebPInfo* const webp_info,
|
||||
MemBuffer* const mem) {
|
||||
const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
|
||||
size_t riff_size;
|
||||
@@ -609,14 +603,14 @@ static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info,
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
riff_size += CHUNK_HEADER_SIZE;
|
||||
if (!webp_info->quiet) {
|
||||
if (!webp_info->quiet_) {
|
||||
printf("RIFF HEADER:\n");
|
||||
printf(" File size: %6d\n", (int)riff_size);
|
||||
}
|
||||
if (riff_size < mem->end) {
|
||||
if (riff_size < mem->end_) {
|
||||
LOG_WARN("RIFF size is smaller than the file size.");
|
||||
mem->end = riff_size;
|
||||
} else if (riff_size > mem->end) {
|
||||
mem->end_ = riff_size;
|
||||
} else if (riff_size > mem->end_) {
|
||||
LOG_ERROR("Truncated data detected when parsing RIFF payload.");
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
}
|
||||
@@ -632,7 +626,7 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
|
||||
LOG_ERROR("Truncated data detected when parsing chunk header.");
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
} else {
|
||||
const size_t chunk_start_offset = mem->start;
|
||||
const size_t chunk_start_offset = mem->start_;
|
||||
const uint32_t fourcc = ReadMemBufLE32(mem);
|
||||
const uint32_t payload_size = ReadMemBufLE32(mem);
|
||||
const uint32_t payload_size_padded = payload_size + (payload_size & 1);
|
||||
@@ -647,13 +641,13 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
}
|
||||
for (i = 0; i < CHUNK_TYPES; ++i) {
|
||||
if (kWebPChunkTags[i] == fourcc) break;
|
||||
if (!memcmp(kWebPChunkTags[i], &fourcc, TAG_SIZE)) break;
|
||||
}
|
||||
chunk_data->offset = chunk_start_offset;
|
||||
chunk_data->size = chunk_size;
|
||||
chunk_data->id = (ChunkID)i;
|
||||
chunk_data->payload = GetBuffer(mem);
|
||||
if (chunk_data->id == CHUNK_ANMF) {
|
||||
chunk_data->offset_ = chunk_start_offset;
|
||||
chunk_data->size_ = chunk_size;
|
||||
chunk_data->id_ = (ChunkID)i;
|
||||
chunk_data->payload_ = GetBuffer(mem);
|
||||
if (chunk_data->id_ == CHUNK_ANMF) {
|
||||
if (payload_size != payload_size_padded) {
|
||||
LOG_ERROR("ANMF chunk size should always be even.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
@@ -672,39 +666,39 @@ static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info,
|
||||
|
||||
static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
if (webp_info->chunk_counts[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts[CHUNK_VP8L] ||
|
||||
webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts_[CHUNK_VP8L] ||
|
||||
webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
LOG_ERROR("Already seen a VP8/VP8L/VP8X chunk when parsing VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (chunk_data->size != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
|
||||
if (chunk_data->size_ != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
|
||||
LOG_ERROR("Corrupted VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
++webp_info->chunk_counts[CHUNK_VP8X];
|
||||
webp_info->feature_flags = *data;
|
||||
++webp_info->chunk_counts_[CHUNK_VP8X];
|
||||
webp_info->feature_flags_ = *data;
|
||||
data += 4;
|
||||
webp_info->canvas_width = 1 + ReadLE24(&data);
|
||||
webp_info->canvas_height = 1 + ReadLE24(&data);
|
||||
if (!webp_info->quiet) {
|
||||
webp_info->canvas_width_ = 1 + ReadLE24(&data);
|
||||
webp_info->canvas_height_ = 1 + ReadLE24(&data);
|
||||
if (!webp_info->quiet_) {
|
||||
printf(" ICCP: %d\n Alpha: %d\n EXIF: %d\n XMP: %d\n Animation: %d\n",
|
||||
(webp_info->feature_flags & ICCP_FLAG) != 0,
|
||||
(webp_info->feature_flags & ALPHA_FLAG) != 0,
|
||||
(webp_info->feature_flags & EXIF_FLAG) != 0,
|
||||
(webp_info->feature_flags & XMP_FLAG) != 0,
|
||||
(webp_info->feature_flags & ANIMATION_FLAG) != 0);
|
||||
(webp_info->feature_flags_ & ICCP_FLAG) != 0,
|
||||
(webp_info->feature_flags_ & ALPHA_FLAG) != 0,
|
||||
(webp_info->feature_flags_ & EXIF_FLAG) != 0,
|
||||
(webp_info->feature_flags_ & XMP_FLAG) != 0,
|
||||
(webp_info->feature_flags_ & ANIMATION_FLAG) != 0);
|
||||
printf(" Canvas size %d x %d\n",
|
||||
webp_info->canvas_width, webp_info->canvas_height);
|
||||
webp_info->canvas_width_, webp_info->canvas_height_);
|
||||
}
|
||||
if (webp_info->canvas_width > MAX_CANVAS_SIZE) {
|
||||
if (webp_info->canvas_width_ > MAX_CANVAS_SIZE) {
|
||||
LOG_WARN("Canvas width is out of range in VP8X chunk.");
|
||||
}
|
||||
if (webp_info->canvas_height > MAX_CANVAS_SIZE) {
|
||||
if (webp_info->canvas_height_ > MAX_CANVAS_SIZE) {
|
||||
LOG_WARN("Canvas height is out of range in VP8X chunk.");
|
||||
}
|
||||
if ((uint64_t)webp_info->canvas_width * webp_info->canvas_height >
|
||||
if ((uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
|
||||
MAX_IMAGE_AREA) {
|
||||
LOG_WARN("Canvas area is out of range in VP8X chunk.");
|
||||
}
|
||||
@@ -713,27 +707,27 @@ static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data,
|
||||
|
||||
static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
LOG_ERROR("ANIM chunk detected before VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (chunk_data->size != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
|
||||
if (chunk_data->size_ != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) {
|
||||
LOG_ERROR("Corrupted ANIM chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
webp_info->bgcolor = ReadLE32(&data);
|
||||
webp_info->loop_count = ReadLE16(&data);
|
||||
++webp_info->chunk_counts[CHUNK_ANIM];
|
||||
if (!webp_info->quiet) {
|
||||
webp_info->bgcolor_ = ReadLE32(&data);
|
||||
webp_info->loop_count_ = ReadLE16(&data);
|
||||
++webp_info->chunk_counts_[CHUNK_ANIM];
|
||||
if (!webp_info->quiet_) {
|
||||
printf(" Background color:(ARGB) %02x %02x %02x %02x\n",
|
||||
(webp_info->bgcolor >> 24) & 0xff,
|
||||
(webp_info->bgcolor >> 16) & 0xff,
|
||||
(webp_info->bgcolor >> 8) & 0xff,
|
||||
webp_info->bgcolor & 0xff);
|
||||
printf(" Loop count : %d\n", webp_info->loop_count);
|
||||
(webp_info->bgcolor_ >> 24) & 0xff,
|
||||
(webp_info->bgcolor_ >> 16) & 0xff,
|
||||
(webp_info->bgcolor_ >> 8) & 0xff,
|
||||
webp_info->bgcolor_ & 0xff);
|
||||
printf(" Loop count : %d\n", webp_info->loop_count_);
|
||||
}
|
||||
if (webp_info->loop_count > MAX_LOOP_COUNT) {
|
||||
if (webp_info->loop_count_ > MAX_LOOP_COUNT) {
|
||||
LOG_WARN("Loop count is out of range in ANIM chunk.");
|
||||
}
|
||||
return WEBP_INFO_OK;
|
||||
@@ -741,17 +735,17 @@ static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data,
|
||||
|
||||
static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload;
|
||||
const uint8_t* data = chunk_data->payload_;
|
||||
int offset_x, offset_y, width, height, duration, blend, dispose, temp;
|
||||
if (webp_info->is_processing_anim_frame) {
|
||||
if (webp_info->is_processing_anim_frame_) {
|
||||
LOG_ERROR("ANMF chunk detected within another ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (!webp_info->chunk_counts[CHUNK_ANIM]) {
|
||||
if (!webp_info->chunk_counts_[CHUNK_ANIM]) {
|
||||
LOG_ERROR("ANMF chunk detected before ANIM chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (chunk_data->size <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) {
|
||||
if (chunk_data->size_ <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) {
|
||||
LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
}
|
||||
@@ -763,8 +757,8 @@ static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
|
||||
temp = *data;
|
||||
dispose = temp & 1;
|
||||
blend = (temp >> 1) & 1;
|
||||
++webp_info->chunk_counts[CHUNK_ANMF];
|
||||
if (!webp_info->quiet) {
|
||||
++webp_info->chunk_counts_[CHUNK_ANMF];
|
||||
if (!webp_info->quiet_) {
|
||||
printf(" Offset_X: %d\n Offset_Y: %d\n Width: %d\n Height: %d\n"
|
||||
" Duration: %d\n Dispose: %d\n Blend: %d\n",
|
||||
offset_x, offset_y, width, height, duration, dispose, blend);
|
||||
@@ -777,92 +771,93 @@ static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data,
|
||||
LOG_ERROR("Invalid offset parameters in ANMF chunk.");
|
||||
return WEBP_INFO_INVALID_PARAM;
|
||||
}
|
||||
if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width ||
|
||||
(uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height) {
|
||||
if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width_ ||
|
||||
(uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height_) {
|
||||
LOG_ERROR("Frame exceeds canvas in ANMF chunk.");
|
||||
return WEBP_INFO_INVALID_PARAM;
|
||||
}
|
||||
webp_info->is_processing_anim_frame = 1;
|
||||
webp_info->seen_alpha_subchunk = 0;
|
||||
webp_info->seen_image_subchunk = 0;
|
||||
webp_info->frame_width = width;
|
||||
webp_info->frame_height = height;
|
||||
webp_info->anim_frame_data_size =
|
||||
chunk_data->size - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE;
|
||||
webp_info->is_processing_anim_frame_ = 1;
|
||||
webp_info->seen_alpha_subchunk_ = 0;
|
||||
webp_info->seen_image_subchunk_ = 0;
|
||||
webp_info->frame_width_ = width;
|
||||
webp_info->frame_height_ = height;
|
||||
webp_info->anim_frame_data_size_ =
|
||||
chunk_data->size_ - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE;
|
||||
return WEBP_INFO_OK;
|
||||
}
|
||||
|
||||
static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
const uint8_t* data = chunk_data->payload - CHUNK_HEADER_SIZE;
|
||||
const uint8_t* data = chunk_data->payload_ - CHUNK_HEADER_SIZE;
|
||||
WebPBitstreamFeatures features;
|
||||
const VP8StatusCode vp8_status =
|
||||
WebPGetFeatures(data, chunk_data->size, &features);
|
||||
WebPGetFeatures(data, chunk_data->size_, &features);
|
||||
if (vp8_status != VP8_STATUS_OK) {
|
||||
LOG_ERROR("VP8/VP8L bitstream error.");
|
||||
return WEBP_INFO_BITSTREAM_ERROR;
|
||||
}
|
||||
if (!webp_info->quiet) {
|
||||
if (!webp_info->quiet_) {
|
||||
assert(features.format >= 0 && features.format <= 2);
|
||||
printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n"
|
||||
" Format: %s (%d)\n",
|
||||
features.width, features.height, features.has_alpha,
|
||||
features.has_animation, kFormats[features.format], features.format);
|
||||
}
|
||||
if (webp_info->is_processing_anim_frame) {
|
||||
++webp_info->anmf_subchunk_counts[chunk_data->id == CHUNK_VP8 ? 0 : 1];
|
||||
if (chunk_data->id == CHUNK_VP8L && webp_info->seen_alpha_subchunk) {
|
||||
if (webp_info->is_processing_anim_frame_) {
|
||||
++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1];
|
||||
if (chunk_data->id_ == CHUNK_VP8L && webp_info->seen_alpha_subchunk_) {
|
||||
LOG_ERROR("Both VP8L and ALPH sub-chunks are present in an ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->frame_width != features.width ||
|
||||
webp_info->frame_height != features.height) {
|
||||
if (webp_info->frame_width_ != features.width ||
|
||||
webp_info->frame_height_ != features.height) {
|
||||
LOG_ERROR("Frame size in VP8/VP8L sub-chunk differs from ANMF header.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->seen_image_subchunk) {
|
||||
if (webp_info->seen_image_subchunk_) {
|
||||
LOG_ERROR("Consecutive VP8/VP8L sub-chunks in an ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
} else {
|
||||
webp_info->seen_image_subchunk_ = 1;
|
||||
}
|
||||
webp_info->seen_image_subchunk = 1;
|
||||
} else {
|
||||
if (webp_info->chunk_counts[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts[CHUNK_VP8L]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts_[CHUNK_VP8L]) {
|
||||
LOG_ERROR("Multiple VP8/VP8L chunks detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (chunk_data->id == CHUNK_VP8L &&
|
||||
webp_info->chunk_counts[CHUNK_ALPHA]) {
|
||||
if (chunk_data->id_ == CHUNK_VP8L &&
|
||||
webp_info->chunk_counts_[CHUNK_ALPHA]) {
|
||||
LOG_WARN("Both VP8L and ALPH chunks are detected.");
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_ANIM] ||
|
||||
webp_info->chunk_counts[CHUNK_ANMF]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_ANIM] ||
|
||||
webp_info->chunk_counts_[CHUNK_ANMF]) {
|
||||
LOG_ERROR("VP8/VP8L chunk and ANIM/ANMF chunk are both detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
if (webp_info->canvas_width != features.width ||
|
||||
webp_info->canvas_height != features.height) {
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
if (webp_info->canvas_width_ != features.width ||
|
||||
webp_info->canvas_height_ != features.height) {
|
||||
LOG_ERROR("Image size in VP8/VP8L chunk differs from VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
} else {
|
||||
webp_info->canvas_width = features.width;
|
||||
webp_info->canvas_height = features.height;
|
||||
if (webp_info->canvas_width < 1 || webp_info->canvas_height < 1 ||
|
||||
webp_info->canvas_width > MAX_CANVAS_SIZE ||
|
||||
webp_info->canvas_height > MAX_CANVAS_SIZE ||
|
||||
(uint64_t)webp_info->canvas_width * webp_info->canvas_height >
|
||||
webp_info->canvas_width_ = features.width;
|
||||
webp_info->canvas_height_ = features.height;
|
||||
if (webp_info->canvas_width_ < 1 || webp_info->canvas_height_ < 1 ||
|
||||
webp_info->canvas_width_ > MAX_CANVAS_SIZE ||
|
||||
webp_info->canvas_height_ > MAX_CANVAS_SIZE ||
|
||||
(uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ >
|
||||
MAX_IMAGE_AREA) {
|
||||
LOG_WARN("Invalid parameters in VP8/VP8L chunk.");
|
||||
}
|
||||
}
|
||||
++webp_info->chunk_counts[chunk_data->id];
|
||||
++webp_info->chunk_counts_[chunk_data->id_];
|
||||
}
|
||||
++webp_info->num_frames;
|
||||
webp_info->has_alpha |= features.has_alpha;
|
||||
if (webp_info->parse_bitstream) {
|
||||
const int is_lossy = (chunk_data->id == CHUNK_VP8);
|
||||
++webp_info->num_frames_;
|
||||
webp_info->has_alpha_ |= features.has_alpha;
|
||||
if (webp_info->parse_bitstream_) {
|
||||
const int is_lossy = (chunk_data->id_ == CHUNK_VP8);
|
||||
const WebPInfoStatus status =
|
||||
is_lossy ? ParseLossyHeader(chunk_data, webp_info)
|
||||
: ParseLosslessHeader(chunk_data, webp_info);
|
||||
@@ -873,41 +868,41 @@ static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
|
||||
|
||||
static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
if (webp_info->is_processing_anim_frame) {
|
||||
++webp_info->anmf_subchunk_counts[2];
|
||||
if (webp_info->seen_alpha_subchunk) {
|
||||
if (webp_info->is_processing_anim_frame_) {
|
||||
++webp_info->anmf_subchunk_counts_[2];
|
||||
if (webp_info->seen_alpha_subchunk_) {
|
||||
LOG_ERROR("Consecutive ALPH sub-chunks in an ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
} else {
|
||||
webp_info->seen_alpha_subchunk_ = 1;
|
||||
}
|
||||
webp_info->seen_alpha_subchunk = 1;
|
||||
|
||||
if (webp_info->seen_image_subchunk) {
|
||||
if (webp_info->seen_image_subchunk_) {
|
||||
LOG_ERROR("ALPHA sub-chunk detected after VP8 sub-chunk "
|
||||
"in an ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (webp_info->chunk_counts[CHUNK_ANIM] ||
|
||||
webp_info->chunk_counts[CHUNK_ANMF]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_ANIM] ||
|
||||
webp_info->chunk_counts_[CHUNK_ANMF]) {
|
||||
LOG_ERROR("ALPHA chunk and ANIM/ANMF chunk are both detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
LOG_ERROR("ALPHA chunk detected before VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_VP8]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8]) {
|
||||
LOG_ERROR("ALPHA chunk detected after VP8 chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_ALPHA]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_ALPHA]) {
|
||||
LOG_ERROR("Multiple ALPHA chunks detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
++webp_info->chunk_counts[CHUNK_ALPHA];
|
||||
++webp_info->chunk_counts_[CHUNK_ALPHA];
|
||||
}
|
||||
webp_info->has_alpha = 1;
|
||||
if (webp_info->parse_bitstream) {
|
||||
webp_info->has_alpha_ = 1;
|
||||
if (webp_info->parse_bitstream_) {
|
||||
const WebPInfoStatus status = ParseAlphaHeader(chunk_data, webp_info);
|
||||
if (status != WEBP_INFO_OK) return status;
|
||||
}
|
||||
@@ -917,41 +912,35 @@ static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
|
||||
static WebPInfoStatus ProcessICCPChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
(void)chunk_data;
|
||||
if (!webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
if (!webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
LOG_ERROR("ICCP chunk detected before VP8X chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts[CHUNK_VP8L] ||
|
||||
webp_info->chunk_counts[CHUNK_ANIM]) {
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8] ||
|
||||
webp_info->chunk_counts_[CHUNK_VP8L] ||
|
||||
webp_info->chunk_counts_[CHUNK_ANIM]) {
|
||||
LOG_ERROR("ICCP chunk detected after image data.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
++webp_info->chunk_counts[CHUNK_ICCP];
|
||||
++webp_info->chunk_counts_[CHUNK_ICCP];
|
||||
return WEBP_INFO_OK;
|
||||
}
|
||||
|
||||
static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
|
||||
WebPInfo* const webp_info) {
|
||||
WebPInfoStatus status = WEBP_INFO_OK;
|
||||
ChunkID id = chunk_data->id;
|
||||
if (chunk_data->id == CHUNK_UNKNOWN) {
|
||||
ChunkID id = chunk_data->id_;
|
||||
if (chunk_data->id_ == CHUNK_UNKNOWN) {
|
||||
char error_message[50];
|
||||
snprintf(error_message, 50, "Unknown chunk at offset %6d, length %6d",
|
||||
(int)chunk_data->offset, (int)chunk_data->size);
|
||||
(int)chunk_data->offset_, (int)chunk_data->size_);
|
||||
LOG_WARN(error_message);
|
||||
} else {
|
||||
if (!webp_info->quiet) {
|
||||
char tag[4];
|
||||
uint32_t fourcc = kWebPChunkTags[chunk_data->id];
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
fourcc = (fourcc >> 24) | ((fourcc >> 8) & 0xff00) |
|
||||
((fourcc << 8) & 0xff0000) | (fourcc << 24);
|
||||
#endif
|
||||
memcpy(tag, &fourcc, sizeof(tag));
|
||||
if (!webp_info->quiet_) {
|
||||
const char* tag = kWebPChunkTags[chunk_data->id_];
|
||||
printf("Chunk %c%c%c%c at offset %6d, length %6d\n",
|
||||
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset,
|
||||
(int)chunk_data->size);
|
||||
tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_,
|
||||
(int)chunk_data->size_);
|
||||
}
|
||||
}
|
||||
switch (id) {
|
||||
@@ -976,21 +965,21 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
|
||||
break;
|
||||
case CHUNK_EXIF:
|
||||
case CHUNK_XMP:
|
||||
++webp_info->chunk_counts[id];
|
||||
++webp_info->chunk_counts_[id];
|
||||
break;
|
||||
case CHUNK_UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (webp_info->is_processing_anim_frame && id != CHUNK_ANMF) {
|
||||
if (webp_info->anim_frame_data_size == chunk_data->size) {
|
||||
if (!webp_info->seen_image_subchunk) {
|
||||
if (webp_info->is_processing_anim_frame_ && id != CHUNK_ANMF) {
|
||||
if (webp_info->anim_frame_data_size_ == chunk_data->size_) {
|
||||
if (!webp_info->seen_image_subchunk_) {
|
||||
LOG_ERROR("No VP8/VP8L chunk detected in an ANMF chunk.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
webp_info->is_processing_anim_frame = 0;
|
||||
} else if (webp_info->anim_frame_data_size > chunk_data->size) {
|
||||
webp_info->anim_frame_data_size -= chunk_data->size;
|
||||
webp_info->is_processing_anim_frame_ = 0;
|
||||
} else if (webp_info->anim_frame_data_size_ > chunk_data->size_) {
|
||||
webp_info->anim_frame_data_size_ -= chunk_data->size_;
|
||||
} else {
|
||||
LOG_ERROR("Truncated data detected when parsing ANMF chunk.");
|
||||
return WEBP_INFO_TRUNCATED_DATA;
|
||||
@@ -999,56 +988,56 @@ static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data,
|
||||
return status;
|
||||
}
|
||||
|
||||
static WebPInfoStatus Validate(WebPInfo* const webp_info) {
|
||||
if (webp_info->num_frames < 1) {
|
||||
static WebPInfoStatus Validate(const WebPInfo* const webp_info) {
|
||||
if (webp_info->num_frames_ < 1) {
|
||||
LOG_ERROR("No image/frame detected.");
|
||||
return WEBP_INFO_MISSING_DATA;
|
||||
}
|
||||
if (webp_info->chunk_counts[CHUNK_VP8X]) {
|
||||
const int iccp = !!(webp_info->feature_flags & ICCP_FLAG);
|
||||
const int exif = !!(webp_info->feature_flags & EXIF_FLAG);
|
||||
const int xmp = !!(webp_info->feature_flags & XMP_FLAG);
|
||||
const int animation = !!(webp_info->feature_flags & ANIMATION_FLAG);
|
||||
const int alpha = !!(webp_info->feature_flags & ALPHA_FLAG);
|
||||
if (!alpha && webp_info->has_alpha) {
|
||||
if (webp_info->chunk_counts_[CHUNK_VP8X]) {
|
||||
const int iccp = !!(webp_info->feature_flags_ & ICCP_FLAG);
|
||||
const int exif = !!(webp_info->feature_flags_ & EXIF_FLAG);
|
||||
const int xmp = !!(webp_info->feature_flags_ & XMP_FLAG);
|
||||
const int animation = !!(webp_info->feature_flags_ & ANIMATION_FLAG);
|
||||
const int alpha = !!(webp_info->feature_flags_ & ALPHA_FLAG);
|
||||
if (!alpha && webp_info->has_alpha_) {
|
||||
LOG_ERROR("Unexpected alpha data detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (alpha && !webp_info->has_alpha) {
|
||||
if (alpha && !webp_info->has_alpha_) {
|
||||
LOG_WARN("Alpha flag is set with no alpha data present.");
|
||||
}
|
||||
if (iccp && !webp_info->chunk_counts[CHUNK_ICCP]) {
|
||||
if (iccp && !webp_info->chunk_counts_[CHUNK_ICCP]) {
|
||||
LOG_ERROR("Missing ICCP chunk.");
|
||||
return WEBP_INFO_MISSING_DATA;
|
||||
}
|
||||
if (exif && !webp_info->chunk_counts[CHUNK_EXIF]) {
|
||||
if (exif && !webp_info->chunk_counts_[CHUNK_EXIF]) {
|
||||
LOG_ERROR("Missing EXIF chunk.");
|
||||
return WEBP_INFO_MISSING_DATA;
|
||||
}
|
||||
if (xmp && !webp_info->chunk_counts[CHUNK_XMP]) {
|
||||
if (xmp && !webp_info->chunk_counts_[CHUNK_XMP]) {
|
||||
LOG_ERROR("Missing XMP chunk.");
|
||||
return WEBP_INFO_MISSING_DATA;
|
||||
}
|
||||
if (!iccp && webp_info->chunk_counts[CHUNK_ICCP]) {
|
||||
if (!iccp && webp_info->chunk_counts_[CHUNK_ICCP]) {
|
||||
LOG_ERROR("Unexpected ICCP chunk detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (!exif && webp_info->chunk_counts[CHUNK_EXIF]) {
|
||||
if (!exif && webp_info->chunk_counts_[CHUNK_EXIF]) {
|
||||
LOG_ERROR("Unexpected EXIF chunk detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (!xmp && webp_info->chunk_counts[CHUNK_XMP]) {
|
||||
if (!xmp && webp_info->chunk_counts_[CHUNK_XMP]) {
|
||||
LOG_ERROR("Unexpected XMP chunk detected.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
// Incomplete animation frame.
|
||||
if (webp_info->is_processing_anim_frame) return WEBP_INFO_MISSING_DATA;
|
||||
if (!animation && webp_info->num_frames > 1) {
|
||||
if (webp_info->is_processing_anim_frame_) return WEBP_INFO_MISSING_DATA;
|
||||
if (!animation && webp_info->num_frames_ > 1) {
|
||||
LOG_ERROR("More than 1 frame detected in non-animation file.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
if (animation && (!webp_info->chunk_counts[CHUNK_ANIM] ||
|
||||
!webp_info->chunk_counts[CHUNK_ANMF])) {
|
||||
if (animation && (!webp_info->chunk_counts_[CHUNK_ANIM] ||
|
||||
!webp_info->chunk_counts_[CHUNK_ANMF])) {
|
||||
LOG_ERROR("No ANIM/ANMF chunk detected in animation file.");
|
||||
return WEBP_INFO_PARSE_ERROR;
|
||||
}
|
||||
@@ -1059,17 +1048,17 @@ static WebPInfoStatus Validate(WebPInfo* const webp_info) {
|
||||
static void ShowSummary(const WebPInfo* const webp_info) {
|
||||
int i;
|
||||
printf("Summary:\n");
|
||||
printf("Number of frames: %d\n", webp_info->num_frames);
|
||||
printf("Number of frames: %d\n", webp_info->num_frames_);
|
||||
printf("Chunk type : VP8 VP8L VP8X ALPH ANIM ANMF(VP8 /VP8L/ALPH) ICCP "
|
||||
"EXIF XMP\n");
|
||||
printf("Chunk counts: ");
|
||||
for (i = 0; i < CHUNK_TYPES; ++i) {
|
||||
printf("%4d ", webp_info->chunk_counts[i]);
|
||||
printf("%4d ", webp_info->chunk_counts_[i]);
|
||||
if (i == CHUNK_ANMF) {
|
||||
printf("%4d %4d %4d ",
|
||||
webp_info->anmf_subchunk_counts[0],
|
||||
webp_info->anmf_subchunk_counts[1],
|
||||
webp_info->anmf_subchunk_counts[2]);
|
||||
webp_info->anmf_subchunk_counts_[0],
|
||||
webp_info->anmf_subchunk_counts_[1],
|
||||
webp_info->anmf_subchunk_counts_[2]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
@@ -1092,57 +1081,57 @@ static WebPInfoStatus AnalyzeWebP(WebPInfo* const webp_info,
|
||||
webp_info_status = ProcessChunk(&chunk_data, webp_info);
|
||||
}
|
||||
if (webp_info_status != WEBP_INFO_OK) goto Error;
|
||||
if (webp_info->show_summary) ShowSummary(webp_info);
|
||||
if (webp_info->show_summary_) ShowSummary(webp_info);
|
||||
|
||||
// Final check.
|
||||
webp_info_status = Validate(webp_info);
|
||||
|
||||
Error:
|
||||
if (!webp_info->quiet) {
|
||||
if (!webp_info->quiet_) {
|
||||
if (webp_info_status == WEBP_INFO_OK) {
|
||||
printf("No error detected.\n");
|
||||
} else {
|
||||
printf("Errors detected.\n");
|
||||
}
|
||||
if (webp_info->num_warnings > 0) {
|
||||
printf("There were %d warning(s).\n", webp_info->num_warnings);
|
||||
}
|
||||
}
|
||||
return webp_info_status;
|
||||
}
|
||||
|
||||
static void Help(void) {
|
||||
static void HelpShort(void) {
|
||||
printf("Usage: webpinfo [options] in_files\n"
|
||||
"Try -longhelp for an exhaustive list of options.\n");
|
||||
}
|
||||
|
||||
static void HelpLong(void) {
|
||||
printf("Usage: webpinfo [options] in_files\n"
|
||||
"Note: there could be multiple input files;\n"
|
||||
" options must come before input files.\n"
|
||||
"Options:\n"
|
||||
" -version ........... Print version number and exit.\n"
|
||||
" -quiet ............. Do not show chunk parsing information.\n"
|
||||
" -diag .............. Show parsing error diagnosis.\n"
|
||||
" -summary ........... Show chunk stats summary.\n"
|
||||
" -bitstream_info .... Parse bitstream header.\n");
|
||||
}
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int c, quiet = 0, show_diag = 0, show_summary = 0;
|
||||
int parse_bitstream = 0;
|
||||
WebPInfoStatus webp_info_status = WEBP_INFO_OK;
|
||||
WebPInfo webp_info;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (argc == 1) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
HelpShort();
|
||||
return WEBP_INFO_OK;
|
||||
}
|
||||
|
||||
// Parse command-line input.
|
||||
for (c = 1; c < argc; ++c) {
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help") ||
|
||||
!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||
HelpShort();
|
||||
return WEBP_INFO_OK;
|
||||
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||
HelpLong();
|
||||
return WEBP_INFO_OK;
|
||||
} else if (!strcmp(argv[c], "-quiet")) {
|
||||
quiet = 1;
|
||||
} else if (!strcmp(argv[c], "-diag")) {
|
||||
@@ -1151,41 +1140,34 @@ int main(int argc, const char* argv[]) {
|
||||
show_summary = 1;
|
||||
} else if (!strcmp(argv[c], "-bitstream_info")) {
|
||||
parse_bitstream = 1;
|
||||
} else if (!strcmp(argv[c], "-version")) {
|
||||
const int version = WebPGetDecoderVersion();
|
||||
printf("WebP Decoder version: %d.%d.%d\n",
|
||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
} else { // Assume the remaining are all input files.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == argc) {
|
||||
Help();
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
HelpShort();
|
||||
return WEBP_INFO_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
// Process input files one by one.
|
||||
for (; c < argc; ++c) {
|
||||
WebPData webp_data;
|
||||
const W_CHAR* in_file = NULL;
|
||||
const char* in_file = NULL;
|
||||
WebPInfoInit(&webp_info);
|
||||
webp_info.quiet = quiet;
|
||||
webp_info.show_diagnosis = show_diag;
|
||||
webp_info.show_summary = show_summary;
|
||||
webp_info.parse_bitstream = parse_bitstream;
|
||||
in_file = GET_WARGV(argv, c);
|
||||
if (in_file == NULL ||
|
||||
!ReadFileToWebPData((const char*)in_file, &webp_data)) {
|
||||
webp_info.quiet_ = quiet;
|
||||
webp_info.show_diagnosis_ = show_diag;
|
||||
webp_info.show_summary_ = show_summary;
|
||||
webp_info.parse_bitstream_ = parse_bitstream;
|
||||
in_file = argv[c];
|
||||
if (in_file == NULL || !ReadFileToWebPData(in_file, &webp_data)) {
|
||||
webp_info_status = WEBP_INFO_INVALID_COMMAND;
|
||||
WFPRINTF(stderr, "Failed to open input file %s.\n", in_file);
|
||||
fprintf(stderr, "Failed to open input file %s.\n", in_file);
|
||||
continue;
|
||||
}
|
||||
if (!webp_info.quiet) WPRINTF("File: %s\n", in_file);
|
||||
if (!webp_info.quiet_) printf("File: %s\n", in_file);
|
||||
webp_info_status = AnalyzeWebP(&webp_info, &webp_data);
|
||||
WebPDataClear(&webp_data);
|
||||
}
|
||||
FREE_WARGV_AND_RETURN((webp_info_status == WEBP_INFO_OK) ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE);
|
||||
return webp_info_status;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
|
||||
webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp
|
||||
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
|
||||
webpmux -set loop 1 in.webp -o out_looped.webp
|
||||
|
||||
Extract relevant data from WebP container file:
|
||||
webpmux -get frame n in.webp -o out_frame.webp
|
||||
@@ -48,7 +47,6 @@
|
||||
webpmux -info in.webp
|
||||
webpmux [ -h | -help ]
|
||||
webpmux -version
|
||||
webpmux argument_file_name
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -59,14 +57,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/mux.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Config object to parse command-line arguments.
|
||||
@@ -89,9 +83,9 @@ typedef enum {
|
||||
} FeatureSubType;
|
||||
|
||||
typedef struct {
|
||||
FeatureSubType subtype;
|
||||
const char* filename;
|
||||
const char* params;
|
||||
FeatureSubType subtype_;
|
||||
const char* filename_;
|
||||
const char* params_;
|
||||
} FeatureArg;
|
||||
|
||||
typedef enum {
|
||||
@@ -101,8 +95,6 @@ typedef enum {
|
||||
FEATURE_ICCP,
|
||||
FEATURE_ANMF,
|
||||
FEATURE_DURATION,
|
||||
FEATURE_LOOP,
|
||||
FEATURE_BGCOLOR,
|
||||
LAST_FEATURE
|
||||
} FeatureType;
|
||||
|
||||
@@ -116,26 +108,28 @@ static const char* const kDescriptions[LAST_FEATURE] = {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
CommandLineArguments cmd_args;
|
||||
FeatureType type_;
|
||||
FeatureArg* args_;
|
||||
int arg_count_;
|
||||
} Feature;
|
||||
|
||||
ActionType action_type;
|
||||
const char* input;
|
||||
const char* output;
|
||||
FeatureType type;
|
||||
FeatureArg* args;
|
||||
int arg_count;
|
||||
} Config;
|
||||
typedef struct {
|
||||
ActionType action_type_;
|
||||
const char* input_;
|
||||
const char* output_;
|
||||
Feature feature_;
|
||||
} WebPMuxConfig;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions.
|
||||
|
||||
static int CountOccurrences(const CommandLineArguments* const args,
|
||||
const char* const arg) {
|
||||
static int CountOccurrences(const char* arglist[], int list_length,
|
||||
const char* arg) {
|
||||
int i;
|
||||
int num_occurences = 0;
|
||||
|
||||
for (i = 0; i < args->argc; ++i) {
|
||||
if (!strcmp(args->argv[i], arg)) {
|
||||
for (i = 0; i < list_length; ++i) {
|
||||
if (!strcmp(arglist[i], arg)) {
|
||||
++num_occurences;
|
||||
}
|
||||
}
|
||||
@@ -153,20 +147,16 @@ static const char* ErrorString(WebPMuxError err) {
|
||||
}
|
||||
|
||||
#define RETURN_IF_ERROR(ERR_MSG) \
|
||||
do { \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
return err; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \
|
||||
do { \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
|
||||
return err; \
|
||||
}
|
||||
|
||||
#define ERROR_GOTO1(ERR_MSG, LABEL) \
|
||||
do { \
|
||||
@@ -311,7 +301,6 @@ static void PrintHelp(void) {
|
||||
printf(" webpmux -info INPUT\n");
|
||||
printf(" webpmux [-h|-help]\n");
|
||||
printf(" webpmux -version\n");
|
||||
printf(" webpmux argument_file_name\n");
|
||||
|
||||
printf("\n");
|
||||
printf("GET_OPTIONS:\n");
|
||||
@@ -323,12 +312,10 @@ static void PrintHelp(void) {
|
||||
|
||||
printf("\n");
|
||||
printf("SET_OPTIONS:\n");
|
||||
printf(" Set color profile/metadata/parameters:\n");
|
||||
printf(" loop LOOP_COUNT set the loop count\n");
|
||||
printf(" bgcolor BACKGROUND_COLOR set the animation background color\n");
|
||||
printf(" icc file.icc set ICC profile\n");
|
||||
printf(" exif file.exif set EXIF metadata\n");
|
||||
printf(" xmp file.xmp set XMP metadata\n");
|
||||
printf(" Set color profile/metadata:\n");
|
||||
printf(" icc file.icc set ICC profile\n");
|
||||
printf(" exif file.exif set EXIF metadata\n");
|
||||
printf(" xmp file.xmp set XMP metadata\n");
|
||||
printf(" where: 'file.icc' contains the ICC profile to be set,\n");
|
||||
printf(" 'file.exif' contains the EXIF metadata to be set\n");
|
||||
printf(" 'file.xmp' contains the XMP metadata to be set\n");
|
||||
@@ -336,7 +323,7 @@ static void PrintHelp(void) {
|
||||
printf("\n");
|
||||
printf("DURATION_OPTIONS:\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,start,end set duration of frames in the\n");
|
||||
printf(" interval [start,end])\n");
|
||||
@@ -355,7 +342,7 @@ static void PrintHelp(void) {
|
||||
printf("\n");
|
||||
printf("FRAME_OPTIONS(i):\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(" 'di' is the pause duration before next frame,\n");
|
||||
printf(" 'xi','yi' specify the image offset for this frame,\n");
|
||||
@@ -382,10 +369,6 @@ static void PrintHelp(void) {
|
||||
|
||||
printf("\nNote: The nature of EXIF, XMP and ICC data is not checked");
|
||||
printf(" and is assumed to be\nvalid.\n");
|
||||
printf("\nNote: if a single file name is passed as the argument, the "
|
||||
"arguments will be\n");
|
||||
printf("tokenized from this file. The file name must not start with "
|
||||
"the character '-'.\n");
|
||||
}
|
||||
|
||||
static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
|
||||
@@ -396,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) {
|
||||
WebPData bitstream;
|
||||
assert(mux != NULL);
|
||||
if (!ExUtilReadFileToWebPData(filename, &bitstream)) return 0;
|
||||
if (!ReadFileToWebPData(filename, &bitstream)) return 0;
|
||||
*mux = WebPMuxCreate(&bitstream, 1);
|
||||
WebPDataClear(&bitstream);
|
||||
free((void*)bitstream.bytes);
|
||||
if (*mux != NULL) return 1;
|
||||
WFPRINTF(stderr, "Failed to create mux object from file %s.\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WriteData(const char* filename, const WebPData* const webpdata) {
|
||||
int ok = 0;
|
||||
FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb")
|
||||
: ImgIoUtilSetBinaryMode(stdout);
|
||||
FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb")
|
||||
: ImgIoUtilSetBinaryMode(stdout);
|
||||
if (fout == NULL) {
|
||||
WFPRINTF(stderr, "Error opening output WebP file %s!\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr, "Error opening output WebP file %s!\n", filename);
|
||||
return 0;
|
||||
}
|
||||
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 {
|
||||
WFPRINTF(stderr, "Saved file %s (%d bytes)\n",
|
||||
(const W_CHAR*)filename, (int)webpdata->size);
|
||||
fprintf(stderr, "Saved file %s (%d bytes)\n",
|
||||
filename, (int)webpdata->size);
|
||||
ok = 1;
|
||||
}
|
||||
if (fout != stdout) fclose(fout);
|
||||
@@ -467,8 +458,7 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
||||
if (err == WEBP_MUX_OK && metadata.size > 0) {
|
||||
err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO1("Error transferring metadata in DuplicateMuxHeader().",
|
||||
End);
|
||||
ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,11 +472,11 @@ static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
|
||||
}
|
||||
|
||||
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||
int dispose_method, unused;
|
||||
int dispose_method, dummy;
|
||||
char plus_minus, blend_method;
|
||||
const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration,
|
||||
&info->x_offset, &info->y_offset, &dispose_method,
|
||||
&plus_minus, &blend_method, &unused);
|
||||
&plus_minus, &blend_method, &dummy);
|
||||
switch (num_args) {
|
||||
case 1:
|
||||
info->x_offset = info->y_offset = 0; // fall through
|
||||
@@ -505,7 +495,7 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
|
||||
|
||||
WarnAboutOddOffset(info);
|
||||
|
||||
// Note: The validity of the following conversion is checked by
|
||||
// Note: The sanity of the following conversion is checked by
|
||||
// WebPMuxPushFrame().
|
||||
info->dispose_method = (WebPMuxAnimDispose)dispose_method;
|
||||
|
||||
@@ -527,10 +517,9 @@ static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Clean-up.
|
||||
|
||||
static void DeleteConfig(Config* const config) {
|
||||
static void DeleteConfig(WebPMuxConfig* config) {
|
||||
if (config != NULL) {
|
||||
free(config->args);
|
||||
ExUtilDeleteCommandLineArguments(&config->cmd_args);
|
||||
free(config->feature_.args_);
|
||||
memset(config, 0, sizeof(*config));
|
||||
}
|
||||
}
|
||||
@@ -542,7 +531,7 @@ static void DeleteConfig(Config* const config) {
|
||||
// Returns 1 on valid, 0 otherwise.
|
||||
// Also fills up num_feature_args to be number of feature arguments given.
|
||||
// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
|
||||
static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
|
||||
static int ValidateCommandLine(int argc, const char* argv[],
|
||||
int* num_feature_args) {
|
||||
int num_frame_args;
|
||||
int num_loop_args;
|
||||
@@ -554,27 +543,27 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
|
||||
*num_feature_args = 0;
|
||||
|
||||
// Simple checks.
|
||||
if (CountOccurrences(cmd_args, "-get") > 1) {
|
||||
if (CountOccurrences(argv, argc, "-get") > 1) {
|
||||
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);
|
||||
}
|
||||
if (CountOccurrences(cmd_args, "-strip") > 1) {
|
||||
if (CountOccurrences(argv, argc, "-strip") > 1) {
|
||||
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);
|
||||
}
|
||||
if (CountOccurrences(cmd_args, "-o") > 1) {
|
||||
if (CountOccurrences(argv, argc, "-o") > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
|
||||
}
|
||||
|
||||
// Compound checks.
|
||||
num_frame_args = CountOccurrences(cmd_args, "-frame");
|
||||
num_loop_args = CountOccurrences(cmd_args, "-loop");
|
||||
num_bgcolor_args = CountOccurrences(cmd_args, "-bgcolor");
|
||||
num_durations_args = CountOccurrences(cmd_args, "-duration");
|
||||
num_frame_args = CountOccurrences(argv, argc, "-frame");
|
||||
num_loop_args = CountOccurrences(argv, argc, "-loop");
|
||||
num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
|
||||
num_durations_args = CountOccurrences(argv, argc, "-duration");
|
||||
|
||||
if (num_loop_args > 1) {
|
||||
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
|
||||
@@ -607,148 +596,134 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
|
||||
return ok;
|
||||
}
|
||||
|
||||
#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) \
|
||||
do { \
|
||||
if (argc < i + (NUM)) { \
|
||||
fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
|
||||
goto LABEL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
|
||||
if (argc < i + (NUM)) { \
|
||||
fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
|
||||
goto LABEL; \
|
||||
}
|
||||
|
||||
#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \
|
||||
do { \
|
||||
if (argc > i + (NUM)) { \
|
||||
fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
|
||||
goto LABEL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \
|
||||
do { \
|
||||
CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
|
||||
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL); \
|
||||
} while (0)
|
||||
#define CHECK_NUM_ARGS_NOT_EQUAL(NUM, LABEL) \
|
||||
if (argc != i + (NUM)) { \
|
||||
fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
|
||||
goto LABEL; \
|
||||
}
|
||||
|
||||
// Parses command-line arguments to fill up config object. Also performs some
|
||||
// semantic checks. unicode_argv contains wchar_t arguments or is null.
|
||||
static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
||||
// semantic checks.
|
||||
static int ParseCommandLine(int argc, const char* argv[],
|
||||
WebPMuxConfig* config) {
|
||||
int i = 0;
|
||||
int feature_arg_index = 0;
|
||||
int ok = 1;
|
||||
int argc = config->cmd_args.argc;
|
||||
const char* const* argv = config->cmd_args.argv;
|
||||
// Unicode file paths will be used if available.
|
||||
const char* const* wargv =
|
||||
(unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv;
|
||||
|
||||
while (i < argc) {
|
||||
FeatureArg* const arg = &config->args[feature_arg_index];
|
||||
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 (!strcmp(argv[i], "-set")) {
|
||||
if (ACTION_IS_NIL) {
|
||||
config->action_type = ACTION_SET;
|
||||
config->action_type_ = ACTION_SET;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
++i;
|
||||
} else if (!strcmp(argv[i], "-duration")) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type == ACTION_DURATION) {
|
||||
config->action_type = ACTION_DURATION;
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
|
||||
config->action_type_ = ACTION_DURATION;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || config->type == FEATURE_DURATION) {
|
||||
config->type = FEATURE_DURATION;
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_DURATION) {
|
||||
feature->type_ = FEATURE_DURATION;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
arg->params = argv[i + 1];
|
||||
arg->params_ = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "-get")) {
|
||||
if (ACTION_IS_NIL) {
|
||||
config->action_type = ACTION_GET;
|
||||
config->action_type_ = ACTION_GET;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
++i;
|
||||
} else if (!strcmp(argv[i], "-strip")) {
|
||||
if (ACTION_IS_NIL) {
|
||||
config->action_type = ACTION_STRIP;
|
||||
config->action_type_ = ACTION_STRIP;
|
||||
feature->arg_count_ = 0;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
++i;
|
||||
} else if (!strcmp(argv[i], "-frame")) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(3, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type == ACTION_SET) {
|
||||
config->action_type = ACTION_SET;
|
||||
CHECK_NUM_ARGS_LESS(3, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
|
||||
config->action_type_ = ACTION_SET;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || config->type == FEATURE_ANMF) {
|
||||
config->type = FEATURE_ANMF;
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
arg->subtype = SUBTYPE_ANMF;
|
||||
arg->filename = wargv[i + 1];
|
||||
arg->params = argv[i + 2];
|
||||
arg->subtype_ = SUBTYPE_ANMF;
|
||||
arg->filename_ = argv[i + 1];
|
||||
arg->params_ = argv[i + 2];
|
||||
++feature_arg_index;
|
||||
i += 3;
|
||||
} else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type == ACTION_SET) {
|
||||
config->action_type = ACTION_SET;
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
|
||||
config->action_type_ = ACTION_SET;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
}
|
||||
if (FEATURETYPE_IS_NIL || config->type == FEATURE_ANMF) {
|
||||
config->type = FEATURE_ANMF;
|
||||
if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
arg->subtype =
|
||||
arg->subtype_ =
|
||||
!strcmp(argv[i], "-loop") ? SUBTYPE_LOOP : SUBTYPE_BGCOLOR;
|
||||
arg->params = argv[i + 1];
|
||||
arg->params_ = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "-o")) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
config->output = wargv[i + 1];
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
config->output_ = argv[i + 1];
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "-info")) {
|
||||
CHECK_NUM_ARGS_EXACTLY(2, ErrParse);
|
||||
if (config->action_type != NIL_ACTION) {
|
||||
CHECK_NUM_ARGS_NOT_EQUAL(2, ErrParse);
|
||||
if (config->action_type_ != NIL_ACTION) {
|
||||
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
|
||||
} else {
|
||||
config->action_type = ACTION_INFO;
|
||||
config->arg_count = 0;
|
||||
config->input = wargv[i + 1];
|
||||
config->action_type_ = ACTION_INFO;
|
||||
feature->arg_count_ = 0;
|
||||
config->input_ = argv[i + 1];
|
||||
}
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
|
||||
PrintHelp();
|
||||
DeleteConfig(config);
|
||||
LOCAL_FREE((W_CHAR** const)unicode_argv);
|
||||
exit(0);
|
||||
} else if (!strcmp(argv[i], "-version")) {
|
||||
const int version = WebPGetMuxVersion();
|
||||
printf("%d.%d.%d\n",
|
||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||
DeleteConfig(config);
|
||||
LOCAL_FREE((W_CHAR** const)unicode_argv);
|
||||
exit(0);
|
||||
} else if (!strcmp(argv[i], "--")) {
|
||||
if (i < argc - 1) {
|
||||
++i;
|
||||
if (config->input == NULL) {
|
||||
config->input = wargv[i];
|
||||
if (config->input_ == NULL) {
|
||||
config->input_ = argv[i];
|
||||
} else {
|
||||
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
||||
argv[i], ErrParse);
|
||||
@@ -759,65 +734,36 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
||||
ERROR_GOTO2("ERROR: Unknown option: '%s'.\n", argv[i], ErrParse);
|
||||
}
|
||||
} else { // One of the feature types or input.
|
||||
// After consuming the arguments to -get/-set/-strip, treat any remaining
|
||||
// arguments as input. This allows files that are named the same as the
|
||||
// keywords used with these options.
|
||||
int is_input = feature_arg_index == config->arg_count;
|
||||
if (ACTION_IS_NIL) {
|
||||
ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n",
|
||||
ErrParse);
|
||||
}
|
||||
if (!is_input) {
|
||||
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
|
||||
!strcmp(argv[i], "xmp")) {
|
||||
if (FEATURETYPE_IS_NIL) {
|
||||
config->type = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
|
||||
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
if (config->action_type == ACTION_SET) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
arg->filename = wargv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else {
|
||||
// Note: 'arg->params' is not used in this case. 'arg_count' is
|
||||
// used as a flag to indicate the -get/-strip feature has already
|
||||
// been consumed, allowing input types to be named the same as the
|
||||
// feature type.
|
||||
config->arg_count = 0;
|
||||
++i;
|
||||
}
|
||||
} else if (!strcmp(argv[i], "frame") &&
|
||||
(config->action_type == ACTION_GET)) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
config->type = FEATURE_ANMF;
|
||||
arg->params = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "loop") &&
|
||||
(config->action_type == ACTION_SET)) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
config->type = FEATURE_LOOP;
|
||||
arg->params = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else if (!strcmp(argv[i], "bgcolor") &&
|
||||
(config->action_type == ACTION_SET)) {
|
||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||
config->type = FEATURE_BGCOLOR;
|
||||
arg->params = argv[i + 1];
|
||||
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
|
||||
!strcmp(argv[i], "xmp")) {
|
||||
if (FEATURETYPE_IS_NIL) {
|
||||
feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
|
||||
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
|
||||
}
|
||||
if (config->action_type_ == ACTION_SET) {
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
arg->filename_ = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else {
|
||||
is_input = 1;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_input) {
|
||||
if (config->input == NULL) {
|
||||
config->input = wargv[i];
|
||||
} else if (!strcmp(argv[i], "frame") &&
|
||||
(config->action_type_ == ACTION_GET)) {
|
||||
CHECK_NUM_ARGS_LESS(2, ErrParse);
|
||||
feature->type_ = FEATURE_ANMF;
|
||||
arg->params_ = argv[i + 1];
|
||||
++feature_arg_index;
|
||||
i += 2;
|
||||
} else { // Assume input file.
|
||||
if (config->input_ == NULL) {
|
||||
config->input_ = argv[i];
|
||||
} else {
|
||||
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
||||
argv[i], ErrParse);
|
||||
@@ -831,8 +777,9 @@ static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
||||
}
|
||||
|
||||
// Additional checks after config is filled.
|
||||
static int ValidateConfig(Config* const config) {
|
||||
static int ValidateConfig(WebPMuxConfig* config) {
|
||||
int ok = 1;
|
||||
Feature* const feature = &config->feature_;
|
||||
|
||||
// Action.
|
||||
if (ACTION_IS_NIL) {
|
||||
@@ -840,21 +787,21 @@ static int ValidateConfig(Config* const config) {
|
||||
}
|
||||
|
||||
// Feature type.
|
||||
if (FEATURETYPE_IS_NIL && config->action_type != ACTION_INFO) {
|
||||
if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) {
|
||||
ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2);
|
||||
}
|
||||
|
||||
// Input file.
|
||||
if (config->input == NULL) {
|
||||
if (config->action_type != ACTION_SET) {
|
||||
if (config->input_ == NULL) {
|
||||
if (config->action_type_ != ACTION_SET) {
|
||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||
} else if (config->type != FEATURE_ANMF) {
|
||||
} else if (feature->type_ != FEATURE_ANMF) {
|
||||
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
|
||||
}
|
||||
}
|
||||
|
||||
// Output file.
|
||||
if (config->output == NULL && config->action_type != ACTION_INFO) {
|
||||
if (config->output_ == NULL && config->action_type_ != ACTION_INFO) {
|
||||
ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2);
|
||||
}
|
||||
|
||||
@@ -863,29 +810,28 @@ static int ValidateConfig(Config* const config) {
|
||||
}
|
||||
|
||||
// Create config object from command-line arguments.
|
||||
static int InitializeConfig(int argc, const char* argv[], Config* const config,
|
||||
const W_CHAR** const unicode_argv) {
|
||||
static int InitializeConfig(int argc, const char* argv[],
|
||||
WebPMuxConfig* config) {
|
||||
int num_feature_args = 0;
|
||||
int ok;
|
||||
int ok = 1;
|
||||
|
||||
assert(config != NULL);
|
||||
memset(config, 0, sizeof(*config));
|
||||
|
||||
ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args);
|
||||
if (!ok) return 0;
|
||||
|
||||
// Validate command-line arguments.
|
||||
if (!ValidateCommandLine(&config->cmd_args, &num_feature_args)) {
|
||||
if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
|
||||
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
|
||||
}
|
||||
|
||||
config->arg_count = num_feature_args;
|
||||
config->args = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args));
|
||||
if (config->args == NULL) {
|
||||
config->feature_.arg_count_ = num_feature_args;
|
||||
config->feature_.args_ =
|
||||
(FeatureArg*)calloc(num_feature_args, sizeof(*config->feature_.args_));
|
||||
if (config->feature_.args_ == NULL) {
|
||||
ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -895,14 +841,13 @@ static int InitializeConfig(int argc, const char* argv[], Config* const config,
|
||||
|
||||
#undef ACTION_IS_NIL
|
||||
#undef FEATURETYPE_IS_NIL
|
||||
#undef CHECK_NUM_ARGS_AT_LEAST
|
||||
#undef CHECK_NUM_ARGS_AT_MOST
|
||||
#undef CHECK_NUM_ARGS_EXACTLY
|
||||
#undef CHECK_NUM_ARGS_LESS
|
||||
#undef CHECK_NUM_ARGS_MORE
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Processing.
|
||||
|
||||
static int GetFrame(const WebPMux* mux, const Config* config) {
|
||||
static int GetFrame(const WebPMux* mux, const WebPMuxConfig* config) {
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
WebPMux* mux_single = NULL;
|
||||
int num = 0;
|
||||
@@ -912,7 +857,7 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
|
||||
WebPMuxFrameInfo info;
|
||||
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) {
|
||||
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
|
||||
}
|
||||
@@ -937,7 +882,7 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
|
||||
ErrorString(err), ErrGet);
|
||||
}
|
||||
|
||||
ok = WriteWebP(mux_single, config->output);
|
||||
ok = WriteWebP(mux_single, config->output_);
|
||||
|
||||
ErrGet:
|
||||
WebPDataClear(&info.bitstream);
|
||||
@@ -946,17 +891,18 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
|
||||
}
|
||||
|
||||
// Read and process config.
|
||||
static int Process(const Config* config) {
|
||||
static int Process(const WebPMuxConfig* config) {
|
||||
WebPMux* mux = NULL;
|
||||
WebPData chunk;
|
||||
WebPMuxError err = WEBP_MUX_OK;
|
||||
int ok = 1;
|
||||
const Feature* const feature = &config->feature_;
|
||||
|
||||
switch (config->action_type) {
|
||||
switch (config->action_type_) {
|
||||
case ACTION_GET: {
|
||||
ok = CreateMux(config->input, &mux);
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
switch (config->type) {
|
||||
switch (feature->type_) {
|
||||
case FEATURE_ANMF:
|
||||
ok = GetFrame(mux, config);
|
||||
break;
|
||||
@@ -964,12 +910,12 @@ static int Process(const Config* config) {
|
||||
case FEATURE_ICCP:
|
||||
case FEATURE_EXIF:
|
||||
case FEATURE_XMP:
|
||||
err = WebPMuxGetChunk(mux, kFourccList[config->type], &chunk);
|
||||
err = WebPMuxGetChunk(mux, kFourccList[feature->type_], &chunk);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
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;
|
||||
|
||||
default:
|
||||
@@ -979,7 +925,7 @@ static int Process(const Config* config) {
|
||||
break;
|
||||
}
|
||||
case ACTION_SET: {
|
||||
switch (config->type) {
|
||||
switch (feature->type_) {
|
||||
case FEATURE_ANMF: {
|
||||
int i;
|
||||
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
|
||||
@@ -988,11 +934,11 @@ static int Process(const Config* config) {
|
||||
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
|
||||
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
|
||||
}
|
||||
for (i = 0; i < config->arg_count; ++i) {
|
||||
switch (config->args[i].subtype) {
|
||||
for (i = 0; i < feature->arg_count_; ++i) {
|
||||
switch (feature->args_[i].subtype_) {
|
||||
case SUBTYPE_BGCOLOR: {
|
||||
uint32_t bgcolor;
|
||||
ok = ParseBgcolorArgs(config->args[i].params, &bgcolor);
|
||||
ok = ParseBgcolorArgs(feature->args_[i].params_, &bgcolor);
|
||||
if (!ok) {
|
||||
ERROR_GOTO1("ERROR: Could not parse the background color \n",
|
||||
Err2);
|
||||
@@ -1003,7 +949,7 @@ static int Process(const Config* config) {
|
||||
case SUBTYPE_LOOP: {
|
||||
int parse_error = 0;
|
||||
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) {
|
||||
// Note: This is only a 'necessary' condition for loop_count
|
||||
// to be valid. The 'sufficient' conditioned in checked in
|
||||
@@ -1019,10 +965,10 @@ static int Process(const Config* config) {
|
||||
case SUBTYPE_ANMF: {
|
||||
WebPMuxFrameInfo frame;
|
||||
frame.id = WEBP_CHUNK_ANMF;
|
||||
ok = ExUtilReadFileToWebPData(config->args[i].filename,
|
||||
&frame.bitstream);
|
||||
ok = ReadFileToWebPData(feature->args_[i].filename_,
|
||||
&frame.bitstream);
|
||||
if (!ok) goto Err2;
|
||||
ok = ParseFrameArgs(config->args[i].params, &frame);
|
||||
ok = ParseFrameArgs(feature->args_[i].params_, &frame);
|
||||
if (!ok) {
|
||||
WebPDataClear(&frame.bitstream);
|
||||
ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
|
||||
@@ -1053,64 +999,15 @@ static int Process(const Config* config) {
|
||||
case FEATURE_ICCP:
|
||||
case FEATURE_EXIF:
|
||||
case FEATURE_XMP: {
|
||||
ok = CreateMux(config->input, &mux);
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
ok = ExUtilReadFileToWebPData(config->args[0].filename, &chunk);
|
||||
ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk);
|
||||
if (!ok) goto Err2;
|
||||
err = WebPMuxSetChunk(mux, kFourccList[config->type], &chunk, 1);
|
||||
WebPDataClear(&chunk);
|
||||
err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1);
|
||||
free((void*)chunk.bytes);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
|
||||
ErrorString(err), kDescriptions[config->type], Err2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FEATURE_LOOP: {
|
||||
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
|
||||
int parse_error = 0;
|
||||
const int loop_count =
|
||||
ExUtilGetInt(config->args[0].params, 10, &parse_error);
|
||||
if (loop_count < 0 || loop_count > 65535 || parse_error) {
|
||||
ERROR_GOTO1("ERROR: Loop count must be in the range 0 to 65535.\n",
|
||||
Err2);
|
||||
}
|
||||
ok = CreateMux(config->input, &mux);
|
||||
if (!ok) goto Err2;
|
||||
ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK);
|
||||
if (!ok) {
|
||||
ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n",
|
||||
Err2);
|
||||
}
|
||||
params.loop_count = loop_count;
|
||||
err = WebPMuxSetAnimationParams(mux, ¶ms);
|
||||
ok = (err == WEBP_MUX_OK);
|
||||
if (!ok) {
|
||||
ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
|
||||
ErrorString(err), Err2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FEATURE_BGCOLOR: {
|
||||
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
|
||||
uint32_t bgcolor;
|
||||
ok = ParseBgcolorArgs(config->args[0].params, &bgcolor);
|
||||
if (!ok) {
|
||||
ERROR_GOTO1("ERROR: Could not parse the background color.\n",
|
||||
Err2);
|
||||
}
|
||||
ok = CreateMux(config->input, &mux);
|
||||
if (!ok) goto Err2;
|
||||
ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK);
|
||||
if (!ok) {
|
||||
ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n",
|
||||
Err2);
|
||||
}
|
||||
params.bgcolor = bgcolor;
|
||||
err = WebPMuxSetAnimationParams(mux, ¶ms);
|
||||
ok = (err == WEBP_MUX_OK);
|
||||
if (!ok) {
|
||||
ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n",
|
||||
ErrorString(err), Err2);
|
||||
ErrorString(err), kDescriptions[feature->type_], Err2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1119,12 +1016,12 @@ static int Process(const Config* config) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok = WriteWebP(mux, config->output);
|
||||
ok = WriteWebP(mux, config->output_);
|
||||
break;
|
||||
}
|
||||
case ACTION_DURATION: {
|
||||
int num_frames;
|
||||
ok = CreateMux(config->input, &mux);
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames);
|
||||
ok = (err == WEBP_MUX_OK);
|
||||
@@ -1134,23 +1031,23 @@ static int Process(const Config* config) {
|
||||
if (num_frames == 0) {
|
||||
fprintf(stderr, "Doesn't look like the source is animated. "
|
||||
"Skipping duration setting.\n");
|
||||
ok = WriteWebP(mux, config->output);
|
||||
ok = WriteWebP(mux, config->output_);
|
||||
if (!ok) goto Err2;
|
||||
} else {
|
||||
int i;
|
||||
int* durations = NULL;
|
||||
WebPMux* new_mux = DuplicateMuxHeader(mux);
|
||||
if (new_mux == NULL) goto Err2;
|
||||
durations = (int*)WebPMalloc((size_t)num_frames * sizeof(*durations));
|
||||
durations = (int*)malloc((size_t)num_frames * sizeof(*durations));
|
||||
if (durations == NULL) goto Err2;
|
||||
for (i = 0; i < num_frames; ++i) durations[i] = -1;
|
||||
|
||||
// Parse intervals to process.
|
||||
for (i = 0; i < config->arg_count; ++i) {
|
||||
for (i = 0; i < feature->arg_count_; ++i) {
|
||||
int k;
|
||||
int args[3];
|
||||
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);
|
||||
ok = (nb_args >= 1);
|
||||
if (!ok) goto Err3;
|
||||
@@ -1194,36 +1091,36 @@ static int Process(const Config* config) {
|
||||
WebPDataClear(&frame.bitstream);
|
||||
}
|
||||
WebPMuxDelete(mux);
|
||||
ok = WriteWebP(new_mux, config->output);
|
||||
ok = WriteWebP(new_mux, config->output_);
|
||||
mux = new_mux; // transfer for the WebPMuxDelete() call
|
||||
new_mux = NULL;
|
||||
|
||||
Err3:
|
||||
WebPFree(durations);
|
||||
free(durations);
|
||||
WebPMuxDelete(new_mux);
|
||||
if (!ok) goto Err2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_STRIP: {
|
||||
ok = CreateMux(config->input, &mux);
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
if (config->type == FEATURE_ICCP || config->type == FEATURE_EXIF ||
|
||||
config->type == FEATURE_XMP) {
|
||||
err = WebPMuxDeleteChunk(mux, kFourccList[config->type]);
|
||||
if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF ||
|
||||
feature->type_ == FEATURE_XMP) {
|
||||
err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]);
|
||||
if (err != WEBP_MUX_OK) {
|
||||
ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
|
||||
ErrorString(err), kDescriptions[config->type], Err2);
|
||||
ErrorString(err), kDescriptions[feature->type_], Err2);
|
||||
}
|
||||
} else {
|
||||
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
|
||||
break;
|
||||
}
|
||||
ok = WriteWebP(mux, config->output);
|
||||
ok = WriteWebP(mux, config->output_);
|
||||
break;
|
||||
}
|
||||
case ACTION_INFO: {
|
||||
ok = CreateMux(config->input, &mux);
|
||||
ok = CreateMux(config->input_, &mux);
|
||||
if (!ok) goto Err2;
|
||||
ok = (DisplayInfo(mux) == WEBP_MUX_OK);
|
||||
break;
|
||||
@@ -1242,21 +1139,16 @@ static int Process(const Config* config) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Main.
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
Config config;
|
||||
int ok;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL());
|
||||
WebPMuxConfig config;
|
||||
int ok = InitializeConfig(argc - 1, argv + 1, &config);
|
||||
if (ok) {
|
||||
ok = Process(&config);
|
||||
} else {
|
||||
PrintHelp();
|
||||
}
|
||||
DeleteConfig(&config);
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return !ok;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||
noinst_LTLIBRARIES = libwebpextras.la
|
||||
|
||||
@@ -7,39 +6,31 @@ noinst_HEADERS += ../src/webp/types.h
|
||||
|
||||
libwebpextras_la_SOURCES =
|
||||
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
|
||||
libwebpextras_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
|
||||
|
||||
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libwebpextras_la_LDFLAGS = -lm
|
||||
libwebpextras_la_LIBADD = ../src/libwebp.la
|
||||
|
||||
noinst_PROGRAMS =
|
||||
noinst_PROGRAMS += webp_quality
|
||||
if BUILD_DEMUX
|
||||
noinst_PROGRAMS += get_disto
|
||||
endif
|
||||
noinst_PROGRAMS += get_disto webp_quality
|
||||
if BUILD_VWEBP_SDL
|
||||
noinst_PROGRAMS += vwebp_sdl
|
||||
endif
|
||||
|
||||
get_disto_SOURCES = get_disto.c
|
||||
get_disto_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
get_disto_LDADD =
|
||||
get_disto_LDADD += ../imageio/libimageio_util.la
|
||||
get_disto_LDADD += ../imageio/libimagedec.la
|
||||
get_disto_LDADD = ../imageio/libimageio_util.la ../imageio/libimagedec.la
|
||||
get_disto_LDADD += ../src/libwebp.la
|
||||
get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
|
||||
|
||||
webp_quality_SOURCES = webp_quality.c
|
||||
webp_quality_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
webp_quality_LDADD =
|
||||
webp_quality_LDADD += ../imageio/libimageio_util.la
|
||||
webp_quality_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
webp_quality_LDADD = ../imageio/libimageio_util.la
|
||||
webp_quality_LDADD += libwebpextras.la
|
||||
webp_quality_LDADD += ../src/libwebp.la
|
||||
|
||||
vwebp_sdl_SOURCES = vwebp_sdl.c webp_to_sdl.c webp_to_sdl.h
|
||||
vwebp_sdl_CPPFLAGS = $(AM_CPPFLAGS) $(SDL_INCLUDES)
|
||||
vwebp_sdl_LDADD =
|
||||
vwebp_sdl_LDADD += ../imageio/libimageio_util.la
|
||||
vwebp_sdl_LDADD = ../imageio/libimageio_util.la
|
||||
vwebp_sdl_LDADD += ../src/libwebp.la
|
||||
vwebp_sdl_LDADD += $(SDL_LIBS)
|
||||
|
||||
201
extras/extras.c
201
extras/extras.c
@@ -10,22 +10,14 @@
|
||||
// Additional WebP utilities.
|
||||
//
|
||||
|
||||
#include "extras/extras.h"
|
||||
#include "./extras.h"
|
||||
#include "webp/format_constants.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extras/sharpyuv_risk_table.h"
|
||||
#include "sharpyuv/sharpyuv.h"
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/webp/encode.h"
|
||||
#include "webp/format_constants.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#define XTRA_MAJ_VERSION 1
|
||||
#define XTRA_MIN_VERSION 6
|
||||
#define XTRA_MAJ_VERSION 0
|
||||
#define XTRA_MIN_VERSION 1
|
||||
#define XTRA_REV_VERSION 0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -56,16 +48,15 @@ int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) {
|
||||
|
||||
int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
|
||||
int x, y;
|
||||
uint32_t* dst;
|
||||
if (pic == NULL || rgb565 == NULL) return 0;
|
||||
pic->colorspace = WEBP_YUV420;
|
||||
pic->use_argb = 1;
|
||||
if (!WebPPictureAlloc(pic)) return 0;
|
||||
dst = pic->argb;
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
const int width = pic->width;
|
||||
uint32_t* dst = pic->argb + y * pic->argb_stride;
|
||||
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 gb = rgb565[2 * x + 0];
|
||||
#else
|
||||
@@ -79,26 +70,24 @@ int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
|
||||
r = r | (r >> 5);
|
||||
g = g | (g >> 6);
|
||||
b = b | (b >> 5);
|
||||
dst[x] = (0xffu << 24) | (r << 16) | (g << 8) | b;
|
||||
dst[x] = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
rgb565 += 2 * width;
|
||||
dst += pic->argb_stride;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
|
||||
int x, y;
|
||||
uint32_t* dst;
|
||||
if (pic == NULL || rgb4444 == NULL) return 0;
|
||||
pic->colorspace = WEBP_YUV420;
|
||||
pic->use_argb = 1;
|
||||
if (!WebPPictureAlloc(pic)) return 0;
|
||||
dst = pic->argb;
|
||||
for (y = 0; y < pic->height; ++y) {
|
||||
const int width = pic->width;
|
||||
uint32_t* dst = pic->argb + y * pic->argb_stride;
|
||||
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 ba = rgb4444[2 * x + 0];
|
||||
#else
|
||||
@@ -117,7 +106,6 @@ int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
|
||||
dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
rgb4444 += 2 * width;
|
||||
dst += pic->argb_stride;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -152,174 +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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 420 risk metric
|
||||
|
||||
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
|
||||
static const int kYuvHalf = 1 << (YUV_FIX - 1);
|
||||
|
||||
// Maps a value in [0, (256 << YUV_FIX) - 1] to [0,
|
||||
// precomputed_scores_table_sampling - 1]. It is important that the extremal
|
||||
// values are preserved and 1:1 mapped:
|
||||
// ConvertValue(0) = 0
|
||||
// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1
|
||||
static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) {
|
||||
v = (v + kYuvHalf) >> YUV_FIX;
|
||||
v = (v < 0) ? 0 : (v > 255) ? 255 : v;
|
||||
return (v * (rgb_sampling_size - 1)) / 255;
|
||||
}
|
||||
|
||||
#undef YUV_FIX
|
||||
|
||||
// For each pixel, computes the index to look up that color in a precomputed
|
||||
// risk score table where the YUV space is subsampled to a size of
|
||||
// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h)
|
||||
static int SharpYuvConvertToYuvSharpnessIndex(
|
||||
int r, int g, int b, const SharpYuvConversionMatrix* matrix,
|
||||
int precomputed_scores_table_sampling) {
|
||||
const int y = SharpYuvConvertValueToSampledIdx(
|
||||
matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g +
|
||||
matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3],
|
||||
precomputed_scores_table_sampling);
|
||||
const int u = SharpYuvConvertValueToSampledIdx(
|
||||
matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g +
|
||||
matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3],
|
||||
precomputed_scores_table_sampling);
|
||||
const int v = SharpYuvConvertValueToSampledIdx(
|
||||
matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g +
|
||||
matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3],
|
||||
precomputed_scores_table_sampling);
|
||||
return y + u * precomputed_scores_table_sampling +
|
||||
v * precomputed_scores_table_sampling *
|
||||
precomputed_scores_table_sampling;
|
||||
}
|
||||
|
||||
static void SharpYuvRowToYuvSharpnessIndex(
|
||||
const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
|
||||
int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
|
||||
const SharpYuvConversionMatrix* matrix,
|
||||
int precomputed_scores_table_sampling) {
|
||||
int i;
|
||||
assert(rgb_bit_depth == 8);
|
||||
(void)rgb_bit_depth; // Unused for now.
|
||||
for (i = 0; i < width;
|
||||
++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) {
|
||||
dst[i] =
|
||||
SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix,
|
||||
precomputed_scores_table_sampling);
|
||||
}
|
||||
}
|
||||
|
||||
#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((uint64_t)(W) * (H), sizeof(T)))
|
||||
|
||||
static int DoEstimateRisk(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, int width, int height,
|
||||
const SharpYuvOptions* options,
|
||||
const uint8_t precomputed_scores_table[],
|
||||
int precomputed_scores_table_sampling,
|
||||
float* score_out) {
|
||||
const int sampling3 = precomputed_scores_table_sampling *
|
||||
precomputed_scores_table_sampling *
|
||||
precomputed_scores_table_sampling;
|
||||
const int kNoiseLevel = 4;
|
||||
double total_score = 0;
|
||||
double count = 0;
|
||||
// Rows of indices in
|
||||
uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t);
|
||||
uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t);
|
||||
uint16_t* tmp;
|
||||
int i, j;
|
||||
|
||||
if (row1 == NULL || row2 == NULL) {
|
||||
WebPFree(row1);
|
||||
WebPFree(row2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert the first row ahead.
|
||||
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
||||
width, row2, options->yuv_matrix,
|
||||
precomputed_scores_table_sampling);
|
||||
|
||||
for (j = 1; j < height; ++j) {
|
||||
r_ptr += rgb_stride;
|
||||
g_ptr += rgb_stride;
|
||||
b_ptr += rgb_stride;
|
||||
// Swap row 1 and row 2.
|
||||
tmp = row1;
|
||||
row1 = row2;
|
||||
row2 = tmp;
|
||||
// Convert the row below.
|
||||
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
||||
width, row2, options->yuv_matrix,
|
||||
precomputed_scores_table_sampling);
|
||||
for (i = 0; i < width - 1; ++i) {
|
||||
const int idx0 = row1[i + 0];
|
||||
const int idx1 = row1[i + 1];
|
||||
const int idx2 = row2[i + 0];
|
||||
const int score = precomputed_scores_table[idx0 + sampling3 * idx1] +
|
||||
precomputed_scores_table[idx0 + sampling3 * idx2] +
|
||||
precomputed_scores_table[idx1 + sampling3 * idx2];
|
||||
if (score > kNoiseLevel) {
|
||||
total_score += score;
|
||||
count += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0.) total_score /= count;
|
||||
|
||||
// If less than 1% of pixels were evaluated -> below noise level.
|
||||
if (100. * count / (width * height) < 1.) total_score = 0.;
|
||||
|
||||
// Rescale to [0:100]
|
||||
total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.;
|
||||
|
||||
WebPFree(row1);
|
||||
WebPFree(row2);
|
||||
|
||||
*score_out = (float)total_score;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef SAFE_ALLOC
|
||||
|
||||
int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr,
|
||||
const void* b_ptr, int rgb_step, int rgb_stride,
|
||||
int rgb_bit_depth, int width, int height,
|
||||
const SharpYuvOptions* options, float* score) {
|
||||
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
|
||||
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL ||
|
||||
score == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (rgb_bit_depth != 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (width <= 4 || height <= 4) {
|
||||
*score = 0.0f; // too small, no real risk.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return DoEstimateRisk(
|
||||
(const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
|
||||
rgb_step, rgb_stride, rgb_bit_depth, width, height, options,
|
||||
kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -11,56 +11,46 @@
|
||||
#ifndef WEBP_EXTRAS_EXTRAS_H_
|
||||
#define WEBP_EXTRAS_EXTRAS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sharpyuv/sharpyuv.h"
|
||||
#include "webp/encode.h"
|
||||
|
||||
#define WEBP_EXTRAS_ABI_VERSION 0x0003 // 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
|
||||
// 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.
|
||||
|
||||
// Import luma sample (gray scale image) into 'picture'. The 'picture'
|
||||
// width and height must be set prior to calling this function.
|
||||
WEBP_EXTERN int WebPImportGray(const uint8_t* gray, WebPPicture* picture);
|
||||
WEBP_EXTERN(int) WebPImportGray(const uint8_t* gray, WebPPicture* picture);
|
||||
|
||||
// Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
|
||||
// width and height must be set prior to calling this function.
|
||||
WEBP_EXTERN int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
|
||||
WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
|
||||
|
||||
// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
|
||||
// width and height must be set prior to calling this function.
|
||||
WEBP_EXTERN int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
|
||||
WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
|
||||
|
||||
// Import a color mapped image. The number of colors is less or equal to
|
||||
// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any,
|
||||
// will be discarded. Returns 'false' in case of error, or if indexed[] contains
|
||||
// invalid indices.
|
||||
WEBP_EXTERN int
|
||||
WEBP_EXTERN(int)
|
||||
WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
|
||||
const uint32_t palette[], int palette_size,
|
||||
WebPPicture* pic);
|
||||
|
||||
// Convert the ARGB content of 'pic' from associated to unassociated.
|
||||
// 'pic' can be for instance the result of calling of some WebPPictureImportXXX
|
||||
// functions, with pic->use_argb set to 'true'. It is assumed (and not checked)
|
||||
// that the pre-multiplied r/g/b values as less or equal than the alpha value.
|
||||
// Return false in case of error (invalid parameter, ...).
|
||||
WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Parse a bitstream, search for VP8 (lossy) header and report a
|
||||
@@ -69,39 +59,7 @@ WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic);
|
||||
// Otherwise (lossy bitstream), the returned value is in the range [0..100].
|
||||
// Any error (invalid bitstream, animated WebP, incomplete header, etc.)
|
||||
// will return a value of -1.
|
||||
WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Computes a score between 0 and 100 which represents the risk of having visual
|
||||
// quality loss from converting an RGB image to YUV420.
|
||||
// A low score, typically < 40, means there is a low risk of artifacts from
|
||||
// chroma subsampling and a simple averaging algorithm can be used instead of
|
||||
// the more expensive SharpYuvConvert function.
|
||||
// A medium score, typically >= 40 and < 70, means that simple chroma
|
||||
// subsampling will produce artifacts and it may be advisable to use the more
|
||||
// costly SharpYuvConvert for YUV420 conversion.
|
||||
// A high score, typically >= 70, means there is a very high risk of artifacts
|
||||
// from chroma subsampling even with SharpYuvConvert, and best results might be
|
||||
// achieved by using YUV444.
|
||||
// If not using SharpYuvConvert, a threshold of about 50 can be used to decide
|
||||
// between (simple averaging) 420 and 444.
|
||||
// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
|
||||
// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
|
||||
// rgb_step: distance in bytes between two horizontally adjacent pixels on the
|
||||
// r, g and b channels. If rgb_bit_depth is > 8, it should be a
|
||||
// multiple of 2.
|
||||
// rgb_stride: distance in bytes between two vertically adjacent pixels on the
|
||||
// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
|
||||
// multiple of 2.
|
||||
// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is
|
||||
// currently supported.
|
||||
// width, height: width and height of the image in pixels
|
||||
// Returns 0 on failure.
|
||||
WEBP_EXTERN int SharpYuvEstimate420Risk(
|
||||
const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
|
||||
int rgb_stride, int rgb_bit_depth, int width, int height,
|
||||
const SharpYuvOptions* options, float* score);
|
||||
WEBP_EXTERN(int) VP8EstimateQuality(const uint8_t* const data, size_t size);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -109,4 +67,4 @@ WEBP_EXTERN int SharpYuvEstimate420Risk(
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBP_EXTRAS_EXTRAS_H_
|
||||
#endif /* WEBP_EXTRAS_EXTRAS_H_ */
|
||||
|
||||
@@ -23,11 +23,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../examples/unicode.h"
|
||||
#include "imageio/image_dec.h"
|
||||
#include "imageio/imageio_util.h"
|
||||
#include "src/webp/types.h"
|
||||
#include "webp/encode.h"
|
||||
#include "../imageio/image_dec.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
|
||||
static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||
int keep_alpha) {
|
||||
@@ -50,8 +48,7 @@ static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||
|
||||
End:
|
||||
if (!ok) {
|
||||
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||
(const W_CHAR*)filename);
|
||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
||||
}
|
||||
free((void*)data);
|
||||
return ok ? data_size : 0;
|
||||
@@ -224,15 +221,13 @@ static void Help(void) {
|
||||
" -o <file> . save the diff map as a WebP lossless file\n"
|
||||
" -scale .... scale the difference map to fit [0..255] range\n"
|
||||
" -gray ..... use grayscale for difference map (-scale)\n"
|
||||
"\nSupported input formats:\n %s\n",
|
||||
WebPGetEnabledInputFileFormats());
|
||||
" Also handles PNG, JPG and TIFF files, in addition to WebP.\n");
|
||||
}
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
WebPPicture pic1, pic2;
|
||||
size_t size1 = 0, size2 = 0;
|
||||
int ret = EXIT_FAILURE;
|
||||
int ret = 1;
|
||||
float disto[5];
|
||||
int type = 0;
|
||||
int c;
|
||||
@@ -244,11 +239,9 @@ int main(int argc, const char* argv[]) {
|
||||
const char* name2 = NULL;
|
||||
const char* output = NULL;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
|
||||
fprintf(stderr, "Can't init pictures\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_FAILURE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; ++c) {
|
||||
@@ -264,17 +257,17 @@ int main(int argc, const char* argv[]) {
|
||||
use_gray = 1;
|
||||
} else if (!strcmp(argv[c], "-h")) {
|
||||
help = 1;
|
||||
ret = EXIT_SUCCESS;
|
||||
ret = 0;
|
||||
} else if (!strcmp(argv[c], "-o")) {
|
||||
if (++c == argc) {
|
||||
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
|
||||
goto End;
|
||||
}
|
||||
output = (const char*)GET_WARGV(argv, c);
|
||||
output = argv[c];
|
||||
} else if (name1 == NULL) {
|
||||
name1 = (const char*)GET_WARGV(argv, c);
|
||||
name1 = argv[c];
|
||||
} else {
|
||||
name2 = (const char*)GET_WARGV(argv, c);
|
||||
name2 = argv[c];
|
||||
}
|
||||
}
|
||||
if (help || name1 == NULL || name2 == NULL) {
|
||||
@@ -297,10 +290,9 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Error while computing the distortion.\n");
|
||||
goto End;
|
||||
}
|
||||
printf("%u %.2f %.2f %.2f %.2f %.2f [ %.2f bpp ]\n",
|
||||
printf("%u %.2f %.2f %.2f %.2f %.2f\n",
|
||||
(unsigned int)size1,
|
||||
disto[4], disto[0], disto[1], disto[2], disto[3],
|
||||
8.f * size1 / pic1.width / pic1.height);
|
||||
disto[4], disto[0], disto[1], disto[2], disto[3]);
|
||||
|
||||
if (output != NULL) {
|
||||
uint8_t* data = NULL;
|
||||
@@ -330,7 +322,6 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Can only compute the difference map in ARGB format.\n");
|
||||
goto End;
|
||||
}
|
||||
#if !defined(WEBP_REDUCE_CSP)
|
||||
data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb,
|
||||
pic1.width, pic1.height,
|
||||
pic1.argb_stride * 4,
|
||||
@@ -339,22 +330,14 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Error during lossless encoding.\n");
|
||||
goto End;
|
||||
}
|
||||
ret = ImgIoUtilWriteFile(output, data, data_size) ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
|
||||
WebPFree(data);
|
||||
if (ret) goto End;
|
||||
#else
|
||||
(void)data;
|
||||
(void)data_size;
|
||||
fprintf(stderr, "Cannot save the difference map. Please recompile "
|
||||
"without the WEBP_REDUCE_CSP flag.\n");
|
||||
goto End;
|
||||
#endif // WEBP_REDUCE_CSP
|
||||
}
|
||||
ret = EXIT_SUCCESS;
|
||||
ret = 0;
|
||||
|
||||
End:
|
||||
WebPPictureFree(&pic1);
|
||||
WebPPictureFree(&pic2);
|
||||
FREE_WARGV_AND_RETURN(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -11,13 +11,11 @@
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "extras/extras.h"
|
||||
#include "src/webp/types.h"
|
||||
#include "./extras.h"
|
||||
#include "webp/decode.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define INVALID_BIT_POS (1ull << 63)
|
||||
@@ -75,10 +73,10 @@ int VP8EstimateQuality(const uint8_t* const data, size_t size) {
|
||||
pos += 4;
|
||||
bit_pos = pos * 8;
|
||||
|
||||
GET_BIT(2); // colorspace + clamp type
|
||||
GET_BIT(2); // color_space + clamp type
|
||||
|
||||
// Segment header
|
||||
if (GET_BIT(1)) { // use_segment
|
||||
if (GET_BIT(1)) { // use_segment_
|
||||
int s;
|
||||
const int update_map = GET_BIT(1);
|
||||
if (GET_BIT(1)) { // update data
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
// Copyright 2023 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.
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Precomputed data for 420 risk estimation.
|
||||
|
||||
#ifndef WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
||||
#define WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
||||
|
||||
#include "src/webp/types.h"
|
||||
|
||||
extern const int kSharpYuvPrecomputedRiskYuvSampling;
|
||||
// Table of precomputed risk scores when chroma subsampling images with two
|
||||
// given colors.
|
||||
// Since precomputing values for all possible YUV colors would create a huge
|
||||
// table, the YUV space (i.e. [0, 255]^3) is reduced to
|
||||
// [0, kSharpYuvPrecomputedRiskYuvSampling-1]^3
|
||||
// where 255 maps to kSharpYuvPrecomputedRiskYuvSampling-1.
|
||||
// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB
|
||||
extern const uint8_t kSharpYuvPrecomputedRisk[];
|
||||
|
||||
#endif // WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
||||
@@ -15,7 +15,6 @@
|
||||
// Author: James Zern (jzern@google.com)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "webp/config.h"
|
||||
@@ -25,13 +24,12 @@
|
||||
|
||||
#include "webp_to_sdl.h"
|
||||
#include "webp/decode.h"
|
||||
#include "imageio/imageio_util.h"
|
||||
#include "../examples/unicode.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
|
||||
#if defined(WEBP_HAVE_JUST_SDL_H)
|
||||
#include <SDL.h>
|
||||
#else
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL/SDL.h>
|
||||
#endif
|
||||
|
||||
static void ProcessEvents(void) {
|
||||
@@ -50,43 +48,32 @@ static void ProcessEvents(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, char* argv[]) {
|
||||
int c;
|
||||
int ok = 0;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "Usage: %s [-h] image.webp [more_files.webp...]\n",
|
||||
argv[0]);
|
||||
goto Error;
|
||||
}
|
||||
|
||||
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(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else {
|
||||
file = (const char*)GET_WARGV(argv, c);
|
||||
file = argv[c];
|
||||
}
|
||||
if (file == NULL) continue;
|
||||
if (!ImgIoUtilReadFile(file, &webp, &webp_size)) {
|
||||
WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file);
|
||||
fprintf(stderr, "Error opening file: %s\n", 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);
|
||||
ok = WebpToSDL((const char*)webp, (int)webp_size);
|
||||
free((void*)webp);
|
||||
if (!ok) {
|
||||
WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file);
|
||||
fprintf(stderr, "Error decoding file %s\n", file);
|
||||
goto Error;
|
||||
}
|
||||
ProcessEvents();
|
||||
@@ -95,12 +82,12 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
Error:
|
||||
SDL_Quit();
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
#else // !WEBP_HAVE_SDL
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
fprintf(stderr, "SDL support not enabled in %s.\n", argv[0]);
|
||||
(void)argc;
|
||||
return 0;
|
||||
|
||||
@@ -11,34 +11,28 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../examples/unicode.h"
|
||||
#include "src/webp/types.h"
|
||||
#include "extras/extras.h"
|
||||
#include "imageio/imageio_util.h"
|
||||
#include "./extras.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
|
||||
// Returns EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
int main(int argc, const char* argv[]) {
|
||||
int main(int argc, const char *argv[]) {
|
||||
int c;
|
||||
int quiet = 0;
|
||||
int ok = 1;
|
||||
|
||||
INIT_WARGV(argc, argv);
|
||||
|
||||
for (c = 1; ok && c < argc; ++c) {
|
||||
if (!strcmp(argv[c], "-quiet")) {
|
||||
quiet = 1;
|
||||
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
|
||||
printf("webp_quality [-h][-quiet] webp_files...\n");
|
||||
FREE_WARGV_AND_RETURN(EXIT_SUCCESS);
|
||||
return 0;
|
||||
} else {
|
||||
const char* const filename = (const char*)GET_WARGV(argv, c);
|
||||
const char* const filename = argv[c];
|
||||
const uint8_t* data = NULL;
|
||||
size_t data_size = 0;
|
||||
int q;
|
||||
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||
if (!ok) break;
|
||||
q = VP8EstimateQuality(data, data_size);
|
||||
if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename);
|
||||
if (!quiet) printf("[%s] ", filename);
|
||||
if (q < 0) {
|
||||
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
|
||||
ok = 0;
|
||||
@@ -52,5 +46,5 @@ int main(int argc, const char* argv[]) {
|
||||
free((void*)data);
|
||||
}
|
||||
}
|
||||
FREE_WARGV_AND_RETURN(ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
90
extras/webp_to_sdl.c
Normal file → Executable file
90
extras/webp_to_sdl.c
Normal file → Executable file
@@ -12,7 +12,7 @@
|
||||
// Author: James Zern (jzern@google.com)
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "src/webp/config.h"
|
||||
#include "webp/config.h"
|
||||
#endif
|
||||
|
||||
#if defined(WEBP_HAVE_SDL)
|
||||
@@ -20,75 +20,83 @@
|
||||
#include "webp_to_sdl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "src/webp/decode.h"
|
||||
#include "webp/decode.h"
|
||||
|
||||
#if defined(WEBP_HAVE_JUST_SDL_H)
|
||||
#include <SDL.h>
|
||||
#else
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL/SDL.h>
|
||||
#endif
|
||||
|
||||
static int init_ok = 0;
|
||||
int WebPToSDL(const char* data, unsigned int data_size) {
|
||||
int WebpToSDL(const char* data, unsigned int data_size) {
|
||||
int ok = 0;
|
||||
VP8StatusCode status;
|
||||
WebPBitstreamFeatures input;
|
||||
uint8_t* output = NULL;
|
||||
SDL_Window* window = NULL;
|
||||
SDL_Renderer* renderer = NULL;
|
||||
SDL_Texture* texture = NULL;
|
||||
int width, height;
|
||||
WebPDecoderConfig config;
|
||||
WebPBitstreamFeatures* const input = &config.input;
|
||||
WebPDecBuffer* const output = &config.output;
|
||||
SDL_Surface* screen = NULL;
|
||||
SDL_Surface* surface = NULL;
|
||||
|
||||
if (!init_ok) {
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
init_ok = 1;
|
||||
if (!WebPInitDecoderConfig(&config)) {
|
||||
fprintf(stderr, "Library version mismatch!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &input);
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
|
||||
if (status != VP8_STATUS_OK) goto Error;
|
||||
width = input.width;
|
||||
height = input.height;
|
||||
|
||||
SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer);
|
||||
if (window == NULL || renderer == NULL) {
|
||||
fprintf(stderr, "Unable to create window or renderer!\n");
|
||||
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;
|
||||
}
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
|
||||
"linear"); // make the scaled rendering look smoother.
|
||||
SDL_RenderSetLogicalSize(renderer, width, height);
|
||||
|
||||
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
|
||||
SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
if (texture == NULL) {
|
||||
fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height);
|
||||
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 = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width,
|
||||
&height);
|
||||
output->colorspace = MODE_BGRA;
|
||||
#else
|
||||
output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width,
|
||||
&height);
|
||||
output->colorspace = MODE_RGBA;
|
||||
#endif
|
||||
if (output == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t));
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
|
||||
if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
|
||||
SDL_Flip(screen)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
ok = 1;
|
||||
|
||||
Error:
|
||||
// We should call SDL_DestroyWindow(window) but that makes .js fail.
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyTexture(texture);
|
||||
WebPFree(output);
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_FreeSurface(screen);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#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
|
||||
// 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);
|
||||
extern int WebpToSDL(const char* data, unsigned int data_size);
|
||||
|
||||
#endif // WEBP_EXTRAS_WEBP_TO_SDL_H_
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,6 @@
|
||||
#Thu May 12 17:06:25 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
|
||||
|
||||
65
gradlew
vendored
65
gradlew
vendored
@@ -1,20 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -44,16 +28,16 @@ APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
@@ -125,8 +109,8 @@ if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
@@ -154,30 +138,27 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
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
|
||||
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" "$@"
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
|
||||
190
gradlew.bat
vendored
190
gradlew.bat
vendored
@@ -1,100 +1,90 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# Ignore this file during non-NDK builds.
|
||||
ifdef NDK_ROOT
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
################################################################################
|
||||
@@ -54,4 +52,3 @@ LOCAL_STATIC_LIBRARIES := imageio_util
|
||||
LOCAL_MODULE := imageenc
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
endif # NDK_ROOT
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
|
||||
noinst_LTLIBRARIES =
|
||||
noinst_LTLIBRARIES += libimageio_util.la
|
||||
if BUILD_DEMUX
|
||||
noinst_LTLIBRARIES += libimagedec.la
|
||||
endif
|
||||
noinst_LTLIBRARIES += libimageenc.la
|
||||
noinst_LTLIBRARIES = libimageio_util.la libimagedec.la libimageenc.la
|
||||
|
||||
noinst_HEADERS =
|
||||
noinst_HEADERS += ../src/webp/decode.h
|
||||
noinst_HEADERS += ../src/webp/types.h
|
||||
|
||||
libimageio_util_la_SOURCES =
|
||||
libimageio_util_la_SOURCES += imageio_util.c imageio_util.h
|
||||
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 += metadata.c metadata.h
|
||||
libimagedec_la_SOURCES += pngdec.c pngdec.h
|
||||
@@ -23,10 +16,8 @@ libimagedec_la_SOURCES += tiffdec.c tiffdec.h
|
||||
libimagedec_la_SOURCES += webpdec.c webpdec.h
|
||||
libimagedec_la_SOURCES += wicdec.c wicdec.h
|
||||
libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
|
||||
libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS)
|
||||
libimagedec_la_LIBADD = ../src/demux/libwebpdemux.la
|
||||
libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
|
||||
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 += $(AM_CPPFLAGS)
|
||||
libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
|
||||
|
||||
@@ -9,30 +9,7 @@
|
||||
//
|
||||
// Generic image-type guessing.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "./image_dec.h"
|
||||
#include "./metadata.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
const char* WebPGetEnabledInputFileFormats(void) {
|
||||
return "WebP"
|
||||
#ifdef WEBP_HAVE_JPEG
|
||||
", JPEG"
|
||||
#endif
|
||||
#ifdef WEBP_HAVE_PNG
|
||||
", PNG"
|
||||
#endif
|
||||
", PNM (PGM, PPM, PAM)"
|
||||
#ifdef WEBP_HAVE_TIFF
|
||||
", TIFF"
|
||||
#endif
|
||||
#ifdef HAVE_WINCODEC_H
|
||||
", Windows Imaging Component (WIC)"
|
||||
#endif
|
||||
"";
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t GetBE32(const uint8_t buf[]) {
|
||||
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_
|
||||
#define WEBP_IMAGEIO_IMAGE_DEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -43,9 +41,6 @@ typedef enum {
|
||||
WEBP_UNSUPPORTED_FORMAT
|
||||
} WebPInputFileFormat;
|
||||
|
||||
// Returns a comma separated list of enabled input formats.
|
||||
const char* WebPGetEnabledInputFileFormats(void);
|
||||
|
||||
// Try to infer the image format. 'data_size' should be larger than 12.
|
||||
// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely.
|
||||
WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "./image_enc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WEBP_HAVE_PNG
|
||||
@@ -30,15 +29,11 @@
|
||||
// code with COBJMACROS.
|
||||
#include <ole2.h> // CreateStreamOnHGlobal()
|
||||
#include <shlwapi.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <wincodec.h>
|
||||
#endif
|
||||
|
||||
#include "../examples/unicode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PNG
|
||||
@@ -66,12 +61,11 @@ static HRESULT CreateOutputStream(const char* out_file_name,
|
||||
// Output to a memory buffer. This is freed when 'stream' is released.
|
||||
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
|
||||
} else {
|
||||
IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name,
|
||||
STGM_WRITE | STGM_CREATE, stream));
|
||||
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
_ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"),
|
||||
(const LPTSTR)out_file_name, hr);
|
||||
fprintf(stderr, "Error opening output file %s (%08lx)\n",
|
||||
out_file_name, hr);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
@@ -158,14 +152,20 @@ int WebPWritePNG(const char* out_file_name, int use_stdout,
|
||||
}
|
||||
|
||||
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
|
||||
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
|
||||
(void)unused; // remove variable-unused warning
|
||||
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
|
||||
(void)dummy; // remove variable-unused warning
|
||||
longjmp(png_jmpbuf(png), 1);
|
||||
}
|
||||
|
||||
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_infop info;
|
||||
png_uint_32 y;
|
||||
|
||||
if (out_file == NULL || buffer == NULL) return 0;
|
||||
|
||||
@@ -184,23 +184,14 @@ int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
|
||||
return 0;
|
||||
}
|
||||
png_init_io(png, out_file);
|
||||
{
|
||||
const uint32_t width = buffer->width;
|
||||
const uint32_t height = buffer->height;
|
||||
png_bytep row = buffer->u.RGBA.rgba;
|
||||
const int stride = buffer->u.RGBA.stride;
|
||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||
uint32_t y;
|
||||
|
||||
png_set_IHDR(png, info, width, height, 8,
|
||||
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png, info);
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_write_rows(png, &row, 1);
|
||||
row += stride;
|
||||
}
|
||||
png_set_IHDR(png, info, width, height, 8,
|
||||
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png, info);
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_write_rows(png, &row, 1);
|
||||
row += stride;
|
||||
}
|
||||
png_write_end(png, info);
|
||||
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
|
||||
@@ -263,20 +254,14 @@ int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
|
||||
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
|
||||
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
uint32_t width, height;
|
||||
uint8_t* rgba;
|
||||
int stride;
|
||||
const uint32_t width = buffer->width;
|
||||
const uint32_t height = buffer->height;
|
||||
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
||||
const int stride = buffer->u.RGBA.stride;
|
||||
const uint32_t bytes_per_px = 2;
|
||||
uint32_t y;
|
||||
|
||||
if (fout == NULL || buffer == NULL) return 0;
|
||||
|
||||
width = buffer->width;
|
||||
height = buffer->height;
|
||||
rgba = buffer->u.RGBA.rgba;
|
||||
stride = buffer->u.RGBA.stride;
|
||||
|
||||
if (rgba == NULL) return 0;
|
||||
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||
|
||||
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
|
||||
for (y = 0; y < height; ++y) {
|
||||
@@ -289,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) {
|
||||
dst[0] = (value >> 0) & 0xff;
|
||||
@@ -302,67 +287,49 @@ static void PutLE32(uint8_t* const dst, uint32_t value) {
|
||||
}
|
||||
|
||||
#define BMP_HEADER_SIZE 54
|
||||
#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info
|
||||
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
int has_alpha, header_size;
|
||||
uint32_t width, height;
|
||||
uint8_t* rgba;
|
||||
int stride;
|
||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||
const uint32_t width = buffer->width;
|
||||
const uint32_t height = buffer->height;
|
||||
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
||||
const int stride = buffer->u.RGBA.stride;
|
||||
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
|
||||
uint32_t y;
|
||||
uint32_t bytes_per_px, line_size, image_size, bmp_stride, total_size;
|
||||
uint8_t bmp_header[BMP_HEADER_SIZE + BMP_HEADER_ALPHA_EXTRA_SIZE] = { 0 };
|
||||
const uint32_t line_size = bytes_per_px * width;
|
||||
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
|
||||
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
|
||||
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
|
||||
|
||||
if (fout == NULL || buffer == NULL) return 0;
|
||||
|
||||
has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||
header_size = BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
|
||||
width = buffer->width;
|
||||
height = buffer->height;
|
||||
rgba = buffer->u.RGBA.rgba;
|
||||
stride = buffer->u.RGBA.stride;
|
||||
bytes_per_px = has_alpha ? 4 : 3;
|
||||
line_size = bytes_per_px * width;
|
||||
bmp_stride = (line_size + 3) & ~3; // pad to 4
|
||||
image_size = bmp_stride * height;
|
||||
total_size = image_size + header_size;
|
||||
|
||||
if (rgba == NULL) return 0;
|
||||
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||
|
||||
// bitmap file header
|
||||
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
|
||||
PutLE32(bmp_header + 2, total_size); // size including header
|
||||
PutLE32(bmp_header + 6, 0); // reserved
|
||||
PutLE32(bmp_header + 10, header_size); // offset to pixel array
|
||||
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
|
||||
// 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 + 22, height); // no vertical flip
|
||||
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
|
||||
PutLE16(bmp_header + 26, 1); // number of planes
|
||||
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
|
||||
PutLE32(bmp_header + 30, has_alpha ? 3 : 0); // BI_BITFIELDS or BI_RGB
|
||||
PutLE32(bmp_header + 34, image_size);
|
||||
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
|
||||
PutLE32(bmp_header + 34, 0); // image size (dummy)
|
||||
PutLE32(bmp_header + 38, 2400); // x pixels/meter
|
||||
PutLE32(bmp_header + 42, 2400); // y pixels/meter
|
||||
PutLE32(bmp_header + 46, 0); // number of palette colors
|
||||
PutLE32(bmp_header + 50, 0); // important color count
|
||||
if (has_alpha) { // BITMAPV3INFOHEADER complement
|
||||
PutLE32(bmp_header + 54, 0x00ff0000); // red mask
|
||||
PutLE32(bmp_header + 58, 0x0000ff00); // green mask
|
||||
PutLE32(bmp_header + 62, 0x000000ff); // blue mask
|
||||
PutLE32(bmp_header + 66, 0xff000000); // alpha mask
|
||||
}
|
||||
|
||||
// TODO(skal): color profile
|
||||
|
||||
// write header
|
||||
if (fwrite(bmp_header, header_size, 1, fout) != 1) {
|
||||
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// write pixel array, bottom to top
|
||||
// write pixel array
|
||||
for (y = 0; y < height; ++y) {
|
||||
const uint8_t* const src = &rgba[(uint64_t)(height - 1 - y) * stride];
|
||||
if (fwrite(src, line_size, 1, fout) != 1) {
|
||||
if (fwrite(rgba, line_size, 1, fout) != 1) {
|
||||
return 0;
|
||||
}
|
||||
// write padding zeroes
|
||||
@@ -372,11 +339,11 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rgba += stride;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#undef BMP_HEADER_SIZE
|
||||
#undef BMP_HEADER_ALPHA_EXTRA_SIZE
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TIFF
|
||||
@@ -388,14 +355,17 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
|
||||
|
||||
int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
int has_alpha;
|
||||
uint32_t width, height;
|
||||
uint8_t* rgba;
|
||||
int stride;
|
||||
uint8_t bytes_per_px = 0;
|
||||
const uint8_t assoc_alpha = 0;
|
||||
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||
const uint32_t width = buffer->width;
|
||||
const uint32_t height = buffer->height;
|
||||
const uint8_t* rgba = buffer->u.RGBA.rgba;
|
||||
const int stride = buffer->u.RGBA.stride;
|
||||
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
|
||||
const uint8_t assoc_alpha =
|
||||
WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
|
||||
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
|
||||
const uint8_t num_ifd_entries = 0;
|
||||
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
|
||||
: NUM_IFD_ENTRIES - 1;
|
||||
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
|
||||
0x49, 0x49, 0x2a, 0x00, // little endian signature
|
||||
8, 0, 0, 0, // offset to the unique IFD that follows
|
||||
@@ -429,20 +399,7 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
};
|
||||
uint32_t y;
|
||||
|
||||
if (fout == NULL || buffer == NULL) return 0;
|
||||
|
||||
has_alpha = WebPIsAlphaMode(buffer->colorspace);
|
||||
width = buffer->width;
|
||||
height = buffer->height;
|
||||
rgba = buffer->u.RGBA.rgba;
|
||||
stride = buffer->u.RGBA.stride;
|
||||
|
||||
if (rgba == NULL) return 0;
|
||||
|
||||
// Update bytes_per_px, num_ifd_entries and assoc_alpha.
|
||||
tiff_header[38] = tiff_header[102] = bytes_per_px = has_alpha ? 4 : 3;
|
||||
tiff_header[8] = has_alpha ? NUM_IFD_ENTRIES : NUM_IFD_ENTRIES - 1;
|
||||
tiff_header[186] = WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
|
||||
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
|
||||
|
||||
// Fill placeholders in IFD:
|
||||
PutLE32(tiff_header + 10 + 8, width);
|
||||
@@ -585,26 +542,22 @@ int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
|
||||
// Generic top-level call
|
||||
|
||||
int WebPSaveImage(const WebPDecBuffer* const buffer,
|
||||
WebPOutputFileFormat format,
|
||||
const char* const out_file_name) {
|
||||
WebPOutputFileFormat format, const char* const out_file) {
|
||||
FILE* fout = NULL;
|
||||
int needs_open_file = 1;
|
||||
const int use_stdout =
|
||||
(out_file_name != NULL) && !WSTRCMP(out_file_name, "-");
|
||||
const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
|
||||
int ok = 1;
|
||||
|
||||
if (buffer == NULL || out_file_name == NULL) return 0;
|
||||
if (buffer == NULL || out_file == NULL) return 0;
|
||||
|
||||
#ifdef HAVE_WINCODEC_H
|
||||
needs_open_file = (format != PNG);
|
||||
#endif
|
||||
|
||||
if (needs_open_file) {
|
||||
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout)
|
||||
: WFOPEN(out_file_name, "wb");
|
||||
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
||||
if (fout == NULL) {
|
||||
WFPRINTF(stderr, "Error opening output file %s\n",
|
||||
(const W_CHAR*)out_file_name);
|
||||
fprintf(stderr, "Error opening output file %s\n", out_file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -613,7 +566,7 @@ int WebPSaveImage(const WebPDecBuffer* const buffer,
|
||||
format == RGBA || format == BGRA || format == ARGB ||
|
||||
format == rgbA || format == bgrA || format == Argb) {
|
||||
#ifdef HAVE_WINCODEC_H
|
||||
ok &= WebPWritePNG(out_file_name, use_stdout, buffer);
|
||||
ok &= WebPWritePNG(out_file, use_stdout, buffer);
|
||||
#else
|
||||
ok &= WebPWritePNG(fout, buffer);
|
||||
#endif
|
||||
|
||||
@@ -79,7 +79,7 @@ int WebPWriteTIFF(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).
|
||||
// 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).
|
||||
int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
|
||||
|
||||
|
||||
@@ -16,13 +16,9 @@
|
||||
#include <fcntl.h> // for _O_BINARY
|
||||
#include <io.h> // for _setmode()
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
#include "../examples/unicode.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// File I/O
|
||||
|
||||
@@ -51,8 +47,7 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
while (!feof(stdin)) {
|
||||
// We double the buffer size each time and read as much as possible.
|
||||
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
|
||||
// we allocate one extra byte for the \0 terminator
|
||||
void* const new_data = realloc(input, max_size + extra_size + 1);
|
||||
void* const new_data = realloc(input, max_size + extra_size);
|
||||
if (new_data == NULL) goto Error;
|
||||
input = (uint8_t*)new_data;
|
||||
max_size += extra_size;
|
||||
@@ -60,7 +55,6 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
if (size < max_size) break;
|
||||
}
|
||||
if (ferror(stdin)) goto Error;
|
||||
if (input != NULL) input[size] = '\0'; // convenient 0-terminator
|
||||
*data = input;
|
||||
*data_size = size;
|
||||
return 1;
|
||||
@@ -74,10 +68,10 @@ int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
|
||||
int ImgIoUtilReadFile(const char* const file_name,
|
||||
const uint8_t** data, size_t* data_size) {
|
||||
int ok;
|
||||
uint8_t* file_data;
|
||||
void* file_data;
|
||||
size_t file_size;
|
||||
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);
|
||||
|
||||
@@ -85,57 +79,42 @@ int ImgIoUtilReadFile(const char* const file_name,
|
||||
*data = NULL;
|
||||
*data_size = 0;
|
||||
|
||||
in = WFOPEN(file_name, "rb");
|
||||
in = fopen(file_name, "rb");
|
||||
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;
|
||||
}
|
||||
fseek(in, 0, SEEK_END);
|
||||
file_size = ftell(in);
|
||||
if (file_size == (size_t)-1) {
|
||||
fclose(in);
|
||||
WFPRINTF(stderr, "error getting size of '%s'\n", (const W_CHAR*)file_name);
|
||||
return 0;
|
||||
}
|
||||
fseek(in, 0, SEEK_SET);
|
||||
// we allocate one extra byte for the \0 terminator
|
||||
file_data = (uint8_t*)WebPMalloc(file_size + 1);
|
||||
if (file_data == NULL) {
|
||||
fclose(in);
|
||||
WFPRINTF(stderr, "memory allocation failure when reading file %s\n",
|
||||
(const W_CHAR*)file_name);
|
||||
return 0;
|
||||
}
|
||||
file_data = malloc(file_size);
|
||||
if (file_data == NULL) return 0;
|
||||
ok = (fread(file_data, file_size, 1, in) == 1);
|
||||
fclose(in);
|
||||
|
||||
if (!ok) {
|
||||
WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n",
|
||||
(int)file_size, (const W_CHAR*)file_name);
|
||||
WebPFree(file_data);
|
||||
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
|
||||
(int)file_size, file_name);
|
||||
free(file_data);
|
||||
return 0;
|
||||
}
|
||||
file_data[file_size] = '\0'; // convenient 0-terminator
|
||||
*data = file_data;
|
||||
*data = (uint8_t*)file_data;
|
||||
*data_size = file_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int ImgIoUtilWriteFile(const char* const file_name,
|
||||
const uint8_t* data, size_t data_size) {
|
||||
int ok;
|
||||
FILE* out;
|
||||
const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-");
|
||||
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
|
||||
|
||||
if (data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb");
|
||||
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(file_name, "wb");
|
||||
if (out == NULL) {
|
||||
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
|
||||
(const W_CHAR*)file_name);
|
||||
fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
|
||||
return 0;
|
||||
}
|
||||
ok = (fwrite(data, data_size, 1, out) == 1);
|
||||
@@ -156,15 +135,9 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) {
|
||||
const uint64_t total_size = stride * height;
|
||||
int ok = (total_size == (size_t)total_size);
|
||||
// check that 'stride' is representable as int:
|
||||
ok = ok && ((uint64_t)(int)stride == stride);
|
||||
#if defined(WEBP_MAX_IMAGE_SIZE)
|
||||
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
|
||||
#endif
|
||||
return ok;
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
||||
const uint64_t total_size = nmemb * size;
|
||||
return (total_size == (size_t)total_size);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#define WEBP_IMAGEIO_IMAGEIO_UTIL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -30,10 +29,7 @@ FILE* ImgIoUtilSetBinaryMode(FILE* file);
|
||||
|
||||
// Allocates storage for entire file 'file_name' and returns contents and size
|
||||
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
|
||||
// be deleted using WebPFree().
|
||||
// Note: for convenience, the data will be null-terminated with an extra byte
|
||||
// (not accounted for in *data_size), in case the file is text and intended
|
||||
// to be used as a C-string.
|
||||
// be deleted using free().
|
||||
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
|
||||
// the function ImgIoUtilReadFromStdin().
|
||||
int ImgIoUtilReadFile(const char* const file_name,
|
||||
@@ -55,8 +51,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns 0 in case of overflow, memory over-allocation or excessive dimension.
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height);
|
||||
// Returns 0 in case of overflow of nmemb * size.
|
||||
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -24,10 +24,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webp/encode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "./metadata.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Metadata processing
|
||||
@@ -207,18 +206,7 @@ struct my_error_mgr {
|
||||
|
||||
static void my_error_exit(j_common_ptr dinfo) {
|
||||
struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
|
||||
// The following code is disabled in fuzzing mode because:
|
||||
// - the logs can be flooded due to invalid JPEG files
|
||||
// - msg_code is wrongfully seen as uninitialized by msan when the libjpeg
|
||||
// dependency is not built with sanitizers enabled
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
const int msg_code = myerr->pub.msg_code;
|
||||
fprintf(stderr, "libjpeg error: ");
|
||||
dinfo->err->output_message(dinfo);
|
||||
if (msg_code == JERR_INPUT_EOF || msg_code == JERR_FILE_READ) {
|
||||
fprintf(stderr, "`jpegtran -copy all` MAY be able to process this file.\n");
|
||||
}
|
||||
#endif
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
@@ -285,7 +273,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
||||
ctx.data = data;
|
||||
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);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
@@ -316,18 +304,18 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
||||
|
||||
if (stride != (int)stride ||
|
||||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
||||
goto Error;
|
||||
goto End;
|
||||
}
|
||||
|
||||
rgb = (uint8_t*)malloc((size_t)stride * height);
|
||||
if (rgb == NULL) {
|
||||
goto Error;
|
||||
goto End;
|
||||
}
|
||||
buffer[0] = (JSAMPLE*)rgb;
|
||||
|
||||
while (dinfo.output_scanline < dinfo.output_height) {
|
||||
if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) {
|
||||
goto Error;
|
||||
goto End;
|
||||
}
|
||||
buffer[0] += stride;
|
||||
}
|
||||
@@ -347,11 +335,7 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
|
||||
pic->width = width;
|
||||
pic->height = height;
|
||||
ok = WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||
if (!ok) {
|
||||
pic->width = 0; // WebPPictureImportRGB() barely touches 'pic' on failure.
|
||||
pic->height = 0; // Just reset dimensions but keep any 'custom_ptr' etc.
|
||||
MetadataFree(metadata); // In case the caller forgets to free it on error.
|
||||
}
|
||||
if (!ok) goto Error;
|
||||
|
||||
End:
|
||||
free(rgb);
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#ifndef WEBP_IMAGEIO_JPEGDEC_H_
|
||||
#define WEBP_IMAGEIO_JPEGDEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
#ifndef WEBP_IMAGEIO_METADATA_H_
|
||||
#define WEBP_IMAGEIO_METADATA_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -18,47 +18,20 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WEBP_HAVE_PNG
|
||||
#ifndef PNG_USER_MEM_SUPPORTED
|
||||
#define PNG_USER_MEM_SUPPORTED // for png_create_read_struct_2
|
||||
#endif
|
||||
#include <png.h>
|
||||
|
||||
#include <setjmp.h> // note: this must be included *after* png.h
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webp/encode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "./metadata.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#define LOCAL_PNG_VERSION ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR)
|
||||
#define LOCAL_PNG_PREREQ(maj, min) \
|
||||
(LOCAL_PNG_VERSION >= (((maj) << 8) | (min)))
|
||||
|
||||
static void PNGAPI error_function(png_structp png, png_const_charp error) {
|
||||
if (error != NULL) fprintf(stderr, "libpng error: %s\n", error);
|
||||
longjmp(png_jmpbuf(png), 1);
|
||||
}
|
||||
|
||||
#if LOCAL_PNG_PREREQ(1,4)
|
||||
typedef png_alloc_size_t LocalPngAllocSize;
|
||||
#else
|
||||
typedef png_size_t LocalPngAllocSize;
|
||||
#endif
|
||||
|
||||
static png_voidp MallocFunc(png_structp png_ptr, LocalPngAllocSize size) {
|
||||
(void)png_ptr;
|
||||
if (size != (size_t)size) return NULL;
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow(size, 1)) return NULL;
|
||||
return (png_voidp)malloc((size_t)size);
|
||||
}
|
||||
|
||||
static void FreeFunc(png_structp png_ptr, png_voidp ptr) {
|
||||
(void)png_ptr;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Converts the NULL terminated 'hexstring' which contains 2-byte character
|
||||
// representations of hex values to raw data.
|
||||
// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs,
|
||||
@@ -135,14 +108,12 @@ static const struct {
|
||||
MetadataPayload* const payload);
|
||||
size_t storage_offset;
|
||||
} 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.
|
||||
{ "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) },
|
||||
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
|
||||
// Exiftool puts exif data in APP1 chunk, too.
|
||||
{ "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) },
|
||||
// ImageMagick uses lowercase app1.
|
||||
{ "Raw profile type app1", ProcessRawProfile, METADATA_OFFSET(exif) },
|
||||
// XMP Specification Part 3, Section 3 #PNG
|
||||
{ "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) },
|
||||
{ NULL, NULL, 0 },
|
||||
@@ -163,20 +134,6 @@ static int ExtractMetadataFromPNG(png_structp png,
|
||||
png_textp text = NULL;
|
||||
const png_uint_32 num = png_get_text(png, info, &text, NULL);
|
||||
png_uint_32 i;
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
// Look for an 'eXIf' tag. Preference is given to this tag as it's newer
|
||||
// than the TextualData tags.
|
||||
{
|
||||
png_bytep exif;
|
||||
png_uint_32 len;
|
||||
|
||||
if (png_get_eXIf_1(png, info, &len, &exif) == PNG_INFO_eXIf) {
|
||||
if (!MetadataCopy((const char*)exif, len, &metadata->exif)) return 0;
|
||||
}
|
||||
}
|
||||
#endif // PNG_eXIf_SUPPORTED
|
||||
|
||||
// Look for EXIF / XMP metadata.
|
||||
for (i = 0; i < num; ++i, ++text) {
|
||||
int j;
|
||||
@@ -210,15 +167,15 @@ static int ExtractMetadataFromPNG(png_structp png,
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PNG_iCCP_SUPPORTED
|
||||
// Look for an ICC profile.
|
||||
{
|
||||
png_charp name;
|
||||
int comp_type;
|
||||
#if LOCAL_PNG_PREREQ(1,5)
|
||||
png_bytep profile;
|
||||
#else
|
||||
#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \
|
||||
((1 << 8) | (5 << 0))
|
||||
png_charp profile;
|
||||
#else // >= libpng 1.5.0
|
||||
png_bytep profile;
|
||||
#endif
|
||||
png_uint_32 len;
|
||||
|
||||
@@ -227,8 +184,8 @@ static int ExtractMetadataFromPNG(png_structp png,
|
||||
if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
|
||||
}
|
||||
}
|
||||
#endif // PNG_iCCP_SUPPORTED
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -255,7 +212,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
||||
volatile png_infop end_info = NULL;
|
||||
PNGReadContext context = { NULL, 0, 0 };
|
||||
int color_type, bit_depth, interlaced;
|
||||
int num_channels;
|
||||
int has_alpha;
|
||||
int num_passes;
|
||||
int p;
|
||||
volatile int ok = 0;
|
||||
@@ -268,8 +225,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
||||
context.data = data;
|
||||
context.data_size = data_size;
|
||||
|
||||
png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
|
||||
NULL, MallocFunc, FreeFunc);
|
||||
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if (png == NULL) goto End;
|
||||
|
||||
png_set_error_fn(png, 0, error_function, NULL);
|
||||
@@ -279,15 +235,6 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
||||
goto End;
|
||||
}
|
||||
|
||||
#if LOCAL_PNG_PREREQ(1,5) || \
|
||||
(LOCAL_PNG_PREREQ(1,4) && PNG_LIBPNG_VER_RELEASE >= 1)
|
||||
// If it looks like the bitstream is going to need more memory than libpng's
|
||||
// internal limit (default: 8M), try to (reasonably) raise it.
|
||||
if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) {
|
||||
png_set_chunk_malloc_max(png, data_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
info = png_create_info_struct(png);
|
||||
if (info == NULL) goto Error;
|
||||
end_info = png_create_info_struct(png);
|
||||
@@ -313,30 +260,20 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
||||
}
|
||||
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png);
|
||||
}
|
||||
|
||||
// Apply gamma correction if needed.
|
||||
{
|
||||
double image_gamma = 1 / 2.2, screen_gamma = 2.2;
|
||||
int srgb_intent;
|
||||
if (png_get_sRGB(png, info, &srgb_intent) ||
|
||||
png_get_gAMA(png, info, &image_gamma)) {
|
||||
png_set_gamma(png, screen_gamma, image_gamma);
|
||||
}
|
||||
has_alpha = 1;
|
||||
} else {
|
||||
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
|
||||
}
|
||||
|
||||
if (!keep_alpha) {
|
||||
png_set_strip_alpha(png);
|
||||
has_alpha = 0;
|
||||
}
|
||||
|
||||
num_passes = png_set_interlace_handling(png);
|
||||
png_read_update_info(png, info);
|
||||
|
||||
num_channels = png_get_channels(png, info);
|
||||
if (num_channels != 3 && num_channels != 4) {
|
||||
goto Error;
|
||||
}
|
||||
stride = (int64_t)num_channels * width * sizeof(*rgb);
|
||||
stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
||||
if (stride != (int)stride ||
|
||||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
||||
goto Error;
|
||||
@@ -361,8 +298,8 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
|
||||
|
||||
pic->width = (int)width;
|
||||
pic->height = (int)height;
|
||||
ok = (num_channels == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
|
||||
: WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride)
|
||||
: WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||
|
||||
if (!ok) {
|
||||
goto Error;
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#ifndef WEBP_IMAGEIO_PNGDEC_H_
|
||||
#define WEBP_IMAGEIO_PNGDEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
116
imageio/pnmdec.c
116
imageio/pnmdec.c
@@ -17,13 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./imageio_util.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#include "./imageio_util.h"
|
||||
|
||||
typedef enum {
|
||||
WIDTH_FLAG = 1 << 0,
|
||||
@@ -31,15 +26,15 @@ typedef enum {
|
||||
DEPTH_FLAG = 1 << 2,
|
||||
MAXVAL_FLAG = 1 << 3,
|
||||
TUPLE_FLAG = 1 << 4,
|
||||
ALL_NEEDED_FLAGS = WIDTH_FLAG | HEIGHT_FLAG | DEPTH_FLAG | MAXVAL_FLAG
|
||||
ALL_NEEDED_FLAGS = 0x1f
|
||||
} 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 bytes_per_px; // 1, 3, 4
|
||||
int depth;
|
||||
int max_value;
|
||||
int type; // 5, 6 or 7
|
||||
int seen_flags;
|
||||
@@ -79,7 +74,6 @@ 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);
|
||||
@@ -101,43 +95,33 @@ static size_t ReadPAMFields(PNMInfo* const info, size_t off) {
|
||||
info->seen_flags |= MAXVAL_FLAG;
|
||||
info->max_value = tmp;
|
||||
} else if (!strcmp(out, "TUPLTYPE RGB_ALPHA")) {
|
||||
expected_depth = 4;
|
||||
info->bytes_per_px = 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->bytes_per_px = 3;
|
||||
info->seen_flags |= TUPLE_FLAG;
|
||||
} else if (!strcmp(out, "TUPLTYPE GRAYSCALE")) {
|
||||
expected_depth = 1;
|
||||
info->bytes_per_px = 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);
|
||||
if (out_size > 20) sprintf(out + 20 - strlen(kEllipsis), 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] = ' ';
|
||||
if (!isprint(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 (!(info->seen_flags & TUPLE_FLAG)) {
|
||||
info->seen_flags |= TUPLE_FLAG;
|
||||
info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1);
|
||||
}
|
||||
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);
|
||||
if (info->seen_flags != ALL_NEEDED_FLAGS) {
|
||||
fprintf(stderr, "PAM: incomplete header.\n");
|
||||
return 0;
|
||||
}
|
||||
return off;
|
||||
@@ -171,15 +155,16 @@ static size_t ReadHeader(PNMInfo* const info) {
|
||||
|
||||
// finish initializing missing fields
|
||||
info->depth = (info->type == 5) ? 1 : 3;
|
||||
info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1);
|
||||
}
|
||||
// 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->bytes_per_px < info->depth ||
|
||||
info->max_value <= 0 || info->max_value >= 65536) {
|
||||
return 0;
|
||||
}
|
||||
info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1);
|
||||
return off;
|
||||
}
|
||||
|
||||
@@ -188,7 +173,7 @@ int ReadPNM(const uint8_t* const data, size_t data_size,
|
||||
struct Metadata* const metadata) {
|
||||
int ok = 0;
|
||||
int i, j;
|
||||
uint64_t stride, pixel_bytes, sample_size, depth;
|
||||
uint64_t stride, pixel_bytes;
|
||||
uint8_t* rgb = NULL, *tmp_rgb;
|
||||
size_t offset;
|
||||
PNMInfo info;
|
||||
@@ -219,10 +204,8 @@ int ReadPNM(const uint8_t* const data, size_t data_size,
|
||||
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;
|
||||
stride =
|
||||
(uint64_t)(info.bytes_per_px < 3 ? 3 : info.bytes_per_px) * info.width;
|
||||
if (stride != (size_t)stride ||
|
||||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, info.height)) {
|
||||
goto End;
|
||||
@@ -231,63 +214,30 @@ int ReadPNM(const uint8_t* const data, size_t data_size,
|
||||
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.
|
||||
// Convert input
|
||||
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
|
||||
}
|
||||
assert(offset + info.bytes_per_px * info.width <= data_size);
|
||||
if (info.depth == 1) {
|
||||
// convert grayscale -> RGB
|
||||
for (i = 0; i < info.width; ++i) {
|
||||
const uint8_t v = data[offset + i];
|
||||
tmp_rgb[3 * i + 0] = tmp_rgb[3 * i + 1] = tmp_rgb[3 * i + 2] = v;
|
||||
}
|
||||
} else if (info.depth == 3) { // RGB
|
||||
memcpy(tmp_rgb, data + offset, 3 * info.width * sizeof(*data));
|
||||
} else if (info.depth == 4) { // RGBA
|
||||
memcpy(tmp_rgb, data + offset, 4 * info.width * sizeof(*data));
|
||||
}
|
||||
offset += info.bytes_per_px * info.width;
|
||||
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);
|
||||
ok = (info.depth == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
|
||||
: WebPPictureImportRGB(pic, rgb, (int)stride);
|
||||
if (!ok) goto End;
|
||||
|
||||
ok = 1;
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#ifndef WEBP_IMAGEIO_PNMDEC_H_
|
||||
#define WEBP_IMAGEIO_PNMDEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -22,10 +22,9 @@
|
||||
#ifdef WEBP_HAVE_TIFF
|
||||
#include <tiffio.h>
|
||||
|
||||
#include "webp/encode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "./metadata.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
static const struct {
|
||||
ttag_t tag;
|
||||
@@ -47,7 +46,7 @@ static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
|
||||
(MetadataPayload*)((uint8_t*)metadata +
|
||||
kTIFFMetadataMap[i].storage_offset);
|
||||
void* tag_data;
|
||||
uint32_t tag_data_len;
|
||||
uint32 tag_data_len;
|
||||
|
||||
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
|
||||
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
|
||||
@@ -122,6 +121,7 @@ static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
|
||||
// (we don't want to force a dependency to a libdspdec library).
|
||||
#define MFIX 24 // 24bit fixed-point arithmetic
|
||||
#define HALF ((1u << MFIX) >> 1)
|
||||
#define KINV_255 ((1u << MFIX) / 255u)
|
||||
|
||||
static uint32_t Unmult(uint8_t x, uint32_t mult) {
|
||||
const uint32_t v = (x * mult + HALF) >> MFIX;
|
||||
@@ -132,9 +132,6 @@ 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) {
|
||||
@@ -157,8 +154,7 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
Metadata* const metadata) {
|
||||
MyData my_data = { data, (toff_t)data_size, 0 };
|
||||
TIFF* tif;
|
||||
uint32_t image_width, image_height, tile_width, tile_height;
|
||||
uint64_t stride;
|
||||
uint32_t width, height;
|
||||
uint16_t samples_per_px = 0;
|
||||
uint16_t extra_samples = 0;
|
||||
uint16_t* extra_samples_ptr = NULL;
|
||||
@@ -189,40 +185,17 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
|
||||
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 (samples_per_px < 3 || samples_per_px > 4) goto End; // not supported
|
||||
|
||||
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) &&
|
||||
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) {
|
||||
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
|
||||
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
|
||||
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
|
||||
goto End;
|
||||
}
|
||||
stride = (uint64_t)image_width * sizeof(*raster);
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) {
|
||||
fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n",
|
||||
image_width, image_height);
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
|
||||
sizeof(*raster))) {
|
||||
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");
|
||||
@@ -230,32 +203,33 @@ int ReadTIFF(const uint8_t* const data, size_t data_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;
|
||||
|
||||
raster = (uint32_t*)_TIFFmalloc((tsize_t)alloc_size);
|
||||
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
|
||||
if (raster != NULL) {
|
||||
if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster,
|
||||
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
|
||||
ORIENTATION_TOPLEFT, 1)) {
|
||||
pic->width = image_width;
|
||||
pic->height = image_height;
|
||||
const int stride = width * sizeof(*raster);
|
||||
pic->width = width;
|
||||
pic->height = height;
|
||||
// TIFF data is ABGR
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
TIFFSwabArrayOfLong(raster, image_width * image_height);
|
||||
TIFFSwabArrayOfLong(raster, width * height);
|
||||
#endif
|
||||
// if we have an alpha channel, we must un-multiply from rgbA to RGBA
|
||||
if (extra_samples == 1 && extra_samples_ptr != NULL &&
|
||||
extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) {
|
||||
uint32_t y;
|
||||
uint8_t* tmp = (uint8_t*)raster;
|
||||
for (y = 0; y < image_height; ++y) {
|
||||
MultARGBRow(tmp, image_width);
|
||||
for (y = 0; y < height; ++y) {
|
||||
MultARGBRow(tmp, width);
|
||||
tmp += stride;
|
||||
}
|
||||
}
|
||||
ok = keep_alpha
|
||||
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride)
|
||||
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride);
|
||||
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
|
||||
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
|
||||
}
|
||||
_TIFFfree(raster);
|
||||
} else {
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#ifndef WEBP_IMAGEIO_TIFFDEC_H_
|
||||
#define WEBP_IMAGEIO_TIFFDEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -9,23 +9,15 @@
|
||||
//
|
||||
// WebP decode.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "webp/config.h"
|
||||
#endif
|
||||
#include "./webpdec.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../examples/unicode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/encode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "./metadata.h"
|
||||
#include "./webpdec.h"
|
||||
#include "webp/decode.h"
|
||||
#include "webp/demux.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/mux_types.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebP decoding
|
||||
@@ -45,7 +37,7 @@ static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
|
||||
}
|
||||
|
||||
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);
|
||||
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||
fprintf(stderr, "(%s)", kStatusMessages[status]);
|
||||
@@ -66,7 +58,7 @@ int LoadWebP(const char* const in_file,
|
||||
|
||||
status = WebPGetFeatures(*data, *data_size, bitstream);
|
||||
if (status != VP8_STATUS_OK) {
|
||||
WebPFree((void*)*data);
|
||||
free((void*)*data);
|
||||
*data = NULL;
|
||||
*data_size = 0;
|
||||
PrintWebPError(in_file, status);
|
||||
@@ -96,50 +88,28 @@ VP8StatusCode DecodeWebPIncremental(
|
||||
{
|
||||
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
|
||||
if (idec == NULL) {
|
||||
fprintf(stderr, "Failed during WebPIDecode().\n");
|
||||
fprintf(stderr, "Failed during WebPINewDecoder().\n");
|
||||
return VP8_STATUS_OUT_OF_MEMORY;
|
||||
} 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);
|
||||
#endif
|
||||
WebPIDelete(idec);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Metadata
|
||||
|
||||
static int ExtractMetadata(const uint8_t* const data, size_t data_size,
|
||||
Metadata* const metadata) {
|
||||
WebPData webp_data = { data, data_size };
|
||||
WebPDemuxer* const demux = WebPDemux(&webp_data);
|
||||
WebPChunkIterator chunk_iter;
|
||||
uint32_t flags;
|
||||
|
||||
if (demux == NULL) return 0;
|
||||
assert(metadata != NULL);
|
||||
|
||||
flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
|
||||
|
||||
if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
|
||||
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
|
||||
&metadata->iccp);
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
}
|
||||
if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
|
||||
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
|
||||
&metadata->exif);
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
}
|
||||
if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
|
||||
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
|
||||
&metadata->xmp);
|
||||
WebPDemuxReleaseChunkIterator(&chunk_iter);
|
||||
}
|
||||
WebPDemuxDelete(demux);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||
@@ -153,6 +123,11 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||
|
||||
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)) {
|
||||
fprintf(stderr, "Library version mismatch!\n");
|
||||
return 0;
|
||||
@@ -166,32 +141,17 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||
|
||||
do {
|
||||
const int has_alpha = keep_alpha && bitstream->has_alpha;
|
||||
uint64_t stride;
|
||||
pic->width = bitstream->width;
|
||||
pic->height = bitstream->height;
|
||||
if (pic->use_argb) {
|
||||
stride = (uint64_t)bitstream->width * 4;
|
||||
} else {
|
||||
stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
|
||||
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
|
||||
}
|
||||
|
||||
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
|
||||
status = VP8_STATUS_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pic->use_argb) pic->colorspace = has_alpha ? WEBP_YUV420A
|
||||
: WEBP_YUV420;
|
||||
ok = WebPPictureAlloc(pic);
|
||||
if (!ok) {
|
||||
status = VP8_STATUS_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
if (pic->use_argb) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
output_buffer->colorspace = MODE_ARGB;
|
||||
#else
|
||||
output_buffer->colorspace = MODE_BGRA;
|
||||
#endif
|
||||
output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
|
||||
output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
|
||||
output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
|
||||
@@ -214,6 +174,7 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||
|
||||
status = DecodeWebP(data, data_size, &config);
|
||||
ok = (status == VP8_STATUS_OK);
|
||||
if (!ok) WebPPictureFree(pic);
|
||||
if (ok && !keep_alpha && pic->use_argb) {
|
||||
// Need to wipe out the alpha value, as requested.
|
||||
int x, y;
|
||||
@@ -227,18 +188,9 @@ int ReadWebP(const uint8_t* const data, size_t data_size,
|
||||
|
||||
if (status != VP8_STATUS_OK) {
|
||||
PrintWebPError("input data", status);
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
WebPFreeDecBuffer(output_buffer);
|
||||
|
||||
if (ok && metadata != NULL) {
|
||||
ok = ExtractMetadata(data, data_size, metadata);
|
||||
if (!ok) {
|
||||
PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
|
||||
}
|
||||
}
|
||||
if (!ok) WebPPictureFree(pic);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,7 @@
|
||||
#ifndef WEBP_IMAGEIO_WEBPDEC_H_
|
||||
#define WEBP_IMAGEIO_WEBPDEC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webp/decode.h"
|
||||
#include "webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -29,14 +29,12 @@
|
||||
// code with COBJMACROS.
|
||||
#include <ole2.h> // CreateStreamOnHGlobal()
|
||||
#include <shlwapi.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <wincodec.h>
|
||||
|
||||
#include "../examples/unicode.h"
|
||||
#include "webp/encode.h"
|
||||
#include "./imageio_util.h"
|
||||
#include "./metadata.h"
|
||||
#include "webp/encode.h"
|
||||
|
||||
#define IFS(fn) \
|
||||
do { \
|
||||
@@ -87,7 +85,7 @@ WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
|
||||
|
||||
static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
||||
HRESULT hr = S_OK;
|
||||
if (!WSTRCMP(filename, "-")) {
|
||||
if (!strcmp(filename, "-")) {
|
||||
const uint8_t* data = NULL;
|
||||
size_t data_size = 0;
|
||||
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||
@@ -110,12 +108,11 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
||||
hr = E_FAIL;
|
||||
}
|
||||
} else {
|
||||
IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream));
|
||||
IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
_ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"),
|
||||
(const LPTSTR)filename, hr);
|
||||
fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
@@ -134,10 +131,7 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
|
||||
IWICColorContext** color_contexts;
|
||||
|
||||
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
|
||||
if (FAILED(hr) || count == 0) {
|
||||
// Treat unsupported operation as a non-fatal error. See crbug.com/webp/506.
|
||||
return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr;
|
||||
}
|
||||
if (FAILED(hr) || count == 0) return hr;
|
||||
|
||||
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
|
||||
if (color_contexts == NULL) return E_OUTOFMEMORY;
|
||||
@@ -273,15 +267,10 @@ int ReadPictureWithWIC(const char* const filename,
|
||||
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
|
||||
const WICFormatImporter* importer = NULL;
|
||||
GUID src_container_format = GUID_NULL_;
|
||||
// From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h
|
||||
WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_,
|
||||
0xe094b0e2, 0x67f2, 0x45b3,
|
||||
0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3);
|
||||
static const GUID* kAlphaContainers[] = {
|
||||
&GUID_ContainerFormatBmp,
|
||||
&GUID_ContainerFormatPng,
|
||||
&GUID_ContainerFormatTiff,
|
||||
&GUID_ContainerFormatWebp_,
|
||||
NULL
|
||||
};
|
||||
int has_alpha = 0;
|
||||
@@ -306,15 +295,9 @@ int ReadPictureWithWIC(const char* const filename,
|
||||
factory, stream, NULL,
|
||||
WICDecodeMetadataCacheOnDemand, &decoder));
|
||||
IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (frame_count == 0) {
|
||||
fprintf(stderr, "No frame found in input file.\n");
|
||||
hr = E_FAIL;
|
||||
} else if (frame_count > 1) {
|
||||
// WIC will be tried before native WebP decoding so avoid duplicating the
|
||||
// error message.
|
||||
hr = E_FAIL;
|
||||
}
|
||||
if (SUCCEEDED(hr) && frame_count == 0) {
|
||||
fprintf(stderr, "No frame found in input file.\n");
|
||||
hr = E_FAIL;
|
||||
}
|
||||
IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
|
||||
IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
|
||||
|
||||
106
infra/common.sh
106
infra/common.sh
@@ -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}" ]]
|
||||
}
|
||||
401
infra/compile.sh
401
infra/compile.sh
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
87
iosbuild.sh
87
iosbuild.sh
@@ -1,21 +1,17 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script generates 'WebP.framework' and 'WebPDecoder.framework',
|
||||
# 'WebPDemux.framework' and 'WebPMux.framework'.
|
||||
# An iOS app can decode WebP images by including 'WebPDecoder.framework' and
|
||||
# both encode and decode WebP images by including 'WebP.framework'.
|
||||
# This script generates 'WebP.framework' and 'WebPDecoder.framework'. An iOS
|
||||
# app can decode WebP images by including 'WebPDecoder.framework' and both
|
||||
# encode and decode WebP images by including 'WebP.framework'.
|
||||
#
|
||||
# Run ./iosbuild.sh to generate the frameworks under the current directory
|
||||
# (the previous build will be erased if it exists).
|
||||
#
|
||||
# This script is inspired by the build script written by Carson McDonald.
|
||||
# (https://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
|
||||
# (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
|
||||
|
||||
set -e
|
||||
|
||||
# Set this variable based on the desired minimum deployment target.
|
||||
readonly IOS_MIN_VERSION=6.0
|
||||
|
||||
# Extract the latest SDK version from the final field of the form: iphoneosX.Y
|
||||
readonly SDK=$(xcodebuild -showsdks \
|
||||
| grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
|
||||
@@ -39,59 +35,35 @@ readonly TOPDIR=$(pwd)
|
||||
readonly BUILDDIR="${TOPDIR}/iosbuild"
|
||||
readonly TARGETDIR="${TOPDIR}/WebP.framework"
|
||||
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
|
||||
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
|
||||
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
|
||||
readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.framework"
|
||||
readonly DEVELOPER=$(xcode-select --print-path)
|
||||
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
|
||||
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
|
||||
LIBLIST=''
|
||||
DECLIBLIST=''
|
||||
MUXLIBLIST=''
|
||||
DEMUXLIBLIST=''
|
||||
|
||||
if [[ -z "${SDK}" ]]; then
|
||||
echo "iOS SDK not available"
|
||||
exit 1
|
||||
elif [[ ${SDK%%.*} -gt 8 && "${XCODE%%.*}" -lt 16 ]]; then
|
||||
elif [[ ${SDK%%.*} -gt 8 ]]; then
|
||||
EXTRA_CFLAGS="-fembed-bitcode"
|
||||
elif [[ ${SDK%%.*} -le 6 ]]; then
|
||||
elif [[ ${SDK} < 6.0 ]]; then
|
||||
echo "You need iOS SDK version 6.0 or above"
|
||||
exit 1
|
||||
else
|
||||
echo "iOS SDK Version ${SDK}"
|
||||
fi
|
||||
|
||||
echo "Xcode Version: ${XCODE}"
|
||||
echo "iOS SDK Version: ${SDK}"
|
||||
|
||||
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/
|
||||
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR}
|
||||
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/
|
||||
|
||||
if [[ ! -e ${SRCDIR}/configure ]]; then
|
||||
if ! (cd ${SRCDIR} && sh autogen.sh); then
|
||||
cat << EOF
|
||||
cat <<EOT
|
||||
Error creating configure script!
|
||||
This script requires the autoconf/automake and libtool to build. MacPorts can
|
||||
be used to obtain these:
|
||||
https://www.macports.org/install.php
|
||||
EOF
|
||||
http://www.macports.org/install.php
|
||||
EOT
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -125,7 +97,7 @@ for PLATFORM in ${PLATFORMS}; do
|
||||
SDKROOT="${PLATFORMSROOT}/"
|
||||
SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
|
||||
CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
|
||||
CFLAGS+=" -miphoneos-version-min=${IOS_MIN_VERSION} ${EXTRA_CFLAGS}"
|
||||
CFLAGS+=" -miphoneos-version-min=6.0 ${EXTRA_CFLAGS}"
|
||||
|
||||
set -x
|
||||
export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
|
||||
@@ -133,46 +105,25 @@ for PLATFORM in ${PLATFORMS}; do
|
||||
--build=$(${SRCDIR}/config.guess) \
|
||||
--disable-shared --enable-static \
|
||||
--enable-libwebpdecoder --enable-swap-16bit-csp \
|
||||
--enable-libwebpmux \
|
||||
CFLAGS="${CFLAGS}"
|
||||
set +x
|
||||
|
||||
# Build only the libraries, skip the examples.
|
||||
make V=0 -C sharpyuv install
|
||||
make V=0 -C src install
|
||||
# run make only in the src/ directory to create libwebp.a/libwebpdecoder.a
|
||||
cd src/
|
||||
make V=0
|
||||
make install
|
||||
|
||||
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
|
||||
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
|
||||
MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
|
||||
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
|
||||
SHARPYUVLIBLIST+=" ${ROOTDIR}/lib/libsharpyuv.a"
|
||||
|
||||
make clean
|
||||
cd ..
|
||||
|
||||
export PATH=${OLDPATH}
|
||||
done
|
||||
|
||||
echo "LIBLIST = ${LIBLIST}"
|
||||
cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/
|
||||
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
|
||||
|
||||
echo "DECLIBLIST = ${DECLIBLIST}"
|
||||
cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/
|
||||
${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder
|
||||
|
||||
echo "MUXLIBLIST = ${MUXLIBLIST}"
|
||||
cp -a ${SRCDIR}/src/webp/{types,mux,mux_types}.h \
|
||||
${MUXTARGETDIR}/Headers/
|
||||
${LIPO} -create ${MUXLIBLIST} -output ${MUXTARGETDIR}/WebPMux
|
||||
|
||||
echo "DEMUXLIBLIST = ${DEMUXLIBLIST}"
|
||||
cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
|
||||
${DEMUXTARGETDIR}/Headers/
|
||||
${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux
|
||||
|
||||
echo "SHARPYUVLIBLIST = ${SHARPYUVLIBLIST}"
|
||||
cp -a ${SRCDIR}/sharpyuv/{sharpyuv,sharpyuv_csp}.h \
|
||||
${SHARPYUVTARGETDIR}/Headers/
|
||||
${LIPO} -create ${SHARPYUVLIBLIST} -output ${SHARPYUVTARGETDIR}/SharpYuv
|
||||
|
||||
echo "SUCCESS"
|
||||
|
||||
136
makefile.unix
136
makefile.unix
@@ -3,8 +3,7 @@
|
||||
# It will not install the libraries system-wide, but just create the 'cwebp'
|
||||
# and 'dwebp' tools in the examples/ directory, along with the static
|
||||
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
|
||||
# 'src/demux/libwebpdemux.a', 'extras/libwebpextras.a' and
|
||||
# 'sharpyuv/libsharpyuv.a'.
|
||||
# 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'.
|
||||
#
|
||||
# To build the library and examples, use:
|
||||
# make -f makefile.unix
|
||||
@@ -26,7 +25,6 @@ ifeq ($(strip $(shell uname)), Darwin)
|
||||
# Failure observed with: gcc 4.2.1 and 4.0.1.
|
||||
EXTRA_FLAGS += -fno-common
|
||||
EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H
|
||||
EXTRA_FLAGS += -Wno-deprecated-declarations
|
||||
EXTRA_FLAGS += -I/opt/local/include
|
||||
EXTRA_LIBS += -L/opt/local/lib
|
||||
GL_LIBS = -framework GLUT -framework OpenGL
|
||||
@@ -36,19 +34,9 @@ else
|
||||
GL_LIBS = -lglut -lGL
|
||||
endif
|
||||
|
||||
# SDL flags: use sdl-config if it exists
|
||||
SDL_CONFIG = $(shell sdl2-config --version 2> /dev/null)
|
||||
ifneq ($(SDL_CONFIG),)
|
||||
SDL_LIBS = $(shell sdl2-config --libs)
|
||||
SDL_FLAGS = $(shell sdl2-config --cflags)
|
||||
else
|
||||
# use best-guess
|
||||
SDL_LIBS = -lSDL2
|
||||
SDL_FLAGS =
|
||||
endif
|
||||
|
||||
# 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"
|
||||
# 3. Run "sudo port install libpng"
|
||||
# 4. Run "sudo port install tiff"
|
||||
@@ -65,8 +53,11 @@ endif
|
||||
# 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect.
|
||||
# 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 += -DWEBP_SWAP_16BIT_CSP=1
|
||||
# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP
|
||||
|
||||
# Extra flags to enable multi-threading
|
||||
EXTRA_FLAGS += -DWEBP_USE_THREAD
|
||||
@@ -90,6 +81,12 @@ EXTRA_FLAGS += -DWEBP_HAVE_SSE41
|
||||
src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1
|
||||
endif
|
||||
|
||||
# AVX2-specific flags:
|
||||
ifeq ($(HAVE_AVX2), 1)
|
||||
EXTRA_FLAGS += -DWEBP_HAVE_AVX2
|
||||
src/dsp/%_avx2.o: EXTRA_FLAGS += -mavx2
|
||||
endif
|
||||
|
||||
# NEON-specific flags:
|
||||
# EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8
|
||||
# -> seems to make the overall lib slower: -fno-split-wide-types
|
||||
@@ -106,35 +103,17 @@ endif
|
||||
|
||||
AR = ar
|
||||
ARFLAGS = r
|
||||
CPPFLAGS = -I. -Isrc/ -Wall
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS = -g
|
||||
else
|
||||
CFLAGS = -O3 -DNDEBUG
|
||||
endif
|
||||
CFLAGS += $(EXTRA_FLAGS)
|
||||
CPPFLAGS = -Isrc/ -Wall
|
||||
CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
|
||||
CC = gcc
|
||||
INSTALL = install
|
||||
GROFF = /usr/bin/groff
|
||||
COL = /usr/bin/col
|
||||
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
|
||||
|
||||
ifdef BITTRACE
|
||||
CFLAGS += -DBITTRACE=$(BITTRACE)
|
||||
endif
|
||||
|
||||
ANIM_UTIL_OBJS = \
|
||||
examples/anim_util.o \
|
||||
|
||||
SHARPYUV_OBJS = \
|
||||
sharpyuv/sharpyuv.o \
|
||||
sharpyuv/sharpyuv_cpu.o \
|
||||
sharpyuv/sharpyuv_csp.o \
|
||||
sharpyuv/sharpyuv_dsp.o \
|
||||
sharpyuv/sharpyuv_gamma.o \
|
||||
sharpyuv/sharpyuv_neon.o \
|
||||
sharpyuv/sharpyuv_sse2.o \
|
||||
|
||||
DEC_OBJS = \
|
||||
src/dec/alpha_dec.o \
|
||||
src/dec/buffer_dec.o \
|
||||
@@ -176,7 +155,6 @@ DSP_DEC_OBJS = \
|
||||
src/dsp/lossless_msa.o \
|
||||
src/dsp/lossless_neon.o \
|
||||
src/dsp/lossless_sse2.o \
|
||||
src/dsp/lossless_sse41.o \
|
||||
src/dsp/rescaler.o \
|
||||
src/dsp/rescaler_mips32.o \
|
||||
src/dsp/rescaler_mips_dsp_r2.o \
|
||||
@@ -188,21 +166,22 @@ DSP_DEC_OBJS = \
|
||||
src/dsp/upsampling_msa.o \
|
||||
src/dsp/upsampling_neon.o \
|
||||
src/dsp/upsampling_sse2.o \
|
||||
src/dsp/upsampling_sse41.o \
|
||||
src/dsp/yuv.o \
|
||||
src/dsp/yuv_mips32.o \
|
||||
src/dsp/yuv_mips_dsp_r2.o \
|
||||
src/dsp/yuv_neon.o \
|
||||
src/dsp/yuv_sse2.o \
|
||||
src/dsp/yuv_sse41.o \
|
||||
|
||||
DSP_ENC_OBJS = \
|
||||
src/dsp/argb.o \
|
||||
src/dsp/argb_mips_dsp_r2.o \
|
||||
src/dsp/argb_sse2.o \
|
||||
src/dsp/cost.o \
|
||||
src/dsp/cost_mips32.o \
|
||||
src/dsp/cost_mips_dsp_r2.o \
|
||||
src/dsp/cost_neon.o \
|
||||
src/dsp/cost_sse2.o \
|
||||
src/dsp/enc.o \
|
||||
src/dsp/enc_avx2.o \
|
||||
src/dsp/enc_mips32.o \
|
||||
src/dsp/enc_mips_dsp_r2.o \
|
||||
src/dsp/enc_msa.o \
|
||||
@@ -226,6 +205,7 @@ ENC_OBJS = \
|
||||
src/enc/backward_references_enc.o \
|
||||
src/enc/config_enc.o \
|
||||
src/enc/cost_enc.o \
|
||||
src/enc/delta_palettization_enc.o \
|
||||
src/enc/filter_enc.o \
|
||||
src/enc/frame_enc.o \
|
||||
src/enc/histogram_enc.o \
|
||||
@@ -276,7 +256,6 @@ UTILS_DEC_OBJS = \
|
||||
src/utils/color_cache_utils.o \
|
||||
src/utils/filters_utils.o \
|
||||
src/utils/huffman_utils.o \
|
||||
src/utils/palette.o \
|
||||
src/utils/quant_levels_dec_utils.o \
|
||||
src/utils/random_utils.o \
|
||||
src/utils/rescaler_utils.o \
|
||||
@@ -291,15 +270,13 @@ UTILS_ENC_OBJS = \
|
||||
EXTRA_OBJS = \
|
||||
extras/extras.o \
|
||||
extras/quality_estimate.o \
|
||||
extras/sharpyuv_risk_table.o \
|
||||
|
||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
|
||||
$(DSP_ENC_OBJS) $(UTILS_ENC_OBJS)
|
||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
|
||||
$(UTILS_ENC_OBJS)
|
||||
LIBWEBPMUX_OBJS = $(MUX_OBJS)
|
||||
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
|
||||
LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
|
||||
LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS)
|
||||
|
||||
HDRS_INSTALLED = \
|
||||
src/webp/decode.h \
|
||||
@@ -309,11 +286,6 @@ HDRS_INSTALLED = \
|
||||
src/webp/mux_types.h \
|
||||
src/webp/types.h \
|
||||
|
||||
SHARPYUV_HDRS_INSTALLED = \
|
||||
sharpyuv/sharpyuv.h \
|
||||
sharpyuv/sharpyuv_cpu.h \
|
||||
sharpyuv/sharpyuv_csp.h \
|
||||
|
||||
HDRS = \
|
||||
src/dec/alphai_dec.h \
|
||||
src/dec/common_dec.h \
|
||||
@@ -322,7 +294,6 @@ HDRS = \
|
||||
src/dec/vp8li_dec.h \
|
||||
src/dec/webpi_dec.h \
|
||||
src/dsp/common_sse2.h \
|
||||
src/dsp/cpu.h \
|
||||
src/dsp/dsp.h \
|
||||
src/dsp/lossless.h \
|
||||
src/dsp/lossless_common.h \
|
||||
@@ -332,6 +303,7 @@ HDRS = \
|
||||
src/dsp/yuv.h \
|
||||
src/enc/backward_references_enc.h \
|
||||
src/enc/cost_enc.h \
|
||||
src/enc/delta_palettization_enc.h \
|
||||
src/enc/histogram_enc.h \
|
||||
src/enc/vp8i_enc.h \
|
||||
src/enc/vp8li_enc.h \
|
||||
@@ -345,7 +317,6 @@ HDRS = \
|
||||
src/utils/filters_utils.h \
|
||||
src/utils/huffman_utils.h \
|
||||
src/utils/huffman_encode_utils.h \
|
||||
src/utils/palette.h \
|
||||
src/utils/quant_levels_utils.h \
|
||||
src/utils/quant_levels_dec_utils.h \
|
||||
src/utils/random_utils.h \
|
||||
@@ -354,7 +325,6 @@ HDRS = \
|
||||
src/utils/utils.h \
|
||||
src/webp/format_constants.h \
|
||||
$(HDRS_INSTALLED) \
|
||||
$(SHARPYUV_HDRS_INSTALLED) \
|
||||
|
||||
OUT_LIBS = examples/libexample_util.a
|
||||
OUT_LIBS += imageio/libimageio_util.a
|
||||
@@ -362,12 +332,10 @@ OUT_LIBS += imageio/libimagedec.a
|
||||
OUT_LIBS += imageio/libimageenc.a
|
||||
OUT_LIBS += src/libwebpdecoder.a
|
||||
OUT_LIBS += src/libwebp.a
|
||||
OUT_LIBS += sharpyuv/libsharpyuv.a
|
||||
EXTRA_LIB = extras/libwebpextras.a
|
||||
OUT_EXAMPLES = examples/cwebp examples/dwebp
|
||||
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
|
||||
examples/anim_diff examples/anim_dump \
|
||||
examples/img2webp examples/webpinfo
|
||||
examples/anim_diff examples/img2webp examples/webpinfo
|
||||
OTHER_EXAMPLES = extras/get_disto extras/webp_quality extras/vwebp_sdl
|
||||
|
||||
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
|
||||
@@ -395,7 +363,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
|
||||
|
||||
%.o: %.c $(HDRS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
examples/libanim_util.a: $(ANIM_UTIL_OBJS)
|
||||
examples/libexample_util.a: $(EX_UTIL_OBJS)
|
||||
@@ -408,13 +376,11 @@ src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
|
||||
src/libwebp.a: $(LIBWEBP_OBJS)
|
||||
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
|
||||
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
|
||||
sharpyuv/libsharpyuv.a: $(LIBSHARPYUV_OBJS)
|
||||
|
||||
%.a:
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
|
||||
examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
|
||||
examples/cwebp: examples/cwebp.o
|
||||
examples/dwebp: examples/dwebp.o
|
||||
examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
|
||||
@@ -426,74 +392,50 @@ examples/webpinfo: examples/webpinfo.o
|
||||
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
|
||||
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
|
||||
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
|
||||
examples/anim_diff: sharpyuv/libsharpyuv.a
|
||||
examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS)
|
||||
examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS)
|
||||
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
||||
examples/anim_dump: examples/libanim_util.a examples/libgifdec.a
|
||||
examples/anim_dump: src/demux/libwebpdemux.a
|
||||
examples/anim_dump: examples/libexample_util.a
|
||||
examples/anim_dump: imageio/libimageio_util.a
|
||||
examples/anim_dump: imageio/libimageenc.a
|
||||
examples/anim_dump: src/libwebp.a
|
||||
examples/anim_dump: sharpyuv/libsharpyuv.a
|
||||
examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
|
||||
examples/cwebp: examples/libexample_util.a
|
||||
examples/cwebp: imageio/libimagedec.a
|
||||
examples/cwebp: src/demux/libwebpdemux.a
|
||||
examples/cwebp: imageio/libimageio_util.a
|
||||
examples/cwebp: src/libwebp.a
|
||||
examples/cwebp: sharpyuv/libsharpyuv.a
|
||||
examples/cwebp: override EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
examples/dwebp: examples/libexample_util.a
|
||||
examples/dwebp: imageio/libimagedec.a
|
||||
examples/dwebp: src/demux/libwebpdemux.a
|
||||
examples/dwebp: imageio/libimageenc.a
|
||||
examples/dwebp: imageio/libimageio_util.a
|
||||
examples/dwebp: src/libwebp.a
|
||||
examples/dwebp: sharpyuv/libsharpyuv.a
|
||||
examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS)
|
||||
examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
|
||||
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
|
||||
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
|
||||
examples/gif2webp: sharpyuv/libsharpyuv.a
|
||||
examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS)
|
||||
examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
|
||||
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
|
||||
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
|
||||
examples/vwebp: imageio/libimageio_util.a src/libwebp.a
|
||||
examples/vwebp: sharpyuv/libsharpyuv.a
|
||||
examples/vwebp: override EXTRA_LIBS += $(GL_LIBS)
|
||||
examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
|
||||
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
|
||||
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a
|
||||
examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
|
||||
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
|
||||
examples/img2webp: imageio/libimagedec.a
|
||||
examples/img2webp: src/demux/libwebpdemux.a
|
||||
examples/img2webp: src/mux/libwebpmux.a
|
||||
examples/img2webp: src/libwebp.a
|
||||
examples/img2webp: sharpyuv/libsharpyuv.a
|
||||
examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
|
||||
examples/img2webp: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
|
||||
examples/webpinfo: src/libwebpdecoder.a
|
||||
|
||||
extras/get_disto: extras/get_disto.o
|
||||
extras/get_disto: imageio/libimagedec.a
|
||||
extras/get_disto: src/demux/libwebpdemux.a
|
||||
extras/get_disto: imageio/libimageio_util.a
|
||||
extras/get_disto: src/libwebp.a
|
||||
extras/get_disto: sharpyuv/libsharpyuv.a
|
||||
extras/get_disto: override EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
extras/get_disto: imageio/libimagedec.a imageio/libimageio_util.a src/libwebp.a
|
||||
extras/get_disto: EXTRA_LIBS += $(CWEBP_LIBS)
|
||||
|
||||
extras/webp_quality: extras/webp_quality.o
|
||||
extras/webp_quality: imageio/libimageio_util.a
|
||||
extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
|
||||
extras/webp_quality: sharpyuv/libsharpyuv.a
|
||||
|
||||
extras/vwebp_sdl: extras/vwebp_sdl.o
|
||||
extras/vwebp_sdl: extras/webp_to_sdl.o
|
||||
extras/vwebp_sdl: imageio/libimageio_util.a
|
||||
extras/vwebp_sdl: src/libwebp.a
|
||||
extras/vwebp_sdl: sharpyuv/libsharpyuv.a
|
||||
extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS)
|
||||
extras/vwebp_sdl: override EXTRA_LIBS += $(SDL_LIBS)
|
||||
extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL
|
||||
extras/vwebp_sdl: EXTRA_LIBS += -lSDL
|
||||
|
||||
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
@@ -502,20 +444,17 @@ dist: DESTDIR := dist
|
||||
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
|
||||
dist: all
|
||||
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \
|
||||
$(DESTDIR)/include/webp/sharpyuv \
|
||||
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
|
||||
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib
|
||||
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin
|
||||
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
|
||||
$(INSTALL) -m644 $(SHARPYUV_HDRS_INSTALLED) $(DESTDIR)/include/webp/sharpyuv
|
||||
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
|
||||
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
|
||||
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
|
||||
$(INSTALL) -m644 sharpyuv/libsharpyuv.a $(DESTDIR)/lib
|
||||
umask 022; \
|
||||
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \
|
||||
man/img2webp.1 man/webpinfo.1; do \
|
||||
basenam=$$(basename $$m .1); \
|
||||
$(GROFF) -t -e -man -T ascii $$m \
|
||||
$(GROFF) -t -e -man -T utf8 $$m \
|
||||
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
|
||||
$(GROFF) -t -e -man -T html $$m \
|
||||
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \
|
||||
@@ -526,7 +465,6 @@ clean:
|
||||
examples/*.o examples/*~ \
|
||||
extras/*.o extras/*~ \
|
||||
imageio/*.o imageio/*~ \
|
||||
sharpyuv/*.o sharpyuv/*~ \
|
||||
src/dec/*.o src/dec/*~ \
|
||||
src/demux/*.o src/demux/*~ \
|
||||
src/dsp/*.o src/dsp/*~ \
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
man_MANS = cwebp.1 dwebp.1
|
||||
if BUILD_MUX
|
||||
if WANT_MUX
|
||||
man_MANS += webpmux.1
|
||||
endif
|
||||
if BUILD_GIF2WEBP
|
||||
man_MANS += gif2webp.1
|
||||
endif
|
||||
if BUILD_IMG2WEBP
|
||||
man_MANS += img2webp.1
|
||||
endif
|
||||
if BUILD_VWEBP
|
||||
man_MANS += vwebp.1
|
||||
endif
|
||||
|
||||
77
man/cwebp.1
77
man/cwebp.1
@@ -1,5 +1,5 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.TH CWEBP 1 "April 10, 2025"
|
||||
.TH CWEBP 1 "January 20, 2017"
|
||||
.SH NAME
|
||||
cwebp \- compress an image file to a WebP file
|
||||
.SH SYNOPSIS
|
||||
@@ -13,7 +13,6 @@ command.
|
||||
.PP
|
||||
\fBcwebp\fP compresses an image using the WebP format.
|
||||
Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples.
|
||||
Note: Animated PNG and WebP files are not supported.
|
||||
.SH OPTIONS
|
||||
The basic options are:
|
||||
.TP
|
||||
@@ -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.
|
||||
.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.
|
||||
Use 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.
|
||||
Range is 0 (maximum preprocessing) to 100 (no preprocessing, the default).
|
||||
.TP
|
||||
.BI \-q " float
|
||||
Specify the compression factor for RGB channels between 0 and 100. The default
|
||||
@@ -90,25 +87,15 @@ additional encoding possibilities and decide on the quality gain.
|
||||
Lower value can result in faster processing time at the expense of
|
||||
larger file size and lower compression quality.
|
||||
.TP
|
||||
.BI \-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
|
||||
Crop the source to a rectangle with top\-left corner at coordinates
|
||||
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
|
||||
This cropping area must be fully contained within the source rectangle.
|
||||
Note: the cropping is applied \fIbefore\fP any scaling.
|
||||
.TP
|
||||
.BI \-resize " width height
|
||||
Resize the source to a rectangle with size \fBwidth\fP x \fBheight\fP.
|
||||
If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
|
||||
the value will be calculated preserving the aspect\-ratio. Note: scaling
|
||||
is applied \fIafter\fP cropping.
|
||||
.TP
|
||||
.BI \-resize_mode " string
|
||||
Specify the behavior of the \fB\-resize\fP option. Possible values are:
|
||||
\fBdown_only\fP, \fBup_only\fP, \fBalways\fP (default). \fBdown_only\fP will
|
||||
use the values specified by \fB\-resize\fP if \fIeither\fP the input width or
|
||||
height are larger than the given dimensions. Similarly, \fBup_only\fP will only
|
||||
resize if \fIeither\fP the input width or height are smaller than the given
|
||||
dimensions.
|
||||
.TP
|
||||
.B \-mt
|
||||
Use multi\-threading for encoding, if possible.
|
||||
@@ -143,16 +130,7 @@ are used, \fB\-size\fP value will prevail.
|
||||
Set a maximum number of passes to use during the dichotomy used by
|
||||
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
|
||||
If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
|
||||
specified, a default value of '6' passes will be used. If \fB\-pass\fP is
|
||||
specified, but neither \fB-size\fP nor \fB-psnr\fP are, a target PSNR of 40dB
|
||||
will be used.
|
||||
.TP
|
||||
.BI \-qrange " int int
|
||||
Specifies the permissible interval for the quality factor. This is particularly
|
||||
useful when using multi-pass (\fB\-size\fP or \fB\-psnr\fP options).
|
||||
Default is 0 100.
|
||||
If the quality factor is outside this range, it will be clamped.
|
||||
If the minimum value must be less or equal to the maximum one.
|
||||
specified, a default value of '6' passes will be used.
|
||||
.TP
|
||||
.B \-af
|
||||
Turns auto\-filter on. This algorithm will spend additional time optimizing
|
||||
@@ -188,8 +166,8 @@ Disable strong filtering (if filtering is being used thanks to the
|
||||
\fB\-f\fP option) and use simple filtering instead.
|
||||
.TP
|
||||
.B \-sharp_yuv
|
||||
Use more accurate and sharper RGB->YUV conversion. Note that this process is
|
||||
slower than the default 'fast' RGB->YUV conversion.
|
||||
Use more accurate and sharper RGB->YUV conversion if needed. Note that this
|
||||
process is slower than the default 'fast' RGB->YUV conversion.
|
||||
.TP
|
||||
.BI \-sns " int
|
||||
Specify the amplitude of the spatial noise shaping. Spatial noise shaping
|
||||
@@ -212,8 +190,7 @@ In the VP8 format, the so\-called control partition has a limit of 512k and
|
||||
is used to store the following information: whether the macroblock is skipped,
|
||||
which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
|
||||
mode, and finally the prediction modes to use for each of the sub\-blocks.
|
||||
For a very large image, 512k only leaves room for a few bits per 16x16
|
||||
macroblock.
|
||||
For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
|
||||
The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
|
||||
information can use up almost all these 4 bits (although the case is unlikely),
|
||||
which is problematic for very large images. The partition_limit factor controls
|
||||
@@ -222,8 +199,7 @@ useful in case the 512k limit is reached and the following message is displayed:
|
||||
\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
|
||||
If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one
|
||||
should use less segments in order to save more header bits per macroblock.
|
||||
See the \fB\-segments\fP option. Note the \fB-m\fP and \fB-q\fP options also
|
||||
influence the encoder's decisions and ability to hit this limit.
|
||||
See the \fB\-segments\fP option.
|
||||
|
||||
.SS LOGGING OPTIONS
|
||||
These options control the level of output:
|
||||
@@ -236,7 +212,7 @@ Compute and report average PSNR (Peak\-Signal\-To\-Noise ratio).
|
||||
.TP
|
||||
.B \-print_ssim
|
||||
Compute and report average SSIM (structural similarity
|
||||
metric, see https://en.wikipedia.org/wiki/SSIM for additional details).
|
||||
metric, see http://en.wikipedia.org/wiki/SSIM for additional details).
|
||||
.TP
|
||||
.B \-print_lsim
|
||||
Compute and report local similarity metric (sum of lowest error amongst the
|
||||
@@ -307,12 +283,12 @@ Note: each input format may not support all combinations.
|
||||
.B \-noasm
|
||||
Disable all assembly optimizations.
|
||||
|
||||
.SH EXIT STATUS
|
||||
If there were no problems during execution, \fBcwebp\fP exits with the value of
|
||||
the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
|
||||
.PP
|
||||
If an error occurs, \fBcwebp\fP exits with the value of the C constant
|
||||
\fBEXIT_FAILURE\fP. This is usually one.
|
||||
.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:
|
||||
http://www.webmproject.org/code/contribute/submitting\-patches/
|
||||
|
||||
.SH EXAMPLES
|
||||
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
|
||||
@@ -332,16 +308,9 @@ https://chromium.googlesource.com/webm/libwebp
|
||||
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
|
||||
for the Debian project (and may be used by others).
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Please report all bugs to the issue tracker:
|
||||
https://issues.webmproject.org
|
||||
.br
|
||||
Patches welcome! See this page to get started:
|
||||
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR dwebp (1),
|
||||
.BR gif2webp (1)
|
||||
.br
|
||||
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
||||
information.
|
||||
|
||||
24
man/dwebp.1
24
man/dwebp.1
@@ -1,5 +1,5 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.TH DWEBP 1 "July 18, 2024"
|
||||
.TH DWEBP 1 "June 23, 2016"
|
||||
.SH NAME
|
||||
dwebp \- decompress a WebP file to an image file
|
||||
.SH SYNOPSIS
|
||||
@@ -12,7 +12,6 @@ This manual page documents the
|
||||
command.
|
||||
.PP
|
||||
\fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images.
|
||||
Note: Animated WebP files are not supported.
|
||||
.SH OPTIONS
|
||||
The basic options are:
|
||||
.TP
|
||||
@@ -108,12 +107,12 @@ Print extra information (decoding time in particular).
|
||||
.B \-noasm
|
||||
Disable all assembly optimizations.
|
||||
|
||||
.SH EXIT STATUS
|
||||
If there were no problems during execution, \fBdwebp\fP exits with the value of
|
||||
the C constant \fBEXIT_SUCCESS\fP. This is usually zero.
|
||||
.PP
|
||||
If an error occurs, \fBdwebp\fP exits with the value of the C constant
|
||||
\fBEXIT_FAILURE\fP. This is usually one.
|
||||
.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:
|
||||
http://www.webmproject.org/code/contribute/submitting-patches/
|
||||
|
||||
.SH EXAMPLES
|
||||
dwebp picture.webp \-o output.png
|
||||
@@ -133,19 +132,12 @@ https://chromium.googlesource.com/webm/libwebp
|
||||
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
|
||||
for the Debian project (and may be used by others).
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Please report all bugs to the issue tracker:
|
||||
https://issues.webmproject.org
|
||||
.br
|
||||
Patches welcome! See this page to get started:
|
||||
https://www.webmproject.org/code/contribute/submitting\-patches/
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR cwebp (1),
|
||||
.BR gif2webp (1),
|
||||
.BR webpmux (1)
|
||||
.br
|
||||
Please refer to https://developers.google.com/speed/webp/ for additional
|
||||
Please refer to http://developers.google.com/speed/webp/ for additional
|
||||
information.
|
||||
.SS Output file format details
|
||||
PAM: http://netpbm.sourceforge.net/doc/pam.html
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user