mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-18 23:09:52 +02:00
Compare commits
40 Commits
v1.0.1-rc2
...
1.0.2
Author | SHA1 | Date | |
---|---|---|---|
7b75522d5e | |||
3180b6f4b7 | |||
16f36e4e39 | |||
df9e129b0d | |||
28b53efd6f | |||
81efa2a3f1 | |||
d8481223b3 | |||
4fdc903597 | |||
fa58371c6a | |||
84fdd0d12e | |||
2b98df90cb | |||
61e372b7e3 | |||
7ae658a026 | |||
51c4907d32 | |||
666bd6c654 | |||
561cdce5bd | |||
aec2cf02d1 | |||
928a75deca | |||
5173d4ee6f | |||
5b081219c9 | |||
381b7b54a0 | |||
6ed15ea1cd | |||
22bbb24ea8 | |||
8b3fb2389b | |||
f435de9575 | |||
41521aed47 | |||
9f4d4a3f49 | |||
0fd7514b55 | |||
f95a996c64 | |||
fd198f7370 | |||
485ff86fbb | |||
4cd0582d50 | |||
6752904b2f | |||
b6284d8247 | |||
decf6f6b87 | |||
dea3e89983 | |||
632798ae6f | |||
dc1a9518bc | |||
9cf9841b5e | |||
a376e7b96a |
5
.mailmap
5
.mailmap
@ -1,7 +1,8 @@
|
|||||||
<johann.koenig@duck.com> <johannkoenig@google.com>
|
Johann Koenig <johann.koenig@duck.com>
|
||||||
|
Johann Koenig <johann.koenig@duck.com> <johannkoenig@google.com>
|
||||||
Mikołaj Zalewski <mikolajz@google.com>
|
Mikołaj Zalewski <mikolajz@google.com>
|
||||||
Pascal Massimino <pascal.massimino@gmail.com>
|
Pascal Massimino <pascal.massimino@gmail.com>
|
||||||
<pascal.massimino@gmail.com> <skal@google.com>
|
Pascal Massimino <pascal.massimino@gmail.com> <skal@google.com>
|
||||||
Vikas Arora <vikasa@google.com>
|
Vikas Arora <vikasa@google.com>
|
||||||
<vikasa@google.com> <vikasa@gmail.com>
|
<vikasa@google.com> <vikasa@gmail.com>
|
||||||
<vikasa@google.com> <vikaas.arora@gmail.com>
|
<vikasa@google.com> <vikaas.arora@gmail.com>
|
||||||
|
2
AUTHORS
2
AUTHORS
@ -7,7 +7,7 @@ Contributors:
|
|||||||
- James Zern (jzern at google dot com)
|
- James Zern (jzern at google dot com)
|
||||||
- Jan Engelhardt (jengelh at medozas dot de)
|
- Jan Engelhardt (jengelh at medozas dot de)
|
||||||
- Jehan (jehan at girinstud dot io)
|
- Jehan (jehan at girinstud dot io)
|
||||||
- Johann (johann dot koenig at duck dot com)
|
- Johann Koenig (johann dot koenig at duck dot com)
|
||||||
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
|
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
|
||||||
- Jyrki Alakuijala (jyrki at google dot com)
|
- Jyrki Alakuijala (jyrki at google dot com)
|
||||||
- Konstantin Ivlev (tomskside at gmail dot com)
|
- Konstantin Ivlev (tomskside at gmail dot com)
|
||||||
|
@ -97,6 +97,7 @@ dsp_enc_srcs := \
|
|||||||
src/dsp/cost.c \
|
src/dsp/cost.c \
|
||||||
src/dsp/cost_mips32.c \
|
src/dsp/cost_mips32.c \
|
||||||
src/dsp/cost_mips_dsp_r2.c \
|
src/dsp/cost_mips_dsp_r2.c \
|
||||||
|
src/dsp/cost_neon.$(NEON) \
|
||||||
src/dsp/cost_sse2.c \
|
src/dsp/cost_sse2.c \
|
||||||
src/dsp/enc.c \
|
src/dsp/enc.c \
|
||||||
src/dsp/enc_mips32.c \
|
src/dsp/enc_mips32.c \
|
||||||
|
@ -18,6 +18,11 @@ option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
|||||||
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
||||||
OFF)
|
OFF)
|
||||||
|
|
||||||
|
# Option needed for handling Unicode file names on Windows.
|
||||||
|
if(WIN32)
|
||||||
|
option(WEBP_UNICODE "Build Unicode executables." ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WEBP_BUILD_WEBP_JS)
|
if(WEBP_BUILD_WEBP_JS)
|
||||||
set(WEBP_ENABLE_SIMD OFF)
|
set(WEBP_ENABLE_SIMD OFF)
|
||||||
set(WEBP_BUILD_ANIM_UTILS OFF)
|
set(WEBP_BUILD_ANIM_UTILS OFF)
|
||||||
@ -50,6 +55,11 @@ if(WEBP_ENABLE_SWAP_16BIT_CSP)
|
|||||||
add_definitions(-DWEBP_SWAP_16BIT_CSP=1)
|
add_definitions(-DWEBP_SWAP_16BIT_CSP=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WEBP_UNICODE)
|
||||||
|
# Windows recommends setting both UNICODE and _UNICODE.
|
||||||
|
add_definitions(-DUNICODE -D_UNICODE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||||
set(exec_prefix "\$\{prefix\}")
|
set(exec_prefix "\$\{prefix\}")
|
||||||
set(libdir "\$\{prefix\}/lib")
|
set(libdir "\$\{prefix\}/lib")
|
||||||
@ -546,7 +556,7 @@ if(WEBP_BUILD_WEBP_JS)
|
|||||||
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
webp_wasm
|
webp_wasm
|
||||||
PROPERTIES LINK_FLAGS "-s WASM=1 -s 'BINARYEN_METHOD=\"native-wasm\"' \
|
PROPERTIES LINK_FLAGS "-s WASM=1 \
|
||||||
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
|
||||||
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||||
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||||
|
30
ChangeLog
30
ChangeLog
@ -1,15 +1,45 @@
|
|||||||
|
61e372b7 update NEWS
|
||||||
|
7ae658a0 bump version to 1.0.2
|
||||||
|
51c4907d update AUTHORS
|
||||||
|
666bd6c6 man/cwebp.1: refine near-lossless text
|
||||||
|
561cdce5 Clarify the doc about GetFeatures.
|
||||||
|
aec2cf02 near_lossless: fix fuzzing-detected integer overflow
|
||||||
|
928a75de webp: Fix VP8LBitWriterClone() bug
|
||||||
|
5173d4ee neon IsFlat
|
||||||
|
5b081219 IsFlat: inline when possible
|
||||||
|
381b7b54 IsFlat: use int for thresh
|
||||||
|
6ed15ea1 fix unprobable leak in webp_sdl.c
|
||||||
|
22bbb24e Merge "IsFlat: return int"
|
||||||
|
8b3fb238 Merge tag 'v1.0.1'
|
||||||
|
f435de95 IsFlat: return int
|
||||||
|
41521aed utils.h: only define WEBP_NEED_LOG_TABLE_8BIT when needed
|
||||||
|
9f4d4a3f neon: GetResidualCost
|
||||||
|
0fd7514b neon: SetResidualCoeffs
|
||||||
|
f95a996c Simpler histogram clustering.
|
||||||
|
e85d3313 update ChangeLog (tag: v1.0.1-rc2, tag: v1.0.1, origin/1.0.1, 1.0.1)
|
||||||
fa8210e4 Fix pair update in stochastic entropy merging.
|
fa8210e4 Fix pair update in stochastic entropy merging.
|
||||||
|
fd198f73 add codereview.settings
|
||||||
825389ac README.mux: add a reference to the AnimDecoder API
|
825389ac README.mux: add a reference to the AnimDecoder API
|
||||||
3be698c3 CMake: fix webp_js compilation
|
3be698c3 CMake: fix webp_js compilation
|
||||||
|
485ff86f Fix pair update in stochastic entropy merging.
|
||||||
|
4cd0582d CMake: fix webp_js compilation
|
||||||
4cbb4caf update NEWS
|
4cbb4caf update NEWS
|
||||||
f5a5918d bump version to 1.0.1
|
f5a5918d bump version to 1.0.1
|
||||||
d61385db Speed-up: Make sure we only initialize histograms when needed.
|
d61385db Speed-up: Make sure we only initialize histograms when needed.
|
||||||
|
6752904b Speed-up: Make sure we only initialize histograms when needed.
|
||||||
0c570316 update AUTHORS
|
0c570316 update AUTHORS
|
||||||
301a2dda img2webp: add help note about arguments from a file
|
301a2dda img2webp: add help note about arguments from a file
|
||||||
f0abab92 Speedups for empty histograms.
|
f0abab92 Speedups for empty histograms.
|
||||||
f2dfd925 Split HistogramAdd to only have the high level logic in C.
|
f2dfd925 Split HistogramAdd to only have the high level logic in C.
|
||||||
06b7bc7d Fix compilation on windows and clang-cl+ninja.
|
06b7bc7d Fix compilation on windows and clang-cl+ninja.
|
||||||
|
b6284d82 img2webp: add help note about arguments from a file
|
||||||
|
decf6f6b Speedups for empty histograms.
|
||||||
|
dea3e899 Split HistogramAdd to only have the high level logic in C.
|
||||||
|
632798ae Merge "Fix compilation on windows and clang-cl+ninja."
|
||||||
|
dc1a9518 Merge "libwebp: Unicode command tools on Windows"
|
||||||
|
9cf9841b libwebp: Unicode command tools on Windows
|
||||||
98179495 remove some minor TODOs
|
98179495 remove some minor TODOs
|
||||||
|
a376e7b9 Fix compilation on windows and clang-cl+ninja.
|
||||||
cbf82cc0 Remove AVX2 files.
|
cbf82cc0 Remove AVX2 files.
|
||||||
5030e902 Merge "TIFF decoder: remove unused KINV definition"
|
5030e902 Merge "TIFF decoder: remove unused KINV definition"
|
||||||
ac543311 Remove a few more useless #defines
|
ac543311 Remove a few more useless #defines
|
||||||
|
18
Makefile.vc
18
Makefile.vc
@ -129,12 +129,16 @@ LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
|
|||||||
CFGSET = TRUE
|
CFGSET = TRUE
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
|
!IF "$(UNICODE)" == "1"
|
||||||
|
CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
# Usage
|
# Usage
|
||||||
#
|
#
|
||||||
!IF "$(CFGSET)" == "FALSE"
|
!IF "$(CFGSET)" == "FALSE"
|
||||||
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
|
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
|
||||||
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
|
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [UNICODE=1] [<target>]
|
||||||
!MESSAGE
|
!MESSAGE
|
||||||
!MESSAGE where <config> is one of:
|
!MESSAGE where <config> is one of:
|
||||||
!MESSAGE - release-static - release static library
|
!MESSAGE - release-static - release static library
|
||||||
@ -234,6 +238,7 @@ DSP_ENC_OBJS = \
|
|||||||
$(DIROBJ)\dsp\cost.obj \
|
$(DIROBJ)\dsp\cost.obj \
|
||||||
$(DIROBJ)\dsp\cost_mips32.obj \
|
$(DIROBJ)\dsp\cost_mips32.obj \
|
||||||
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
|
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
|
||||||
|
$(DIROBJ)\dsp\cost_neon.obj \
|
||||||
$(DIROBJ)\dsp\cost_sse2.obj \
|
$(DIROBJ)\dsp\cost_sse2.obj \
|
||||||
$(DIROBJ)\dsp\enc.obj \
|
$(DIROBJ)\dsp\enc.obj \
|
||||||
$(DIROBJ)\dsp\enc_mips32.obj \
|
$(DIROBJ)\dsp\enc_mips32.obj \
|
||||||
@ -483,15 +488,18 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
|
|||||||
{src\utils}.c{$(DIROBJ)\utils}.obj::
|
{src\utils}.c{$(DIROBJ)\utils}.obj::
|
||||||
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
|
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
|
||||||
|
|
||||||
|
LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib
|
||||||
|
!IF "$(UNICODE)" == "1"
|
||||||
|
LNKLIBS = $(LNKLIBS) Shell32.lib
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
|
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
|
||||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
|
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
||||||
ole32.lib windowscodecs.lib shlwapi.lib
|
|
||||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
$(MT) -manifest $@.manifest -outputresource:$@;1
|
||||||
del $@.manifest
|
del $@.manifest
|
||||||
|
|
||||||
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
|
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
|
||||||
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
|
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
|
||||||
ole32.lib windowscodecs.lib shlwapi.lib
|
|
||||||
$(MT) -manifest $@.manifest -outputresource:$@;1
|
$(MT) -manifest $@.manifest -outputresource:$@;1
|
||||||
del $@.manifest
|
del $@.manifest
|
||||||
|
|
||||||
|
8
NEWS
8
NEWS
@ -1,3 +1,11 @@
|
|||||||
|
- 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
|
- 11/2/2018: version 1.0.1
|
||||||
This is a binary compatible release.
|
This is a binary compatible release.
|
||||||
* lossless encoder speedups
|
* lossless encoder speedups
|
||||||
|
4
README
4
README
@ -4,7 +4,7 @@
|
|||||||
\__\__/\____/\_____/__/ ____ ___
|
\__\__/\____/\_____/__/ ____ ___
|
||||||
/ _/ / \ \ / _ \/ _/
|
/ _/ / \ \ / _ \/ _/
|
||||||
/ \_/ / / \ \ __/ \__
|
/ \_/ / / \ \ __/ \__
|
||||||
\____/____/\_____/_____/____/v1.0.1
|
\____/____/\_____/_____/____/v1.0.2
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
============
|
============
|
||||||
@ -136,6 +136,8 @@ cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
|
|||||||
|
|
||||||
or through your favorite interface (like ccmake or cmake-qt-gui).
|
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:
|
Finally, once installed, you can also use WebP in your CMake project by doing:
|
||||||
|
|
||||||
find_package(WebP)
|
find_package(WebP)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
__ __ ____ ____ ____ __ __ _ __ __
|
__ __ ____ ____ ____ __ __ _ __ __
|
||||||
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
||||||
\ / __/ _ \ __/ / / (_/ /__
|
\ / __/ _ \ __/ / / (_/ /__
|
||||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.1
|
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.2
|
||||||
|
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
|
@ -173,6 +173,7 @@ model {
|
|||||||
include "cost.c"
|
include "cost.c"
|
||||||
include "cost_mips32.c"
|
include "cost_mips32.c"
|
||||||
include "cost_mips_dsp_r2.c"
|
include "cost_mips_dsp_r2.c"
|
||||||
|
include "cost_neon.$NEON"
|
||||||
include "cost_sse2.c"
|
include "cost_sse2.c"
|
||||||
include "enc.c"
|
include "enc.c"
|
||||||
include "enc_mips32.c"
|
include "enc_mips32.c"
|
||||||
|
4
codereview.settings
Normal file
4
codereview.settings
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# This file is used by git cl to get repository specific information.
|
||||||
|
GERRIT_HOST: True
|
||||||
|
CODE_REVIEW_SERVER: chromium-review.googlesource.com
|
||||||
|
GERRIT_SQUASH_UPLOADS: False
|
@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libwebp], [1.0.1],
|
AC_INIT([libwebp], [1.0.2],
|
||||||
[https://bugs.chromium.org/p/webp],,
|
[https://bugs.chromium.org/p/webp],,
|
||||||
[http://developers.google.com/speed/webp])
|
[http://developers.google.com/speed/webp])
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "./anim_util.h"
|
#include "./anim_util.h"
|
||||||
#include "./example_util.h"
|
#include "./example_util.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -218,12 +219,14 @@ int main(int argc, const char* argv[]) {
|
|||||||
const char* files[2] = { NULL, NULL };
|
const char* files[2] = { NULL, NULL };
|
||||||
AnimatedImage images[2];
|
AnimatedImage images[2];
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-dump_frames")) {
|
if (!strcmp(argv[c], "-dump_frames")) {
|
||||||
if (c < argc - 1) {
|
if (c < argc - 1) {
|
||||||
dump_frames = 1;
|
dump_frames = 1;
|
||||||
dump_folder = argv[++c];
|
dump_folder = (const char*)GET_WARGV(argv, ++c);
|
||||||
} else {
|
} else {
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
}
|
}
|
||||||
@ -243,7 +246,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-version")) {
|
} else if (!strcmp(argv[c], "-version")) {
|
||||||
int dec_version, demux_version;
|
int dec_version, demux_version;
|
||||||
GetAnimatedImageVersions(&dec_version, &demux_version);
|
GetAnimatedImageVersions(&dec_version, &demux_version);
|
||||||
@ -252,13 +255,13 @@ int main(int argc, const char* argv[]) {
|
|||||||
(dec_version >> 0) & 0xff,
|
(dec_version >> 0) & 0xff,
|
||||||
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
|
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
|
||||||
(demux_version >> 0) & 0xff);
|
(demux_version >> 0) & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else {
|
} else {
|
||||||
if (!got_input1) {
|
if (!got_input1) {
|
||||||
files[0] = argv[c];
|
files[0] = (const char*)GET_WARGV(argv, c);
|
||||||
got_input1 = 1;
|
got_input1 = 1;
|
||||||
} else if (!got_input2) {
|
} else if (!got_input2) {
|
||||||
files[1] = argv[c];
|
files[1] = (const char*)GET_WARGV(argv, c);
|
||||||
got_input2 = 1;
|
got_input2 = 1;
|
||||||
} else {
|
} else {
|
||||||
parse_error = 1;
|
parse_error = 1;
|
||||||
@ -266,29 +269,30 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!got_input2) {
|
if (!got_input2) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_frames) {
|
if (dump_frames) {
|
||||||
printf("Dumping decoded frames in: %s\n", dump_folder);
|
WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(images, 0, sizeof(images));
|
memset(images, 0, sizeof(images));
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 2; ++i) {
|
||||||
printf("Decoding file: %s\n", files[i]);
|
WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]);
|
||||||
if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) {
|
if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) {
|
||||||
fprintf(stderr, "Error decoding file: %s\n Aborting.\n", files[i]);
|
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n",
|
||||||
|
(const W_CHAR*)files[i]);
|
||||||
return_code = -2;
|
return_code = -2;
|
||||||
goto End;
|
goto End;
|
||||||
} else {
|
} else {
|
||||||
@ -298,14 +302,16 @@ int main(int argc, const char* argv[]) {
|
|||||||
|
|
||||||
if (!CompareAnimatedImagePair(&images[0], &images[1],
|
if (!CompareAnimatedImagePair(&images[0], &images[1],
|
||||||
premultiply, min_psnr)) {
|
premultiply, min_psnr)) {
|
||||||
fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]);
|
WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0],
|
||||||
|
(const W_CHAR*)files[1]);
|
||||||
return_code = -3;
|
return_code = -3;
|
||||||
} else {
|
} else {
|
||||||
printf("\nFiles %s and %s are identical.\n", files[0], files[1]);
|
WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0],
|
||||||
|
(const W_CHAR*)files[1]);
|
||||||
return_code = 0;
|
return_code = 0;
|
||||||
}
|
}
|
||||||
End:
|
End:
|
||||||
ClearAnimatedImage(&images[0]);
|
ClearAnimatedImage(&images[0]);
|
||||||
ClearAnimatedImage(&images[1]);
|
ClearAnimatedImage(&images[1]);
|
||||||
return return_code;
|
FREE_WARGV_AND_RETURN(return_code);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "./anim_util.h"
|
#include "./anim_util.h"
|
||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "../imageio/image_enc.h"
|
#include "../imageio/image_enc.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -36,15 +37,17 @@ static void Help(void) {
|
|||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
int error = 0;
|
int error = 0;
|
||||||
const char* dump_folder = ".";
|
const W_CHAR* dump_folder = TO_W_CHAR(".");
|
||||||
const char* prefix = "dump_";
|
const W_CHAR* prefix = TO_W_CHAR("dump_");
|
||||||
const char* suffix = "png";
|
const W_CHAR* suffix = TO_W_CHAR("png");
|
||||||
WebPOutputFileFormat format = PNG;
|
WebPOutputFileFormat format = PNG;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 1; !error && c < argc; ++c) {
|
for (c = 1; !error && c < argc; ++c) {
|
||||||
@ -54,23 +57,23 @@ int main(int argc, const char* argv[]) {
|
|||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dump_folder = argv[++c];
|
dump_folder = GET_WARGV(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-prefix")) {
|
} else if (!strcmp(argv[c], "-prefix")) {
|
||||||
if (c + 1 == argc) {
|
if (c + 1 == argc) {
|
||||||
fprintf(stderr, "missing argument after option '%s'\n", argv[c]);
|
fprintf(stderr, "missing argument after option '%s'\n", argv[c]);
|
||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prefix = argv[++c];
|
prefix = GET_WARGV(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-tiff")) {
|
} else if (!strcmp(argv[c], "-tiff")) {
|
||||||
format = TIFF;
|
format = TIFF;
|
||||||
suffix = "tiff";
|
suffix = TO_W_CHAR("tiff");
|
||||||
} else if (!strcmp(argv[c], "-pam")) {
|
} else if (!strcmp(argv[c], "-pam")) {
|
||||||
format = PAM;
|
format = PAM;
|
||||||
suffix = "pam";
|
suffix = TO_W_CHAR("pam");
|
||||||
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-version")) {
|
} else if (!strcmp(argv[c], "-version")) {
|
||||||
int dec_version, demux_version;
|
int dec_version, demux_version;
|
||||||
GetAnimatedImageVersions(&dec_version, &demux_version);
|
GetAnimatedImageVersions(&dec_version, &demux_version);
|
||||||
@ -79,21 +82,21 @@ int main(int argc, const char* argv[]) {
|
|||||||
(dec_version >> 0) & 0xff,
|
(dec_version >> 0) & 0xff,
|
||||||
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
|
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
|
||||||
(demux_version >> 0) & 0xff);
|
(demux_version >> 0) & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else {
|
} else {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
AnimatedImage image;
|
AnimatedImage image;
|
||||||
const char* const file = argv[c];
|
const W_CHAR* const file = GET_WARGV(argv, c);
|
||||||
memset(&image, 0, sizeof(image));
|
memset(&image, 0, sizeof(image));
|
||||||
printf("Decoding file: %s as %s/%sxxxx.%s\n",
|
WPRINTF("Decoding file: %s as %s/%sxxxx.%s\n",
|
||||||
file, dump_folder, prefix, suffix);
|
file, dump_folder, prefix, suffix);
|
||||||
if (!ReadAnimatedImage(file, &image, 0, NULL)) {
|
if (!ReadAnimatedImage((const char*)file, &image, 0, NULL)) {
|
||||||
fprintf(stderr, "Error decoding file: %s\n Aborting.\n", file);
|
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", file);
|
||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (i = 0; !error && i < image.num_frames; ++i) {
|
for (i = 0; !error && i < image.num_frames; ++i) {
|
||||||
char out_file[1024];
|
W_CHAR out_file[1024];
|
||||||
WebPDecBuffer buffer;
|
WebPDecBuffer buffer;
|
||||||
WebPInitDecBuffer(&buffer);
|
WebPInitDecBuffer(&buffer);
|
||||||
buffer.colorspace = MODE_RGBA;
|
buffer.colorspace = MODE_RGBA;
|
||||||
@ -103,10 +106,10 @@ int main(int argc, const char* argv[]) {
|
|||||||
buffer.u.RGBA.rgba = image.frames[i].rgba;
|
buffer.u.RGBA.rgba = image.frames[i].rgba;
|
||||||
buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t);
|
buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t);
|
||||||
buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height;
|
buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height;
|
||||||
snprintf(out_file, sizeof(out_file), "%s/%s%.4d.%s",
|
WSNPRINTF(out_file, sizeof(out_file), "%s/%s%.4d.%s",
|
||||||
dump_folder, prefix, i, suffix);
|
dump_folder, prefix, i, suffix);
|
||||||
if (!WebPSaveImage(&buffer, format, out_file)) {
|
if (!WebPSaveImage(&buffer, format, (const char*)out_file)) {
|
||||||
fprintf(stderr, "Error while saving image '%s'\n", out_file);
|
WFPRINTF(stderr, "Error while saving image '%s'\n", out_file);
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
WebPFreeDecBuffer(&buffer);
|
WebPFreeDecBuffer(&buffer);
|
||||||
@ -114,5 +117,5 @@ int main(int argc, const char* argv[]) {
|
|||||||
ClearAnimatedImage(&image);
|
ClearAnimatedImage(&image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error ? 1 : 0;
|
FREE_WARGV_AND_RETURN(error ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "webp/demux.h"
|
#include "webp/demux.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./gifdec.h"
|
#include "./gifdec.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
#include "./unicode_gif.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -152,42 +154,42 @@ static int DumpFrame(const char filename[], const char dump_folder[],
|
|||||||
int ok = 0;
|
int ok = 0;
|
||||||
size_t max_len;
|
size_t max_len;
|
||||||
int y;
|
int y;
|
||||||
const char* base_name = NULL;
|
const W_CHAR* base_name = NULL;
|
||||||
char* file_name = NULL;
|
W_CHAR* file_name = NULL;
|
||||||
FILE* f = NULL;
|
FILE* f = NULL;
|
||||||
const char* row;
|
const char* row;
|
||||||
|
|
||||||
if (dump_folder == NULL) dump_folder = ".";
|
if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR(".");
|
||||||
|
|
||||||
base_name = strrchr(filename, '/');
|
base_name = WSTRRCHR(filename, '/');
|
||||||
base_name = (base_name == NULL) ? filename : base_name + 1;
|
base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1;
|
||||||
max_len = strlen(dump_folder) + 1 + strlen(base_name)
|
max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name)
|
||||||
+ strlen("_frame_") + strlen(".pam") + 8;
|
+ strlen("_frame_") + strlen(".pam") + 8;
|
||||||
file_name = (char*)malloc(max_len * sizeof(*file_name));
|
file_name = (W_CHAR*)malloc(max_len * sizeof(*file_name));
|
||||||
if (file_name == NULL) goto End;
|
if (file_name == NULL) goto End;
|
||||||
|
|
||||||
if (snprintf(file_name, max_len, "%s/%s_frame_%d.pam",
|
if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam",
|
||||||
dump_folder, base_name, frame_num) < 0) {
|
(const W_CHAR*)dump_folder, base_name, frame_num) < 0) {
|
||||||
fprintf(stderr, "Error while generating file name\n");
|
fprintf(stderr, "Error while generating file name\n");
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
f = fopen(file_name, "wb");
|
f = WFOPEN(file_name, "wb");
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
fprintf(stderr, "Error opening file for writing: %s\n", file_name);
|
WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n"
|
if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n"
|
||||||
"DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
|
"DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
|
||||||
canvas_width, canvas_height) < 0) {
|
canvas_width, canvas_height) < 0) {
|
||||||
fprintf(stderr, "Write error for file %s\n", file_name);
|
WFPRINTF(stderr, "Write error for file %s\n", file_name);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
row = (const char*)rgba;
|
row = (const char*)rgba;
|
||||||
for (y = 0; y < canvas_height; ++y) {
|
for (y = 0; y < canvas_height; ++y) {
|
||||||
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
|
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
|
||||||
fprintf(stderr, "Error writing to file: %s\n", file_name);
|
WFPRINTF(stderr, "Error writing to file: %s\n", file_name);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
row += canvas_width * kNumChannels;
|
row += canvas_width * kNumChannels;
|
||||||
@ -223,7 +225,7 @@ static int ReadAnimatedWebP(const char filename[],
|
|||||||
|
|
||||||
dec = WebPAnimDecoderNew(webp_data, NULL);
|
dec = WebPAnimDecoderNew(webp_data, NULL);
|
||||||
if (dec == NULL) {
|
if (dec == NULL) {
|
||||||
fprintf(stderr, "Error parsing image: %s\n", filename);
|
WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,15 +513,15 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
|
|||||||
int gif_error;
|
int gif_error;
|
||||||
GifFileType* gif;
|
GifFileType* gif;
|
||||||
|
|
||||||
gif = DGifOpenFileName(filename, NULL);
|
gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL);
|
||||||
if (gif == NULL) {
|
if (gif == NULL) {
|
||||||
fprintf(stderr, "Could not read file: %s.\n", filename);
|
WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gif_error = DGifSlurp(gif);
|
gif_error = DGifSlurp(gif);
|
||||||
if (gif_error != GIF_OK) {
|
if (gif_error != GIF_OK) {
|
||||||
fprintf(stderr, "Could not parse image: %s.\n", filename);
|
WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename);
|
||||||
GIFDisplayError(gif, gif_error);
|
GIFDisplayError(gif, gif_error);
|
||||||
DGifCloseFile(gif, NULL);
|
DGifCloseFile(gif, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
@ -705,7 +707,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
|
|||||||
memset(image, 0, sizeof(*image));
|
memset(image, 0, sizeof(*image));
|
||||||
|
|
||||||
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
|
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
|
||||||
fprintf(stderr, "Error reading file: %s\n", filename);
|
WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,9 +717,9 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
|
|||||||
} else if (IsGIF(&webp_data)) {
|
} else if (IsGIF(&webp_data)) {
|
||||||
ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder);
|
ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
WFPRINTF(stderr,
|
||||||
"Unknown file type: %s. Supported file types are WebP and GIF\n",
|
"Unknown file type: %s. Supported file types are WebP and GIF\n",
|
||||||
filename);
|
(const W_CHAR*)filename);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
if (!ok) ClearAnimatedImage(image);
|
if (!ok) ClearAnimatedImage(image);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "../imageio/image_dec.h"
|
#include "../imageio/image_dec.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./stopwatch.h"
|
#include "./stopwatch.h"
|
||||||
|
#include "./unicode.h"
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
|
|
||||||
#ifndef WEBP_DLL
|
#ifndef WEBP_DLL
|
||||||
@ -88,7 +89,8 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||||
|
(const W_CHAR*)filename);
|
||||||
}
|
}
|
||||||
free((void*)data);
|
free((void*)data);
|
||||||
return ok;
|
return ok;
|
||||||
@ -114,7 +116,8 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
|||||||
}
|
}
|
||||||
End:
|
End:
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||||
|
(const W_CHAR*)filename);
|
||||||
}
|
}
|
||||||
free((void*)data);
|
free((void*)data);
|
||||||
return ok;
|
return ok;
|
||||||
@ -185,7 +188,7 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic,
|
|||||||
if (short_output) {
|
if (short_output) {
|
||||||
fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
|
fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "File: %s\n", file_name);
|
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
|
||||||
fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
|
fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
|
||||||
fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size,
|
fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size,
|
||||||
8.f * stats->coded_size / pic->width / pic->height);
|
8.f * stats->coded_size / pic->width / pic->height);
|
||||||
@ -204,7 +207,7 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
|
|||||||
const int num_i16 = stats->block_count[1];
|
const int num_i16 = stats->block_count[1];
|
||||||
const int num_skip = stats->block_count[2];
|
const int num_skip = stats->block_count[2];
|
||||||
const int total = num_i4 + num_i16;
|
const int total = num_i4 + num_i16;
|
||||||
fprintf(stderr, "File: %s\n", file_name);
|
WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name);
|
||||||
fprintf(stderr, "Dimension: %d x %d%s\n",
|
fprintf(stderr, "Dimension: %d x %d%s\n",
|
||||||
pic->width, pic->height,
|
pic->width, pic->height,
|
||||||
stats->alpha_data_size ? " (with alpha)" : "");
|
stats->alpha_data_size ? " (with alpha)" : "");
|
||||||
@ -309,7 +312,7 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
|||||||
const int alpha_height =
|
const int alpha_height =
|
||||||
WebPPictureHasTransparency(picture) ? picture->height : 0;
|
WebPPictureHasTransparency(picture) ? picture->height : 0;
|
||||||
const int height = picture->height + uv_height + alpha_height;
|
const int height = picture->height + uv_height + alpha_height;
|
||||||
FILE* const f = fopen(PGM_name, "wb");
|
FILE* const f = WFOPEN(PGM_name, "wb");
|
||||||
if (f == NULL) return 0;
|
if (f == NULL) return 0;
|
||||||
fprintf(f, "P5\n%d %d\n255\n", stride, height);
|
fprintf(f, "P5\n%d %d\n255\n", stride, height);
|
||||||
for (y = 0; y < picture->height; ++y) {
|
for (y = 0; y < picture->height; ++y) {
|
||||||
@ -663,32 +666,34 @@ int main(int argc, const char *argv[]) {
|
|||||||
Metadata metadata;
|
Metadata metadata;
|
||||||
Stopwatch stop_watch;
|
Stopwatch stop_watch;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
MetadataInit(&metadata);
|
MetadataInit(&metadata);
|
||||||
WebPMemoryWriterInit(&memory_writer);
|
WebPMemoryWriterInit(&memory_writer);
|
||||||
if (!WebPPictureInit(&picture) ||
|
if (!WebPPictureInit(&picture) ||
|
||||||
!WebPPictureInit(&original_picture) ||
|
!WebPPictureInit(&original_picture) ||
|
||||||
!WebPConfigInit(&config)) {
|
!WebPConfigInit(&config)) {
|
||||||
fprintf(stderr, "Error! Version mismatch!\n");
|
fprintf(stderr, "Error! Version mismatch!\n");
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
HelpShort();
|
HelpShort();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
HelpShort();
|
HelpShort();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||||
HelpLong();
|
HelpLong();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
||||||
out_file = argv[++c];
|
out_file = (const char*)GET_WARGV(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-d") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-d") && c < argc - 1) {
|
||||||
dump_file = argv[++c];
|
dump_file = (const char*)GET_WARGV(argv, ++c);
|
||||||
config.show_compressed = 1;
|
config.show_compressed = 1;
|
||||||
} else if (!strcmp(argv[c], "-print_psnr")) {
|
} else if (!strcmp(argv[c], "-print_psnr")) {
|
||||||
config.show_compressed = 1;
|
config.show_compressed = 1;
|
||||||
@ -816,7 +821,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
const int version = WebPGetEncoderVersion();
|
const int version = WebPGetEncoderVersion();
|
||||||
printf("%d.%d.%d\n",
|
printf("%d.%d.%d\n",
|
||||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-progress")) {
|
} else if (!strcmp(argv[c], "-progress")) {
|
||||||
show_progress = 1;
|
show_progress = 1;
|
||||||
} else if (!strcmp(argv[c], "-quiet")) {
|
} else if (!strcmp(argv[c], "-quiet")) {
|
||||||
@ -878,8 +883,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
if (i == kNumTokens) {
|
if (i == kNumTokens) {
|
||||||
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
||||||
(int)(token - start), start);
|
(int)(token - start), start);
|
||||||
HelpLong();
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
start = token + 1;
|
start = token + 1;
|
||||||
}
|
}
|
||||||
@ -893,19 +897,19 @@ int main(int argc, const char *argv[]) {
|
|||||||
} else if (!strcmp(argv[c], "-v")) {
|
} else if (!strcmp(argv[c], "-v")) {
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
} else if (!strcmp(argv[c], "--")) {
|
} else if (!strcmp(argv[c], "--")) {
|
||||||
if (c < argc - 1) in_file = argv[++c];
|
if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c);
|
||||||
break;
|
break;
|
||||||
} else if (argv[c][0] == '-') {
|
} else if (argv[c][0] == '-') {
|
||||||
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
||||||
HelpLong();
|
HelpLong();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
} else {
|
} else {
|
||||||
in_file = argv[c];
|
in_file = (const char*)GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
HelpLong();
|
HelpLong();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_file == NULL) {
|
if (in_file == NULL) {
|
||||||
@ -955,7 +959,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
if (!ReadPicture(in_file, &picture, keep_alpha,
|
if (!ReadPicture(in_file, &picture, keep_alpha,
|
||||||
(keep_metadata == 0) ? NULL : &metadata)) {
|
(keep_metadata == 0) ? NULL : &metadata)) {
|
||||||
fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
|
WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n",
|
||||||
|
(const W_CHAR*)in_file);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
|
picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
|
||||||
@ -971,14 +976,15 @@ int main(int argc, const char *argv[]) {
|
|||||||
|
|
||||||
// Open the output
|
// Open the output
|
||||||
if (out_file != NULL) {
|
if (out_file != NULL) {
|
||||||
const int use_stdout = !strcmp(out_file, "-");
|
const int use_stdout = !WSTRCMP(out_file, "-");
|
||||||
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
|
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
|
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
|
||||||
|
(const W_CHAR*)out_file);
|
||||||
goto Error;
|
goto Error;
|
||||||
} else {
|
} else {
|
||||||
if (!short_output && !quiet) {
|
if (!short_output && !quiet) {
|
||||||
fprintf(stderr, "Saving file '%s'\n", out_file);
|
WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keep_metadata == 0) {
|
if (keep_metadata == 0) {
|
||||||
@ -1093,7 +1099,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
fprintf(stderr, "Warning: can't dump file (-d option) "
|
fprintf(stderr, "Warning: can't dump file (-d option) "
|
||||||
"in lossless mode.\n");
|
"in lossless mode.\n");
|
||||||
} else if (!DumpPicture(&picture, dump_file)) {
|
} else if (!DumpPicture(&picture, dump_file)) {
|
||||||
fprintf(stderr, "Warning, couldn't dump picture %s\n", dump_file);
|
WFPRINTF(stderr, "Warning, couldn't dump picture %s\n",
|
||||||
|
(const W_CHAR*)dump_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,7 +1176,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
fclose(out);
|
fclose(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return return_value;
|
FREE_WARGV_AND_RETURN(return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "../imageio/image_enc.h"
|
#include "../imageio/image_enc.h"
|
||||||
#include "../imageio/webpdec.h"
|
#include "../imageio/webpdec.h"
|
||||||
#include "./stopwatch.h"
|
#include "./stopwatch.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
static int quiet = 0;
|
static int quiet = 0;
|
||||||
@ -42,7 +43,7 @@ extern void* VP8GetCPUInfo; // opaque forward declaration.
|
|||||||
|
|
||||||
static int SaveOutput(const WebPDecBuffer* const buffer,
|
static int SaveOutput(const WebPDecBuffer* const buffer,
|
||||||
WebPOutputFileFormat format, const char* const out_file) {
|
WebPOutputFileFormat format, const char* const out_file) {
|
||||||
const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-");
|
const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-");
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
Stopwatch stop_watch;
|
Stopwatch stop_watch;
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
|
|||||||
if (use_stdout) {
|
if (use_stdout) {
|
||||||
fprintf(stderr, "Saved to stdout\n");
|
fprintf(stderr, "Saved to stdout\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Saved file %s\n", out_file);
|
WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
@ -67,7 +68,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
|
|||||||
if (use_stdout) {
|
if (use_stdout) {
|
||||||
fprintf(stderr, "Error writing to stdout !!\n");
|
fprintf(stderr, "Error writing to stdout !!\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error writing file %s !!\n", out_file);
|
WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
@ -191,18 +192,20 @@ int main(int argc, const char *argv[]) {
|
|||||||
int incremental = 0;
|
int incremental = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (!WebPInitDecoderConfig(&config)) {
|
if (!WebPInitDecoderConfig(&config)) {
|
||||||
fprintf(stderr, "Library version mismatch!\n");
|
fprintf(stderr, "Library version mismatch!\n");
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
||||||
out_file = argv[++c];
|
out_file = (const char*)GET_WARGV(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-alpha")) {
|
} else if (!strcmp(argv[c], "-alpha")) {
|
||||||
format = ALPHA_PLANE_ONLY;
|
format = ALPHA_PLANE_ONLY;
|
||||||
} else if (!strcmp(argv[c], "-nofancy")) {
|
} else if (!strcmp(argv[c], "-nofancy")) {
|
||||||
@ -223,7 +226,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
const int version = WebPGetDecoderVersion();
|
const int version = WebPGetDecoderVersion();
|
||||||
printf("%d.%d.%d\n",
|
printf("%d.%d.%d\n",
|
||||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-pgm")) {
|
} else if (!strcmp(argv[c], "-pgm")) {
|
||||||
format = PGM;
|
format = PGM;
|
||||||
} else if (!strcmp(argv[c], "-yuv")) {
|
} else if (!strcmp(argv[c], "-yuv")) {
|
||||||
@ -284,26 +287,26 @@ int main(int argc, const char *argv[]) {
|
|||||||
} else if (!strcmp(argv[c], "-incremental")) {
|
} else if (!strcmp(argv[c], "-incremental")) {
|
||||||
incremental = 1;
|
incremental = 1;
|
||||||
} else if (!strcmp(argv[c], "--")) {
|
} else if (!strcmp(argv[c], "--")) {
|
||||||
if (c < argc - 1) in_file = argv[++c];
|
if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c);
|
||||||
break;
|
break;
|
||||||
} else if (argv[c][0] == '-') {
|
} else if (argv[c][0] == '-') {
|
||||||
fprintf(stderr, "Unknown option '%s'\n", argv[c]);
|
fprintf(stderr, "Unknown option '%s'\n", argv[c]);
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
} else {
|
} else {
|
||||||
in_file = argv[c];
|
in_file = (const char*)GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_file == NULL) {
|
if (in_file == NULL) {
|
||||||
fprintf(stderr, "missing input file!!\n");
|
fprintf(stderr, "missing input file!!\n");
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quiet) verbose = 0;
|
if (quiet) verbose = 0;
|
||||||
@ -312,7 +315,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
VP8StatusCode status = VP8_STATUS_OK;
|
VP8StatusCode status = VP8_STATUS_OK;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
|
if (!LoadWebP(in_file, &data, &data_size, bitstream)) {
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@ -389,18 +392,18 @@ int main(int argc, const char *argv[]) {
|
|||||||
|
|
||||||
if (out_file != NULL) {
|
if (out_file != NULL) {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
fprintf(stderr, "Decoded %s. Dimensions: %d x %d %s. Format: %s. "
|
WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file);
|
||||||
"Now saving...\n",
|
fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n",
|
||||||
in_file, output_buffer->width, output_buffer->height,
|
output_buffer->width, output_buffer->height,
|
||||||
bitstream->has_alpha ? " (with alpha)" : "",
|
bitstream->has_alpha ? " (with alpha)" : "",
|
||||||
kFormatType[bitstream->format]);
|
kFormatType[bitstream->format]);
|
||||||
}
|
}
|
||||||
ok = SaveOutput(output_buffer, format, out_file);
|
ok = SaveOutput(output_buffer, format, out_file);
|
||||||
} else {
|
} else {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
fprintf(stderr, "File %s can be decoded "
|
WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file);
|
||||||
"(dimensions: %d x %d %s. Format: %s).\n",
|
fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n",
|
||||||
in_file, output_buffer->width, output_buffer->height,
|
output_buffer->width, output_buffer->height,
|
||||||
bitstream->has_alpha ? " (with alpha)" : "",
|
bitstream->has_alpha ? " (with alpha)" : "",
|
||||||
kFormatType[bitstream->format]);
|
kFormatType[bitstream->format]);
|
||||||
fprintf(stderr, "Nothing written; "
|
fprintf(stderr, "Nothing written; "
|
||||||
@ -411,7 +414,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
WebPFreeDecBuffer(output_buffer);
|
WebPFreeDecBuffer(output_buffer);
|
||||||
free((void*)external_buffer);
|
free((void*)external_buffer);
|
||||||
free((void*)data);
|
free((void*)data);
|
||||||
return ok ? 0 : -1;
|
FREE_WARGV_AND_RETURN(ok ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -90,6 +90,14 @@ int ExUtilInitCommandLineArguments(int argc, const char* argv[],
|
|||||||
if (argc == 1 && argv[0][0] != '-') {
|
if (argc == 1 && argv[0][0] != '-') {
|
||||||
char* cur;
|
char* cur;
|
||||||
const char sep[] = " \t\r\n\f\v";
|
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_)) {
|
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#include "../examples/example_util.h"
|
#include "../examples/example_util.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./gifdec.h"
|
#include "./gifdec.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
#include "./unicode_gif.h"
|
||||||
|
|
||||||
#if !defined(STDIN_FILENO)
|
#if !defined(STDIN_FILENO)
|
||||||
#define STDIN_FILENO 0
|
#define STDIN_FILENO 0
|
||||||
@ -99,7 +101,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
int gif_error = GIF_ERROR;
|
int gif_error = GIF_ERROR;
|
||||||
WebPMuxError err = WEBP_MUX_OK;
|
WebPMuxError err = WEBP_MUX_OK;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
const char *in_file = NULL, *out_file = NULL;
|
const W_CHAR *in_file = NULL, *out_file = NULL;
|
||||||
GifFileType* gif = NULL;
|
GifFileType* gif = NULL;
|
||||||
int frame_duration = 0;
|
int frame_duration = 0;
|
||||||
int frame_timestamp = 0;
|
int frame_timestamp = 0;
|
||||||
@ -132,11 +134,13 @@ int main(int argc, const char *argv[]) {
|
|||||||
int default_kmin = 1; // Whether to use default kmin value.
|
int default_kmin = 1; // Whether to use default kmin value.
|
||||||
int default_kmax = 1;
|
int default_kmax = 1;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) ||
|
if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) ||
|
||||||
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
|
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
|
||||||
!WebPPictureInit(&prev_canvas)) {
|
!WebPPictureInit(&prev_canvas)) {
|
||||||
fprintf(stderr, "Error! Version mismatch!\n");
|
fprintf(stderr, "Error! Version mismatch!\n");
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
config.lossless = 1; // Use lossless compression by default.
|
config.lossless = 1; // Use lossless compression by default.
|
||||||
|
|
||||||
@ -146,16 +150,16 @@ int main(int argc, const char *argv[]) {
|
|||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
||||||
out_file = argv[++c];
|
out_file = GET_WARGV(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-lossy")) {
|
} else if (!strcmp(argv[c], "-lossy")) {
|
||||||
config.lossless = 0;
|
config.lossless = 0;
|
||||||
} else if (!strcmp(argv[c], "-mixed")) {
|
} else if (!strcmp(argv[c], "-mixed")) {
|
||||||
@ -212,7 +216,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
|
||||||
(int)(token - start), start);
|
(int)(token - start), start);
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
start = token + 1;
|
start = token + 1;
|
||||||
}
|
}
|
||||||
@ -225,7 +229,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
|
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
|
||||||
enc_version & 0xff, (mux_version >> 16) & 0xff,
|
enc_version & 0xff, (mux_version >> 16) & 0xff,
|
||||||
(mux_version >> 8) & 0xff, mux_version & 0xff);
|
(mux_version >> 8) & 0xff, mux_version & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-quiet")) {
|
} else if (!strcmp(argv[c], "-quiet")) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
enc_options.verbose = 0;
|
enc_options.verbose = 0;
|
||||||
@ -233,19 +237,19 @@ int main(int argc, const char *argv[]) {
|
|||||||
verbose = 1;
|
verbose = 1;
|
||||||
enc_options.verbose = 1;
|
enc_options.verbose = 1;
|
||||||
} else if (!strcmp(argv[c], "--")) {
|
} else if (!strcmp(argv[c], "--")) {
|
||||||
if (c < argc - 1) in_file = argv[++c];
|
if (c < argc - 1) in_file = GET_WARGV(argv, ++c);
|
||||||
break;
|
break;
|
||||||
} else if (argv[c][0] == '-') {
|
} else if (argv[c][0] == '-') {
|
||||||
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
} else {
|
} else {
|
||||||
in_file = argv[c];
|
in_file = GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,13 +273,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the decoder object
|
// Start the decoder object
|
||||||
#if LOCAL_GIF_PREREQ(5,0)
|
gif = DGifOpenFileUnicode(in_file, &gif_error);
|
||||||
gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO, &gif_error)
|
|
||||||
: DGifOpenFileName(in_file, &gif_error);
|
|
||||||
#else
|
|
||||||
gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO)
|
|
||||||
: DGifOpenFileName(in_file);
|
|
||||||
#endif
|
|
||||||
if (gif == NULL) goto End;
|
if (gif == NULL) goto End;
|
||||||
|
|
||||||
// Loop over GIF images
|
// Loop over GIF images
|
||||||
@ -544,17 +542,18 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out_file != NULL) {
|
if (out_file != NULL) {
|
||||||
if (!ImgIoUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
|
if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes,
|
||||||
fprintf(stderr, "Error writing output file: %s\n", out_file);
|
webp_data.size)) {
|
||||||
|
WFPRINTF(stderr, "Error writing output file: %s\n", out_file);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
if (!strcmp(out_file, "-")) {
|
if (!WSTRCMP(out_file, "-")) {
|
||||||
fprintf(stderr, "Saved %d bytes to STDIO\n",
|
fprintf(stderr, "Saved %d bytes to STDIO\n",
|
||||||
(int)webp_data.size);
|
(int)webp_data.size);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Saved output file (%d bytes): %s\n",
|
WFPRINTF(stderr, "Saved output file (%d bytes): %s\n",
|
||||||
(int)webp_data.size, out_file);
|
(int)webp_data.size, out_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -589,7 +588,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return !ok;
|
FREE_WARGV_AND_RETURN(!ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_HAVE_GIF
|
#else // !WEBP_HAVE_GIF
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "../imageio/image_dec.h"
|
#include "../imageio/image_dec.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
#include "./stopwatch.h"
|
#include "./stopwatch.h"
|
||||||
|
#include "./unicode.h"
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "webp/mux.h"
|
#include "webp/mux.h"
|
||||||
|
|
||||||
@ -138,8 +139,13 @@ int main(int argc, const char* argv[]) {
|
|||||||
int c;
|
int c;
|
||||||
int have_input = 0;
|
int have_input = 0;
|
||||||
CommandLineArguments cmd_args;
|
CommandLineArguments cmd_args;
|
||||||
int ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
|
int ok;
|
||||||
if (!ok) return 1;
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
|
ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
|
||||||
|
if (!ok) FREE_WARGV_AND_RETURN(1);
|
||||||
|
|
||||||
argc = cmd_args.argc_;
|
argc = cmd_args.argc_;
|
||||||
argv = cmd_args.argv_;
|
argv = cmd_args.argv_;
|
||||||
|
|
||||||
@ -158,7 +164,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-o") && c + 1 < argc) {
|
if (!strcmp(argv[c], "-o") && c + 1 < argc) {
|
||||||
argv[c] = NULL;
|
argv[c] = NULL;
|
||||||
output = argv[++c];
|
output = (const char*)GET_WARGV_SHIFTED(argv, ++c);
|
||||||
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
|
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
|
||||||
argv[c] = NULL;
|
argv[c] = NULL;
|
||||||
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
|
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
|
||||||
@ -245,7 +251,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
|
|
||||||
// read next input image
|
// read next input image
|
||||||
pic.use_argb = 1;
|
pic.use_argb = 1;
|
||||||
ok = ReadImage(argv[c], &pic);
|
ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic);
|
||||||
if (!ok) goto End;
|
if (!ok) goto End;
|
||||||
|
|
||||||
if (enc == NULL) {
|
if (enc == NULL) {
|
||||||
@ -277,8 +283,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
if (!ok) goto End;
|
if (!ok) goto End;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n",
|
WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n",
|
||||||
pic_num, timestamp_ms, argv[c]);
|
pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c));
|
||||||
}
|
}
|
||||||
timestamp_ms += duration;
|
timestamp_ms += duration;
|
||||||
++pic_num;
|
++pic_num;
|
||||||
@ -302,7 +308,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
if (ok) {
|
if (ok) {
|
||||||
if (output != NULL) {
|
if (output != NULL) {
|
||||||
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
|
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
|
||||||
if (ok) fprintf(stderr, "output file: %s ", output);
|
if (ok) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)output);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[no output file specified] ");
|
fprintf(stderr, "[no output file specified] ");
|
||||||
}
|
}
|
||||||
@ -314,5 +320,5 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
WebPDataClear(&webp_data);
|
WebPDataClear(&webp_data);
|
||||||
ExUtilDeleteCommandLineArguments(&cmd_args);
|
ExUtilDeleteCommandLineArguments(&cmd_args);
|
||||||
return ok ? 0 : 1;
|
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
102
examples/unicode.h
Normal file
102
examples/unicode.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2018 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Unicode support for Windows. The main idea is to maintain an array of Unicode
|
||||||
|
// arguments (wargv) and use it only for file paths. The regular argv is used
|
||||||
|
// for everything else.
|
||||||
|
//
|
||||||
|
// Author: Yannis Guyon (yguyon@google.com)
|
||||||
|
|
||||||
|
#ifndef WEBP_EXAMPLES_UNICODE_H_
|
||||||
|
#define WEBP_EXAMPLES_UNICODE_H_
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(_UNICODE)
|
||||||
|
|
||||||
|
// wchar_t is used instead of TCHAR because we only perform additional work when
|
||||||
|
// Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t.
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
// Create a wchar_t array containing Unicode parameters.
|
||||||
|
#define INIT_WARGV(ARGC, ARGV) \
|
||||||
|
int wargc; \
|
||||||
|
const W_CHAR** const wargv = \
|
||||||
|
(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 WPRINTF(STR, ...) wprintf(TO_W_CHAR(STR), __VA_ARGS__)
|
||||||
|
#define WFPRINTF(STDERR, STR, ...) fwprintf(STDERR, TO_W_CHAR(STR), __VA_ARGS__)
|
||||||
|
|
||||||
|
#define WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME)
|
||||||
|
#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
|
||||||
|
#define WSTRRCHR(FILENAME, STR) wcsrchr((const W_CHAR*)FILENAME, TO_W_CHAR(STR))
|
||||||
|
#define WSNPRINTF(A, B, STR, ...) _snwprintf(A, B, TO_W_CHAR(STR), __VA_ARGS__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Unicode file paths work as is on Unix platforms, and no extra work is done on
|
||||||
|
// Windows either if Unicode is disabled.
|
||||||
|
|
||||||
|
#define INIT_WARGV(ARGC, ARGV)
|
||||||
|
|
||||||
|
#define GET_WARGV(ARGV, C) (ARGV)[C]
|
||||||
|
#define GET_WARGV_SHIFTED(ARGV, C) (ARGV)[C]
|
||||||
|
#define GET_WARGV_OR_NULL() NULL
|
||||||
|
|
||||||
|
#define FREE_WARGV()
|
||||||
|
#define LOCAL_FREE(WARGV)
|
||||||
|
|
||||||
|
#define W_CHAR char
|
||||||
|
#define TO_W_CHAR(STR) (STR)
|
||||||
|
|
||||||
|
#define WFOPEN(ARG, OPT) fopen(ARG, OPT)
|
||||||
|
|
||||||
|
#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__)
|
||||||
|
#define WFPRINTF(STDERR, STR, ...) fprintf(STDERR, STR, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define WSTRLEN(FILENAME) strlen(FILENAME)
|
||||||
|
#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR)
|
||||||
|
#define WSTRRCHR(FILENAME, STR) strrchr(FILENAME, STR)
|
||||||
|
#define WSNPRINTF(A, B, STR, ...) snprintf(A, B, STR, __VA_ARGS__)
|
||||||
|
|
||||||
|
#endif // defined(_WIN32) && defined(_UNICODE)
|
||||||
|
|
||||||
|
// Don't forget to free wargv before returning (e.g. from main).
|
||||||
|
#define FREE_WARGV_AND_RETURN(VALUE) \
|
||||||
|
do { \
|
||||||
|
FREE_WARGV(); \
|
||||||
|
return (VALUE); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif // WEBP_EXAMPLES_UNICODE_H_
|
75
examples/unicode_gif.h
Normal file
75
examples/unicode_gif.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2018 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// giflib doesn't have a Unicode DGifOpenFileName(). Let's make one.
|
||||||
|
//
|
||||||
|
// Author: Yannis Guyon (yguyon@google.com)
|
||||||
|
|
||||||
|
#ifndef WEBP_EXAMPLES_UNICODE_GIF_H_
|
||||||
|
#define WEBP_EXAMPLES_UNICODE_GIF_H_
|
||||||
|
|
||||||
|
#include "./unicode.h"
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "webp/config.h" // For WEBP_HAVE_GIF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBP_HAVE_GIF)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <fcntl.h> // Not standard, needed for _topen and flags.
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gif_lib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "./gifdec.h"
|
||||||
|
|
||||||
|
#if !defined(STDIN_FILENO)
|
||||||
|
#define STDIN_FILENO 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) {
|
||||||
|
if (!WSTRCMP(file_name, "-")) {
|
||||||
|
#if LOCAL_GIF_PREREQ(5, 0)
|
||||||
|
return DGifOpenFileHandle(STDIN_FILENO, error);
|
||||||
|
#else
|
||||||
|
(void)error;
|
||||||
|
return DGifOpenFileHandle(STDIN_FILENO);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(_UNICODE)
|
||||||
|
|
||||||
|
int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY);
|
||||||
|
if (file_handle == -1) {
|
||||||
|
if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LOCAL_GIF_PREREQ(5, 0)
|
||||||
|
return DGifOpenFileHandle(file_handle, error);
|
||||||
|
#else
|
||||||
|
return DGifOpenFileHandle(file_handle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if LOCAL_GIF_PREREQ(5, 0)
|
||||||
|
return DGifOpenFileName(file_name, error);
|
||||||
|
#else
|
||||||
|
return DGifOpenFileName(file_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // defined(_WIN32) && defined(_UNICODE)
|
||||||
|
// DGifCloseFile() is called later.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(WEBP_HAVE_GIF)
|
||||||
|
|
||||||
|
#endif // WEBP_EXAMPLES_UNICODE_GIF_H_
|
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "../examples/example_util.h"
|
#include "../examples/example_util.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -470,9 +471,11 @@ int main(int argc, char *argv[]) {
|
|||||||
WebPDecoderConfig* const config = &kParams.config;
|
WebPDecoderConfig* const config = &kParams.config;
|
||||||
WebPIterator* const curr = &kParams.curr_frame;
|
WebPIterator* const curr = &kParams.curr_frame;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (!WebPInitDecoderConfig(config)) {
|
if (!WebPInitDecoderConfig(config)) {
|
||||||
fprintf(stderr, "Library version mismatch!\n");
|
fprintf(stderr, "Library version mismatch!\n");
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
config->options.dithering_strength = 50;
|
config->options.dithering_strength = 50;
|
||||||
config->options.alpha_dithering_strength = 100;
|
config->options.alpha_dithering_strength = 100;
|
||||||
@ -484,7 +487,7 @@ int main(int argc, char *argv[]) {
|
|||||||
int parse_error = 0;
|
int parse_error = 0;
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-noicc")) {
|
} else if (!strcmp(argv[c], "-noicc")) {
|
||||||
kParams.use_color_profile = 0;
|
kParams.use_color_profile = 0;
|
||||||
} else if (!strcmp(argv[c], "-nofancy")) {
|
} else if (!strcmp(argv[c], "-nofancy")) {
|
||||||
@ -507,30 +510,30 @@ int main(int argc, char *argv[]) {
|
|||||||
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
|
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
|
||||||
dec_version & 0xff, (dmux_version >> 16) & 0xff,
|
dec_version & 0xff, (dmux_version >> 16) & 0xff,
|
||||||
(dmux_version >> 8) & 0xff, dmux_version & 0xff);
|
(dmux_version >> 8) & 0xff, dmux_version & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else if (!strcmp(argv[c], "-mt")) {
|
} else if (!strcmp(argv[c], "-mt")) {
|
||||||
config->options.use_threads = 1;
|
config->options.use_threads = 1;
|
||||||
} else if (!strcmp(argv[c], "--")) {
|
} else if (!strcmp(argv[c], "--")) {
|
||||||
if (c < argc - 1) kParams.file_name = argv[++c];
|
if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c);
|
||||||
break;
|
break;
|
||||||
} else if (argv[c][0] == '-') {
|
} else if (argv[c][0] == '-') {
|
||||||
printf("Unknown option '%s'\n", argv[c]);
|
printf("Unknown option '%s'\n", argv[c]);
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
} else {
|
} else {
|
||||||
kParams.file_name = argv[c];
|
kParams.file_name = (const char*)GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_error) {
|
if (parse_error) {
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kParams.file_name == NULL) {
|
if (kParams.file_name == NULL) {
|
||||||
printf("missing input file!!\n");
|
printf("missing input file!!\n");
|
||||||
Help();
|
Help();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ImgIoUtilReadFile(kParams.file_name,
|
if (!ImgIoUtilReadFile(kParams.file_name,
|
||||||
@ -605,11 +608,11 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Should only be reached when using FREEGLUT:
|
// Should only be reached when using FREEGLUT:
|
||||||
ClearParams();
|
ClearParams();
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
ClearParams();
|
ClearParams();
|
||||||
return -1;
|
FREE_WARGV_AND_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_HAVE_GL
|
#else // !WEBP_HAVE_GL
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
|
#include "./unicode.h"
|
||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "webp/format_constants.h"
|
#include "webp/format_constants.h"
|
||||||
#include "webp/mux_types.h"
|
#include "webp/mux_types.h"
|
||||||
@ -1119,19 +1120,21 @@ int main(int argc, const char* argv[]) {
|
|||||||
WebPInfoStatus webp_info_status = WEBP_INFO_OK;
|
WebPInfoStatus webp_info_status = WEBP_INFO_OK;
|
||||||
WebPInfo webp_info;
|
WebPInfo webp_info;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
HelpShort();
|
HelpShort();
|
||||||
return WEBP_INFO_OK;
|
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse command-line input.
|
// Parse command-line input.
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
|
||||||
HelpShort();
|
HelpShort();
|
||||||
return WEBP_INFO_OK;
|
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
||||||
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
} else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
|
||||||
HelpLong();
|
HelpLong();
|
||||||
return WEBP_INFO_OK;
|
FREE_WARGV_AND_RETURN(WEBP_INFO_OK);
|
||||||
} else if (!strcmp(argv[c], "-quiet")) {
|
} else if (!strcmp(argv[c], "-quiet")) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
} else if (!strcmp(argv[c], "-diag")) {
|
} else if (!strcmp(argv[c], "-diag")) {
|
||||||
@ -1144,7 +1147,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
const int version = WebPGetDecoderVersion();
|
const int version = WebPGetDecoderVersion();
|
||||||
printf("WebP Decoder version: %d.%d.%d\n",
|
printf("WebP Decoder version: %d.%d.%d\n",
|
||||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else { // Assume the remaining are all input files.
|
} else { // Assume the remaining are all input files.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1152,27 +1155,28 @@ int main(int argc, const char* argv[]) {
|
|||||||
|
|
||||||
if (c == argc) {
|
if (c == argc) {
|
||||||
HelpShort();
|
HelpShort();
|
||||||
return WEBP_INFO_INVALID_COMMAND;
|
FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process input files one by one.
|
// Process input files one by one.
|
||||||
for (; c < argc; ++c) {
|
for (; c < argc; ++c) {
|
||||||
WebPData webp_data;
|
WebPData webp_data;
|
||||||
const char* in_file = NULL;
|
const W_CHAR* in_file = NULL;
|
||||||
WebPInfoInit(&webp_info);
|
WebPInfoInit(&webp_info);
|
||||||
webp_info.quiet_ = quiet;
|
webp_info.quiet_ = quiet;
|
||||||
webp_info.show_diagnosis_ = show_diag;
|
webp_info.show_diagnosis_ = show_diag;
|
||||||
webp_info.show_summary_ = show_summary;
|
webp_info.show_summary_ = show_summary;
|
||||||
webp_info.parse_bitstream_ = parse_bitstream;
|
webp_info.parse_bitstream_ = parse_bitstream;
|
||||||
in_file = argv[c];
|
in_file = GET_WARGV(argv, c);
|
||||||
if (in_file == NULL || !ReadFileToWebPData(in_file, &webp_data)) {
|
if (in_file == NULL ||
|
||||||
|
!ReadFileToWebPData((const char*)in_file, &webp_data)) {
|
||||||
webp_info_status = WEBP_INFO_INVALID_COMMAND;
|
webp_info_status = WEBP_INFO_INVALID_COMMAND;
|
||||||
fprintf(stderr, "Failed to open input file %s.\n", in_file);
|
WFPRINTF(stderr, "Failed to open input file %s.\n", in_file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!webp_info.quiet_) printf("File: %s\n", in_file);
|
if (!webp_info.quiet_) WPRINTF("File: %s\n", in_file);
|
||||||
webp_info_status = AnalyzeWebP(&webp_info, &webp_data);
|
webp_info_status = AnalyzeWebP(&webp_info, &webp_data);
|
||||||
WebPDataClear(&webp_data);
|
WebPDataClear(&webp_data);
|
||||||
}
|
}
|
||||||
return webp_info_status;
|
FREE_WARGV_AND_RETURN(webp_info_status);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#include "webp/mux.h"
|
#include "webp/mux.h"
|
||||||
#include "../examples/example_util.h"
|
#include "../examples/example_util.h"
|
||||||
#include "../imageio/imageio_util.h"
|
#include "../imageio/imageio_util.h"
|
||||||
|
#include "./unicode.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Config object to parse command-line arguments.
|
// Config object to parse command-line arguments.
|
||||||
@ -390,23 +391,25 @@ static int CreateMux(const char* const filename, WebPMux** mux) {
|
|||||||
*mux = WebPMuxCreate(&bitstream, 1);
|
*mux = WebPMuxCreate(&bitstream, 1);
|
||||||
WebPDataClear(&bitstream);
|
WebPDataClear(&bitstream);
|
||||||
if (*mux != NULL) return 1;
|
if (*mux != NULL) return 1;
|
||||||
fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
|
WFPRINTF(stderr, "Failed to create mux object from file %s.\n",
|
||||||
|
(const W_CHAR*)filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WriteData(const char* filename, const WebPData* const webpdata) {
|
static int WriteData(const char* filename, const WebPData* const webpdata) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb")
|
FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb")
|
||||||
: ImgIoUtilSetBinaryMode(stdout);
|
: ImgIoUtilSetBinaryMode(stdout);
|
||||||
if (fout == NULL) {
|
if (fout == NULL) {
|
||||||
fprintf(stderr, "Error opening output WebP file %s!\n", filename);
|
WFPRINTF(stderr, "Error opening output WebP file %s!\n",
|
||||||
|
(const W_CHAR*)filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) {
|
if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) {
|
||||||
fprintf(stderr, "Error writing file %s!\n", filename);
|
WFPRINTF(stderr, "Error writing file %s!\n", (const W_CHAR*)filename);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Saved file %s (%d bytes)\n",
|
WFPRINTF(stderr, "Saved file %s (%d bytes)\n",
|
||||||
filename, (int)webpdata->size);
|
(const W_CHAR*)filename, (int)webpdata->size);
|
||||||
ok = 1;
|
ok = 1;
|
||||||
}
|
}
|
||||||
if (fout != stdout) fclose(fout);
|
if (fout != stdout) fclose(fout);
|
||||||
@ -612,13 +615,16 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
|
|||||||
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
|
CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
|
||||||
|
|
||||||
// Parses command-line arguments to fill up config object. Also performs some
|
// Parses command-line arguments to fill up config object. Also performs some
|
||||||
// semantic checks.
|
// semantic checks. unicode_argv contains wchar_t arguments or is null.
|
||||||
static int ParseCommandLine(Config* config) {
|
static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int feature_arg_index = 0;
|
int feature_arg_index = 0;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
int argc = config->cmd_args_.argc_;
|
int argc = config->cmd_args_.argc_;
|
||||||
const char* const* argv = config->cmd_args_.argv_;
|
const char* const* argv = config->cmd_args_.argv_;
|
||||||
|
// Unicode file paths will be used if available.
|
||||||
|
const char* const* wargv =
|
||||||
|
(unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv;
|
||||||
|
|
||||||
while (i < argc) {
|
while (i < argc) {
|
||||||
FeatureArg* const arg = &config->args_[feature_arg_index];
|
FeatureArg* const arg = &config->args_[feature_arg_index];
|
||||||
@ -696,7 +702,7 @@ static int ParseCommandLine(Config* config) {
|
|||||||
i += 2;
|
i += 2;
|
||||||
} else if (!strcmp(argv[i], "-o")) {
|
} else if (!strcmp(argv[i], "-o")) {
|
||||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||||
config->output_ = argv[i + 1];
|
config->output_ = wargv[i + 1];
|
||||||
i += 2;
|
i += 2;
|
||||||
} else if (!strcmp(argv[i], "-info")) {
|
} else if (!strcmp(argv[i], "-info")) {
|
||||||
CHECK_NUM_ARGS_EXACTLY(2, ErrParse);
|
CHECK_NUM_ARGS_EXACTLY(2, ErrParse);
|
||||||
@ -705,24 +711,26 @@ static int ParseCommandLine(Config* config) {
|
|||||||
} else {
|
} else {
|
||||||
config->action_type_ = ACTION_INFO;
|
config->action_type_ = ACTION_INFO;
|
||||||
config->arg_count_ = 0;
|
config->arg_count_ = 0;
|
||||||
config->input_ = argv[i + 1];
|
config->input_ = wargv[i + 1];
|
||||||
}
|
}
|
||||||
i += 2;
|
i += 2;
|
||||||
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
|
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
|
||||||
PrintHelp();
|
PrintHelp();
|
||||||
DeleteConfig(config);
|
DeleteConfig(config);
|
||||||
|
LOCAL_FREE((W_CHAR** const)unicode_argv);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if (!strcmp(argv[i], "-version")) {
|
} else if (!strcmp(argv[i], "-version")) {
|
||||||
const int version = WebPGetMuxVersion();
|
const int version = WebPGetMuxVersion();
|
||||||
printf("%d.%d.%d\n",
|
printf("%d.%d.%d\n",
|
||||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||||
DeleteConfig(config);
|
DeleteConfig(config);
|
||||||
|
LOCAL_FREE((W_CHAR** const)unicode_argv);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if (!strcmp(argv[i], "--")) {
|
} else if (!strcmp(argv[i], "--")) {
|
||||||
if (i < argc - 1) {
|
if (i < argc - 1) {
|
||||||
++i;
|
++i;
|
||||||
if (config->input_ == NULL) {
|
if (config->input_ == NULL) {
|
||||||
config->input_ = argv[i];
|
config->input_ = wargv[i];
|
||||||
} else {
|
} else {
|
||||||
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
||||||
argv[i], ErrParse);
|
argv[i], ErrParse);
|
||||||
@ -747,7 +755,7 @@ static int ParseCommandLine(Config* config) {
|
|||||||
}
|
}
|
||||||
if (config->action_type_ == ACTION_SET) {
|
if (config->action_type_ == ACTION_SET) {
|
||||||
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
CHECK_NUM_ARGS_AT_LEAST(2, ErrParse);
|
||||||
arg->filename_ = argv[i + 1];
|
arg->filename_ = wargv[i + 1];
|
||||||
++feature_arg_index;
|
++feature_arg_index;
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
@ -762,7 +770,7 @@ static int ParseCommandLine(Config* config) {
|
|||||||
i += 2;
|
i += 2;
|
||||||
} else { // Assume input file.
|
} else { // Assume input file.
|
||||||
if (config->input_ == NULL) {
|
if (config->input_ == NULL) {
|
||||||
config->input_ = argv[i];
|
config->input_ = wargv[i];
|
||||||
} else {
|
} else {
|
||||||
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
|
||||||
argv[i], ErrParse);
|
argv[i], ErrParse);
|
||||||
@ -808,8 +816,8 @@ static int ValidateConfig(Config* const config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create config object from command-line arguments.
|
// Create config object from command-line arguments.
|
||||||
static int InitializeConfig(int argc, const char* argv[],
|
static int InitializeConfig(int argc, const char* argv[], Config* const config,
|
||||||
Config* const config) {
|
const W_CHAR** const unicode_argv) {
|
||||||
int num_feature_args = 0;
|
int num_feature_args = 0;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
@ -830,7 +838,7 @@ static int InitializeConfig(int argc, const char* argv[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse command-line.
|
// Parse command-line.
|
||||||
if (!ParseCommandLine(config) || !ValidateConfig(config)) {
|
if (!ParseCommandLine(config, unicode_argv) || !ValidateConfig(config)) {
|
||||||
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
|
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1140,14 +1148,18 @@ static int Process(const Config* config) {
|
|||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
Config config;
|
Config config;
|
||||||
int ok = InitializeConfig(argc - 1, argv + 1, &config);
|
int ok;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
|
ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL());
|
||||||
if (ok) {
|
if (ok) {
|
||||||
ok = Process(&config);
|
ok = Process(&config);
|
||||||
} else {
|
} else {
|
||||||
PrintHelp();
|
PrintHelp();
|
||||||
}
|
}
|
||||||
DeleteConfig(&config);
|
DeleteConfig(&config);
|
||||||
return !ok;
|
FREE_WARGV_AND_RETURN(!ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#define XTRA_MAJ_VERSION 1
|
#define XTRA_MAJ_VERSION 1
|
||||||
#define XTRA_MIN_VERSION 0
|
#define XTRA_MIN_VERSION 0
|
||||||
#define XTRA_REV_VERSION 1
|
#define XTRA_REV_VERSION 2
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
#include "imageio/image_dec.h"
|
#include "imageio/image_dec.h"
|
||||||
#include "imageio/imageio_util.h"
|
#include "imageio/imageio_util.h"
|
||||||
|
#include "../examples/unicode.h"
|
||||||
|
|
||||||
static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||||
int keep_alpha) {
|
int keep_alpha) {
|
||||||
@ -48,7 +49,8 @@ static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
|
|||||||
|
|
||||||
End:
|
End:
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Error! Could not process file %s\n", filename);
|
WFPRINTF(stderr, "Error! Could not process file %s\n",
|
||||||
|
(const W_CHAR*)filename);
|
||||||
}
|
}
|
||||||
free((void*)data);
|
free((void*)data);
|
||||||
return ok ? data_size : 0;
|
return ok ? data_size : 0;
|
||||||
@ -239,9 +241,11 @@ int main(int argc, const char *argv[]) {
|
|||||||
const char* name2 = NULL;
|
const char* name2 = NULL;
|
||||||
const char* output = NULL;
|
const char* output = NULL;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
|
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
|
||||||
fprintf(stderr, "Can't init pictures\n");
|
fprintf(stderr, "Can't init pictures\n");
|
||||||
return 1;
|
FREE_WARGV_AND_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
@ -263,11 +267,11 @@ int main(int argc, const char *argv[]) {
|
|||||||
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
|
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
output = argv[c];
|
output = (const char*)GET_WARGV(argv, c);
|
||||||
} else if (name1 == NULL) {
|
} else if (name1 == NULL) {
|
||||||
name1 = argv[c];
|
name1 = (const char*)GET_WARGV(argv, c);
|
||||||
} else {
|
} else {
|
||||||
name2 = argv[c];
|
name2 = (const char*)GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (help || name1 == NULL || name2 == NULL) {
|
if (help || name1 == NULL || name2 == NULL) {
|
||||||
@ -347,5 +351,5 @@ int main(int argc, const char *argv[]) {
|
|||||||
End:
|
End:
|
||||||
WebPPictureFree(&pic1);
|
WebPPictureFree(&pic1);
|
||||||
WebPPictureFree(&pic2);
|
WebPPictureFree(&pic2);
|
||||||
return ret;
|
FREE_WARGV_AND_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "webp_to_sdl.h"
|
#include "webp_to_sdl.h"
|
||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "imageio/imageio_util.h"
|
#include "imageio/imageio_util.h"
|
||||||
|
#include "../examples/unicode.h"
|
||||||
|
|
||||||
#if defined(WEBP_HAVE_JUST_SDL_H)
|
#if defined(WEBP_HAVE_JUST_SDL_H)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
@ -51,29 +52,33 @@ static void ProcessEvents(void) {
|
|||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
int c;
|
int c;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
for (c = 1; c < argc; ++c) {
|
for (c = 1; c < argc; ++c) {
|
||||||
const char* file = NULL;
|
const char* file = NULL;
|
||||||
const uint8_t* webp = NULL;
|
const uint8_t* webp = NULL;
|
||||||
size_t webp_size = 0;
|
size_t webp_size = 0;
|
||||||
if (!strcmp(argv[c], "-h")) {
|
if (!strcmp(argv[c], "-h")) {
|
||||||
printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]);
|
printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]);
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else {
|
} else {
|
||||||
file = argv[c];
|
file = (const char*)GET_WARGV(argv, c);
|
||||||
}
|
}
|
||||||
if (file == NULL) continue;
|
if (file == NULL) continue;
|
||||||
if (!ImgIoUtilReadFile(file, &webp, &webp_size)) {
|
if (!ImgIoUtilReadFile(file, &webp, &webp_size)) {
|
||||||
fprintf(stderr, "Error opening file: %s\n", file);
|
WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (webp_size != (size_t)(int)webp_size) {
|
if (webp_size != (size_t)(int)webp_size) {
|
||||||
|
free((void*)webp);
|
||||||
fprintf(stderr, "File too large.\n");
|
fprintf(stderr, "File too large.\n");
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
ok = WebpToSDL((const char*)webp, (int)webp_size);
|
ok = WebpToSDL((const char*)webp, (int)webp_size);
|
||||||
free((void*)webp);
|
free((void*)webp);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Error decoding file %s\n", file);
|
WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
ProcessEvents();
|
ProcessEvents();
|
||||||
@ -82,7 +87,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
Error:
|
Error:
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return ok ? 0 : 1;
|
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_HAVE_SDL
|
#else // !WEBP_HAVE_SDL
|
||||||
|
@ -13,26 +13,30 @@
|
|||||||
|
|
||||||
#include "extras/extras.h"
|
#include "extras/extras.h"
|
||||||
#include "imageio/imageio_util.h"
|
#include "imageio/imageio_util.h"
|
||||||
|
#include "../examples/unicode.h"
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
int main(int argc, const char *argv[]) {
|
||||||
int c;
|
int c;
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
|
INIT_WARGV(argc, argv);
|
||||||
|
|
||||||
for (c = 1; ok && c < argc; ++c) {
|
for (c = 1; ok && c < argc; ++c) {
|
||||||
if (!strcmp(argv[c], "-quiet")) {
|
if (!strcmp(argv[c], "-quiet")) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
|
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
|
||||||
printf("webp_quality [-h][-quiet] webp_files...\n");
|
printf("webp_quality [-h][-quiet] webp_files...\n");
|
||||||
return 0;
|
FREE_WARGV_AND_RETURN(0);
|
||||||
} else {
|
} else {
|
||||||
const char* const filename = argv[c];
|
const char* const filename = (const char*)GET_WARGV(argv, c);
|
||||||
const uint8_t* data = NULL;
|
const uint8_t* data = NULL;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
int q;
|
int q;
|
||||||
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
if (!ok) break;
|
if (!ok) break;
|
||||||
q = VP8EstimateQuality(data, data_size);
|
q = VP8EstimateQuality(data, data_size);
|
||||||
if (!quiet) printf("[%s] ", filename);
|
if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename);
|
||||||
if (q < 0) {
|
if (q < 0) {
|
||||||
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
|
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
|
||||||
ok = 0;
|
ok = 0;
|
||||||
@ -46,5 +50,5 @@ int main(int argc, const char *argv[]) {
|
|||||||
free((void*)data);
|
free((void*)data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok ? 0 : 1;
|
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,13 @@
|
|||||||
// code with COBJMACROS.
|
// code with COBJMACROS.
|
||||||
#include <ole2.h> // CreateStreamOnHGlobal()
|
#include <ole2.h> // CreateStreamOnHGlobal()
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
#include <tchar.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wincodec.h>
|
#include <wincodec.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./imageio_util.h"
|
#include "./imageio_util.h"
|
||||||
|
#include "../examples/unicode.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// PNG
|
// PNG
|
||||||
@ -61,11 +63,12 @@ static HRESULT CreateOutputStream(const char* out_file_name,
|
|||||||
// Output to a memory buffer. This is freed when 'stream' is released.
|
// Output to a memory buffer. This is freed when 'stream' is released.
|
||||||
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
|
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
|
||||||
} else {
|
} else {
|
||||||
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
|
IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name,
|
||||||
|
STGM_WRITE | STGM_CREATE, stream));
|
||||||
}
|
}
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
fprintf(stderr, "Error opening output file %s (%08lx)\n",
|
_ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"),
|
||||||
out_file_name, hr);
|
(const LPTSTR)out_file_name, hr);
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@ -549,7 +552,8 @@ int WebPSaveImage(const WebPDecBuffer* const buffer,
|
|||||||
const char* const out_file_name) {
|
const char* const out_file_name) {
|
||||||
FILE* fout = NULL;
|
FILE* fout = NULL;
|
||||||
int needs_open_file = 1;
|
int needs_open_file = 1;
|
||||||
const int use_stdout = (out_file_name != NULL) && !strcmp(out_file_name, "-");
|
const int use_stdout =
|
||||||
|
(out_file_name != NULL) && !WSTRCMP(out_file_name, "-");
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
if (buffer == NULL || out_file_name == NULL) return 0;
|
if (buffer == NULL || out_file_name == NULL) return 0;
|
||||||
@ -560,9 +564,10 @@ int WebPSaveImage(const WebPDecBuffer* const buffer,
|
|||||||
|
|
||||||
if (needs_open_file) {
|
if (needs_open_file) {
|
||||||
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout)
|
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout)
|
||||||
: fopen(out_file_name, "wb");
|
: WFOPEN(out_file_name, "wb");
|
||||||
if (fout == NULL) {
|
if (fout == NULL) {
|
||||||
fprintf(stderr, "Error opening output file %s\n", out_file_name);
|
WFPRINTF(stderr, "Error opening output file %s\n",
|
||||||
|
(const W_CHAR*)out_file_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "../examples/unicode.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// File I/O
|
// File I/O
|
||||||
@ -73,7 +74,7 @@ int ImgIoUtilReadFile(const char* const file_name,
|
|||||||
uint8_t* file_data;
|
uint8_t* file_data;
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
FILE* in;
|
FILE* in;
|
||||||
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
|
const int from_stdin = (file_name == NULL) || !WSTRCMP(file_name, "-");
|
||||||
|
|
||||||
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
|
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
|
||||||
|
|
||||||
@ -81,9 +82,9 @@ int ImgIoUtilReadFile(const char* const file_name,
|
|||||||
*data = NULL;
|
*data = NULL;
|
||||||
*data_size = 0;
|
*data_size = 0;
|
||||||
|
|
||||||
in = fopen(file_name, "rb");
|
in = WFOPEN(file_name, "rb");
|
||||||
if (in == NULL) {
|
if (in == NULL) {
|
||||||
fprintf(stderr, "cannot open input file '%s'\n", file_name);
|
WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)file_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fseek(in, 0, SEEK_END);
|
fseek(in, 0, SEEK_END);
|
||||||
@ -93,16 +94,16 @@ int ImgIoUtilReadFile(const char* const file_name,
|
|||||||
file_data = (uint8_t*)malloc(file_size + 1);
|
file_data = (uint8_t*)malloc(file_size + 1);
|
||||||
if (file_data == NULL) {
|
if (file_data == NULL) {
|
||||||
fclose(in);
|
fclose(in);
|
||||||
fprintf(stderr, "memory allocation failure when reading file %s\n",
|
WFPRINTF(stderr, "memory allocation failure when reading file %s\n",
|
||||||
file_name);
|
(const W_CHAR*)file_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ok = (fread(file_data, file_size, 1, in) == 1);
|
ok = (fread(file_data, file_size, 1, in) == 1);
|
||||||
fclose(in);
|
fclose(in);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
|
WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n",
|
||||||
(int)file_size, file_name);
|
(int)file_size, (const W_CHAR*)file_name);
|
||||||
free(file_data);
|
free(file_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -118,14 +119,15 @@ int ImgIoUtilWriteFile(const char* const file_name,
|
|||||||
const uint8_t* data, size_t data_size) {
|
const uint8_t* data, size_t data_size) {
|
||||||
int ok;
|
int ok;
|
||||||
FILE* out;
|
FILE* out;
|
||||||
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
|
const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-");
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(file_name, "wb");
|
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
|
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
|
||||||
|
(const W_CHAR*)file_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ok = (fwrite(data, data_size, 1, out) == 1);
|
ok = (fwrite(data, data_size, 1, out) == 1);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "webp/decode.h"
|
#include "webp/decode.h"
|
||||||
#include "webp/demux.h"
|
#include "webp/demux.h"
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
|
#include "../examples/unicode.h"
|
||||||
#include "./imageio_util.h"
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PrintWebPError(const char* const in_file, int status) {
|
void PrintWebPError(const char* const in_file, int status) {
|
||||||
fprintf(stderr, "Decoding of %s failed.\n", in_file);
|
WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file);
|
||||||
fprintf(stderr, "Status: %d", status);
|
fprintf(stderr, "Status: %d", status);
|
||||||
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
|
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||||
fprintf(stderr, "(%s)", kStatusMessages[status]);
|
fprintf(stderr, "(%s)", kStatusMessages[status]);
|
||||||
|
@ -29,12 +29,14 @@
|
|||||||
// code with COBJMACROS.
|
// code with COBJMACROS.
|
||||||
#include <ole2.h> // CreateStreamOnHGlobal()
|
#include <ole2.h> // CreateStreamOnHGlobal()
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
#include <tchar.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wincodec.h>
|
#include <wincodec.h>
|
||||||
|
|
||||||
#include "webp/encode.h"
|
#include "../examples/unicode.h"
|
||||||
#include "./imageio_util.h"
|
#include "./imageio_util.h"
|
||||||
#include "./metadata.h"
|
#include "./metadata.h"
|
||||||
|
#include "webp/encode.h"
|
||||||
|
|
||||||
#define IFS(fn) \
|
#define IFS(fn) \
|
||||||
do { \
|
do { \
|
||||||
@ -85,7 +87,7 @@ WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
|
|||||||
|
|
||||||
static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!strcmp(filename, "-")) {
|
if (!WSTRCMP(filename, "-")) {
|
||||||
const uint8_t* data = NULL;
|
const uint8_t* data = NULL;
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
||||||
@ -108,11 +110,12 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
|||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
|
IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
|
_ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"),
|
||||||
|
(const LPTSTR)filename, hr);
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,7 @@ DSP_ENC_OBJS = \
|
|||||||
src/dsp/cost.o \
|
src/dsp/cost.o \
|
||||||
src/dsp/cost_mips32.o \
|
src/dsp/cost_mips32.o \
|
||||||
src/dsp/cost_mips_dsp_r2.o \
|
src/dsp/cost_mips_dsp_r2.o \
|
||||||
|
src/dsp/cost_neon.o \
|
||||||
src/dsp/cost_sse2.o \
|
src/dsp/cost_sse2.o \
|
||||||
src/dsp/enc.o \
|
src/dsp/enc.o \
|
||||||
src/dsp/enc_mips32.o \
|
src/dsp/enc_mips32.o \
|
||||||
|
12
man/cwebp.1
12
man/cwebp.1
@ -1,5 +1,5 @@
|
|||||||
.\" Hey, EMACS: -*- nroff -*-
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
.TH CWEBP 1 "January 20, 2017"
|
.TH CWEBP 1 "January 11, 2019"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
cwebp \- compress an image file to a WebP file
|
cwebp \- compress an image file to a WebP file
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -41,10 +41,12 @@ the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the
|
|||||||
\-exact option is used.
|
\-exact option is used.
|
||||||
.TP
|
.TP
|
||||||
.BI \-near_lossless " int
|
.BI \-near_lossless " int
|
||||||
Use near\-lossless image preprocessing. This option adjusts pixel values
|
Specify the level of near\-lossless image preprocessing. This option adjusts
|
||||||
to help compressibility, but has minimal impact on the visual quality.
|
pixel values to help compressibility, but has minimal impact on the visual
|
||||||
It triggers lossless compression mode automatically.
|
quality. It triggers lossless compression mode automatically. The range is 0
|
||||||
Range is 0 (maximum preprocessing) to 100 (no preprocessing, the default).
|
(maximum preprocessing) to 100 (no preprocessing, the default). The typical
|
||||||
|
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
|
||||||
|
better results.
|
||||||
.TP
|
.TP
|
||||||
.BI \-q " float
|
.BI \-q " float
|
||||||
Specify the compression factor for RGB channels between 0 and 100. The default
|
Specify the compression factor for RGB channels between 0 and 100. The default
|
||||||
|
@ -36,7 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
|
|||||||
# other than the ones listed on the command line, i.e., after linking, it will
|
# other than the ones listed on the command line, i.e., after linking, it will
|
||||||
# not have unresolved symbols. Some platforms (Windows among them) require all
|
# not have unresolved symbols. Some platforms (Windows among them) require all
|
||||||
# symbols in shared libraries to be resolved at library creation.
|
# symbols in shared libraries to be resolved at library creation.
|
||||||
libwebp_la_LDFLAGS = -no-undefined -version-info 7:3:0
|
libwebp_la_LDFLAGS = -no-undefined -version-info 7:4:0
|
||||||
libwebpincludedir = $(includedir)/webp
|
libwebpincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebp.pc
|
pkgconfig_DATA = libwebp.pc
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
|
|||||||
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
|
||||||
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
|
||||||
|
|
||||||
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 3:3:0
|
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 3:4:0
|
||||||
pkgconfig_DATA += libwebpdecoder.pc
|
pkgconfig_DATA += libwebpdecoder.pc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ extern "C" {
|
|||||||
// version numbers
|
// version numbers
|
||||||
#define DEC_MAJ_VERSION 1
|
#define DEC_MAJ_VERSION 1
|
||||||
#define DEC_MIN_VERSION 0
|
#define DEC_MIN_VERSION 0
|
||||||
#define DEC_REV_VERSION 1
|
#define DEC_REV_VERSION 2
|
||||||
|
|
||||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||||
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
||||||
|
@ -13,6 +13,6 @@ noinst_HEADERS =
|
|||||||
noinst_HEADERS += ../webp/format_constants.h
|
noinst_HEADERS += ../webp/format_constants.h
|
||||||
|
|
||||||
libwebpdemux_la_LIBADD = ../libwebp.la
|
libwebpdemux_la_LIBADD = ../libwebp.la
|
||||||
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:5:0
|
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:6:0
|
||||||
libwebpdemuxincludedir = $(includedir)/webp
|
libwebpdemuxincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebpdemux.pc
|
pkgconfig_DATA = libwebpdemux.pc
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define DMUX_MAJ_VERSION 1
|
#define DMUX_MAJ_VERSION 1
|
||||||
#define DMUX_MIN_VERSION 0
|
#define DMUX_MIN_VERSION 0
|
||||||
#define DMUX_REV_VERSION 1
|
#define DMUX_REV_VERSION 2
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t start_; // start location of the data
|
size_t start_; // start location of the data
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,0,1
|
FILEVERSION 1,0,0,2
|
||||||
PRODUCTVERSION 1,0,0,1
|
PRODUCTVERSION 1,0,0,2
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -24,12 +24,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Google, Inc."
|
VALUE "CompanyName", "Google, Inc."
|
||||||
VALUE "FileDescription", "libwebpdemux DLL"
|
VALUE "FileDescription", "libwebpdemux DLL"
|
||||||
VALUE "FileVersion", "1.0.1"
|
VALUE "FileVersion", "1.0.2"
|
||||||
VALUE "InternalName", "libwebpdemux.dll"
|
VALUE "InternalName", "libwebpdemux.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2018"
|
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||||
VALUE "OriginalFilename", "libwebpdemux.dll"
|
VALUE "OriginalFilename", "libwebpdemux.dll"
|
||||||
VALUE "ProductName", "WebP Image Demuxer"
|
VALUE "ProductName", "WebP Image Demuxer"
|
||||||
VALUE "ProductVersion", "1.0.1"
|
VALUE "ProductVersion", "1.0.2"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -40,6 +40,7 @@ ENC_SOURCES =
|
|||||||
ENC_SOURCES += cost.c
|
ENC_SOURCES += cost.c
|
||||||
ENC_SOURCES += enc.c
|
ENC_SOURCES += enc.c
|
||||||
ENC_SOURCES += lossless_enc.c
|
ENC_SOURCES += lossless_enc.c
|
||||||
|
ENC_SOURCES += quant.h
|
||||||
ENC_SOURCES += ssim.c
|
ENC_SOURCES += ssim.c
|
||||||
|
|
||||||
libwebpdspdecode_sse41_la_SOURCES =
|
libwebpdspdecode_sse41_la_SOURCES =
|
||||||
@ -121,6 +122,7 @@ libwebpdsp_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS)
|
|||||||
libwebpdsp_sse41_la_LIBADD = libwebpdspdecode_sse41.la
|
libwebpdsp_sse41_la_LIBADD = libwebpdspdecode_sse41.la
|
||||||
|
|
||||||
libwebpdsp_neon_la_SOURCES =
|
libwebpdsp_neon_la_SOURCES =
|
||||||
|
libwebpdsp_neon_la_SOURCES += cost_neon.c
|
||||||
libwebpdsp_neon_la_SOURCES += enc_neon.c
|
libwebpdsp_neon_la_SOURCES += enc_neon.c
|
||||||
libwebpdsp_neon_la_SOURCES += lossless_enc_neon.c
|
libwebpdsp_neon_la_SOURCES += lossless_enc_neon.c
|
||||||
libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
|
||||||
|
@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
|
|||||||
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* dst, int dst_stride) {
|
||||||
uint32_t alpha_mask = 0xffffffffu;
|
uint32_t alpha_mask = 0xffu;
|
||||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
uint32_t tmp[2];
|
uint32_t tmp[2];
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
|
|||||||
dst += dst_stride;
|
dst += dst_stride;
|
||||||
}
|
}
|
||||||
vst1_u8((uint8_t*)tmp, mask8);
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask *= 0x01010101;
|
||||||
alpha_mask &= tmp[0];
|
alpha_mask &= tmp[0];
|
||||||
alpha_mask &= tmp[1];
|
alpha_mask &= tmp[1];
|
||||||
return (alpha_mask != 0xffffffffu);
|
return (alpha_mask != 0xffffffffu);
|
||||||
@ -134,7 +135,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
|
|||||||
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* alpha, int alpha_stride) {
|
||||||
uint32_t alpha_mask = 0xffffffffu;
|
uint32_t alpha_mask = 0xffu;
|
||||||
uint8x8_t mask8 = vdup_n_u8(0xff);
|
uint8x8_t mask8 = vdup_n_u8(0xff);
|
||||||
uint32_t tmp[2];
|
uint32_t tmp[2];
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -156,6 +157,7 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
|
|||||||
alpha += alpha_stride;
|
alpha += alpha_stride;
|
||||||
}
|
}
|
||||||
vst1_u8((uint8_t*)tmp, mask8);
|
vst1_u8((uint8_t*)tmp, mask8);
|
||||||
|
alpha_mask *= 0x01010101;
|
||||||
alpha_mask &= tmp[0];
|
alpha_mask &= tmp[0];
|
||||||
alpha_mask &= tmp[1];
|
alpha_mask &= tmp[1];
|
||||||
return (alpha_mask == 0xffffffffu);
|
return (alpha_mask == 0xffffffffu);
|
||||||
|
@ -377,6 +377,7 @@ VP8SetResidualCoeffsFunc VP8SetResidualCoeffs;
|
|||||||
extern void VP8EncDspCostInitMIPS32(void);
|
extern void VP8EncDspCostInitMIPS32(void);
|
||||||
extern void VP8EncDspCostInitMIPSdspR2(void);
|
extern void VP8EncDspCostInitMIPSdspR2(void);
|
||||||
extern void VP8EncDspCostInitSSE2(void);
|
extern void VP8EncDspCostInitSSE2(void);
|
||||||
|
extern void VP8EncDspCostInitNEON(void);
|
||||||
|
|
||||||
WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
|
WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
|
||||||
VP8GetResidualCost = GetResidualCost_C;
|
VP8GetResidualCost = GetResidualCost_C;
|
||||||
@ -398,6 +399,11 @@ WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
|
|||||||
if (VP8GetCPUInfo(kSSE2)) {
|
if (VP8GetCPUInfo(kSSE2)) {
|
||||||
VP8EncDspCostInitSSE2();
|
VP8EncDspCostInitSSE2();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (VP8GetCPUInfo(kNEON)) {
|
||||||
|
VP8EncDspCostInitNEON();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
122
src/dsp/cost_neon.c
Normal file
122
src/dsp/cost_neon.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// 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.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ARM NEON version of cost functions
|
||||||
|
|
||||||
|
#include "src/dsp/dsp.h"
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
|
#include "src/dsp/neon.h"
|
||||||
|
#include "src/enc/cost_enc.h"
|
||||||
|
|
||||||
|
static const uint8_t position[16] = { 1, 2, 3, 4, 5, 6, 7, 8,
|
||||||
|
9, 10, 11, 12, 13, 14, 15, 16 };
|
||||||
|
|
||||||
|
static void SetResidualCoeffs_NEON(const int16_t* const coeffs,
|
||||||
|
VP8Residual* const res) {
|
||||||
|
const int16x8_t minus_one = vdupq_n_s16(-1);
|
||||||
|
const int16x8_t coeffs_0 = vld1q_s16(coeffs);
|
||||||
|
const int16x8_t coeffs_1 = vld1q_s16(coeffs + 8);
|
||||||
|
const uint16x8_t eob_0 = vtstq_s16(coeffs_0, minus_one);
|
||||||
|
const uint16x8_t eob_1 = vtstq_s16(coeffs_1, minus_one);
|
||||||
|
const uint8x16_t eob = vcombine_u8(vqmovn_u16(eob_0), vqmovn_u16(eob_1));
|
||||||
|
const uint8x16_t masked = vandq_u8(eob, vld1q_u8(position));
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
res->last = vmaxvq_u8(masked) - 1;
|
||||||
|
#else
|
||||||
|
const uint8x8_t eob_8x8 = vmax_u8(vget_low_u8(masked), vget_high_u8(masked));
|
||||||
|
const uint16x8_t eob_16x8 = vmovl_u8(eob_8x8);
|
||||||
|
const uint16x4_t eob_16x4 =
|
||||||
|
vmax_u16(vget_low_u16(eob_16x8), vget_high_u16(eob_16x8));
|
||||||
|
const uint32x4_t eob_32x4 = vmovl_u16(eob_16x4);
|
||||||
|
uint32x2_t eob_32x2 =
|
||||||
|
vmax_u32(vget_low_u32(eob_32x4), vget_high_u32(eob_32x4));
|
||||||
|
eob_32x2 = vpmax_u32(eob_32x2, eob_32x2);
|
||||||
|
|
||||||
|
vst1_lane_s32(&res->last, vreinterpret_s32_u32(eob_32x2), 0);
|
||||||
|
--res->last;
|
||||||
|
#endif // __aarch64__
|
||||||
|
|
||||||
|
res->coeffs = coeffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetResidualCost_NEON(int ctx0, const VP8Residual* const res) {
|
||||||
|
uint8_t levels[16], ctxs[16];
|
||||||
|
uint16_t abs_levels[16];
|
||||||
|
int n = res->first;
|
||||||
|
// should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
|
||||||
|
const int p0 = res->prob[n][ctx0][0];
|
||||||
|
CostArrayPtr const costs = res->costs;
|
||||||
|
const uint16_t* t = costs[n][ctx0];
|
||||||
|
// bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
|
||||||
|
// (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
|
||||||
|
// be missing during the loop.
|
||||||
|
int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
|
||||||
|
|
||||||
|
if (res->last < 0) {
|
||||||
|
return VP8BitCost(0, p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // precompute clamped levels and contexts, packed to 8b.
|
||||||
|
const uint8x16_t kCst2 = vdupq_n_u8(2);
|
||||||
|
const uint8x16_t kCst67 = vdupq_n_u8(MAX_VARIABLE_LEVEL);
|
||||||
|
const int16x8_t c0 = vld1q_s16(res->coeffs);
|
||||||
|
const int16x8_t c1 = vld1q_s16(res->coeffs + 8);
|
||||||
|
const uint16x8_t E0 = vreinterpretq_u16_s16(vabsq_s16(c0));
|
||||||
|
const uint16x8_t E1 = vreinterpretq_u16_s16(vabsq_s16(c1));
|
||||||
|
const uint8x16_t F = vcombine_u8(vqmovn_u16(E0), vqmovn_u16(E1));
|
||||||
|
const uint8x16_t G = vminq_u8(F, kCst2); // context = 0,1,2
|
||||||
|
const uint8x16_t H = vminq_u8(F, kCst67); // clamp_level in [0..67]
|
||||||
|
|
||||||
|
vst1q_u8(ctxs, G);
|
||||||
|
vst1q_u8(levels, H);
|
||||||
|
|
||||||
|
vst1q_u16(abs_levels, E0);
|
||||||
|
vst1q_u16(abs_levels + 8, E1);
|
||||||
|
}
|
||||||
|
for (; n < res->last; ++n) {
|
||||||
|
const int ctx = ctxs[n];
|
||||||
|
const int level = levels[n];
|
||||||
|
const int flevel = abs_levels[n]; // full level
|
||||||
|
cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost()
|
||||||
|
t = costs[n + 1][ctx];
|
||||||
|
}
|
||||||
|
// Last coefficient is always non-zero
|
||||||
|
{
|
||||||
|
const int level = levels[n];
|
||||||
|
const int flevel = abs_levels[n];
|
||||||
|
assert(flevel != 0);
|
||||||
|
cost += VP8LevelFixedCosts[flevel] + t[level];
|
||||||
|
if (n < 15) {
|
||||||
|
const int b = VP8EncBands[n + 1];
|
||||||
|
const int ctx = ctxs[n];
|
||||||
|
const int last_p0 = res->prob[b][ctx][0];
|
||||||
|
cost += VP8BitCost(0, last_p0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
|
extern void VP8EncDspCostInitNEON(void);
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitNEON(void) {
|
||||||
|
VP8SetResidualCoeffs = SetResidualCoeffs_NEON;
|
||||||
|
VP8GetResidualCost = GetResidualCost_NEON;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !WEBP_USE_NEON
|
||||||
|
|
||||||
|
WEBP_DSP_INIT_STUB(VP8EncDspCostInitNEON)
|
||||||
|
|
||||||
|
#endif // WEBP_USE_NEON
|
@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[],
|
|||||||
static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
|
static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
|
||||||
uint32_t* pout, int size) {
|
uint32_t* pout, int size) {
|
||||||
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
|
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
|
||||||
const uint32_t end = ((size) / 4) * 4;
|
const int end = ((size) / 4) * 4;
|
||||||
const uint32_t* const LoopEnd = pa + end;
|
const uint32_t* const LoopEnd = pa + end;
|
||||||
int i;
|
int i;
|
||||||
ASM_START
|
ASM_START
|
||||||
ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
|
ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
|
||||||
ASM_END_0
|
ASM_END_0
|
||||||
for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i];
|
for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
|
static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
|
||||||
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
|
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
|
||||||
const uint32_t end = ((size) / 4) * 4;
|
const int end = ((size) / 4) * 4;
|
||||||
const uint32_t* const LoopEnd = pa + end;
|
const uint32_t* const LoopEnd = pa + end;
|
||||||
int i;
|
int i;
|
||||||
ASM_START
|
ASM_START
|
||||||
ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
|
ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
|
||||||
ASM_END_1
|
ASM_END_1
|
||||||
for (i = end; i < size; ++i) pout[i] += pa[i];
|
for (i = 0; i < size - end; ++i) pout[i] += pa[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ASM_END_1
|
#undef ASM_END_1
|
||||||
|
70
src/dsp/quant.h
Normal file
70
src/dsp/quant.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef WEBP_DSP_QUANT_H_
|
||||||
|
#define WEBP_DSP_QUANT_H_
|
||||||
|
|
||||||
|
#include "src/dsp/dsp.h"
|
||||||
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && \
|
||||||
|
!defined(WEBP_HAVE_NEON_RTCD)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
|
||||||
|
#define IsFlat IsFlat_NEON
|
||||||
|
|
||||||
|
static uint32x2_t horizontal_add_uint32x4(const uint32x4_t a) {
|
||||||
|
const uint64x2_t b = vpaddlq_u32(a);
|
||||||
|
return vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)),
|
||||||
|
vreinterpret_u32_u64(vget_high_u64(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
|
||||||
|
int thresh) {
|
||||||
|
const int16x8_t tst_ones = vdupq_n_s16(-1);
|
||||||
|
uint32x4_t sum = vdupq_n_u32(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_blocks; ++i) {
|
||||||
|
// Set DC to zero.
|
||||||
|
const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0);
|
||||||
|
const int16x8_t a_1 = vld1q_s16(levels + 8);
|
||||||
|
|
||||||
|
const uint16x8_t b_0 = vshrq_n_u16(vtstq_s16(a_0, tst_ones), 15);
|
||||||
|
const uint16x8_t b_1 = vshrq_n_u16(vtstq_s16(a_1, tst_ones), 15);
|
||||||
|
|
||||||
|
sum = vpadalq_u16(sum, b_0);
|
||||||
|
sum = vpadalq_u16(sum, b_1);
|
||||||
|
|
||||||
|
levels += 16;
|
||||||
|
}
|
||||||
|
return thresh >= (int32_t)vget_lane_u32(horizontal_add_uint32x4(sum), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define IsFlat IsFlat_C
|
||||||
|
|
||||||
|
static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
|
||||||
|
int thresh) {
|
||||||
|
int score = 0;
|
||||||
|
while (num_blocks-- > 0) { // TODO(skal): refine positional scoring?
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC
|
||||||
|
score += (levels[i] != 0);
|
||||||
|
if (score > thresh) return 0;
|
||||||
|
}
|
||||||
|
levels += 16;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) &&
|
||||||
|
// !defined(WEBP_HAVE_NEON_RTCD)
|
||||||
|
|
||||||
|
#endif // WEBP_DSP_QUANT_H_
|
@ -109,8 +109,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
|
|||||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t J = frow[x_out];
|
const uint32_t J = frow[x_out];
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||||
@ -120,8 +119,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
|
|||||||
+ (uint64_t)B * irow[x_out];
|
+ (uint64_t)B * irow[x_out];
|
||||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,17 +136,15 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
|
|||||||
assert(!wrk->y_expand);
|
assert(!wrk->y_expand);
|
||||||
if (yscale) {
|
if (yscale) {
|
||||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
|
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = frac; // new fractional start
|
irow[x_out] = frac; // new fractional start
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||||
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = 0;
|
irow[x_out] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,9 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||||
const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
|
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(*frow++, yscale);
|
||||||
const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale);
|
const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||||
*dst++ = v;
|
|
||||||
*irow++ = frac; // new fractional start
|
*irow++ = frac; // new fractional start
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -157,8 +156,7 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
|
|||||||
}
|
}
|
||||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||||
const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
|
const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||||
*dst++ = v;
|
|
||||||
*irow++ = 0;
|
*irow++ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,8 +217,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
|
|||||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||||
const uint32_t J = *frow++;
|
const uint32_t J = *frow++;
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||||
*dst++ = v;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||||
@ -291,8 +288,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
|
|||||||
+ (uint64_t)B * *irow++;
|
+ (uint64_t)B * *irow++;
|
||||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||||
*dst++ = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,8 +166,7 @@ static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst,
|
|||||||
for (x_out = 0; x_out < length; ++x_out) {
|
for (x_out = 0; x_out < length; ++x_out) {
|
||||||
const uint32_t J = frow[x_out];
|
const uint32_t J = frow[x_out];
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,8 +240,7 @@ static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow,
|
|||||||
+ (uint64_t)B * irow[x_out];
|
+ (uint64_t)B * irow[x_out];
|
||||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,10 +340,9 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
|
|||||||
length -= 4;
|
length -= 4;
|
||||||
}
|
}
|
||||||
for (x_out = 0; x_out < length; ++x_out) {
|
for (x_out = 0; x_out < length; ++x_out) {
|
||||||
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
|
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = frac;
|
irow[x_out] = frac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,8 +403,7 @@ static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst,
|
|||||||
}
|
}
|
||||||
for (x_out = 0; x_out < length; ++x_out) {
|
for (x_out = 0; x_out < length; ++x_out) {
|
||||||
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = 0;
|
irow[x_out] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,14 +81,13 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
|||||||
const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half);
|
const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half);
|
||||||
const uint16x4_t C0 = vmovn_u32(B0);
|
const uint16x4_t C0 = vmovn_u32(B0);
|
||||||
const uint16x4_t C1 = vmovn_u32(B1);
|
const uint16x4_t C1 = vmovn_u32(B1);
|
||||||
const uint8x8_t D = vmovn_u16(vcombine_u16(C0, C1));
|
const uint8x8_t D = vqmovn_u16(vcombine_u16(C0, C1));
|
||||||
vst1_u8(dst + x_out, D);
|
vst1_u8(dst + x_out, D);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t J = frow[x_out];
|
const uint32_t J = frow[x_out];
|
||||||
const int v = (int)MULT_FIX_C(J, fy_scale);
|
const int v = (int)MULT_FIX_C(J, fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||||
@ -102,7 +101,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
|||||||
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
|
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
|
||||||
const uint16x4_t E0 = vmovn_u32(D0);
|
const uint16x4_t E0 = vmovn_u32(D0);
|
||||||
const uint16x4_t E1 = vmovn_u32(D1);
|
const uint16x4_t E1 = vmovn_u32(D1);
|
||||||
const uint8x8_t F = vmovn_u16(vcombine_u16(E0, E1));
|
const uint8x8_t F = vqmovn_u16(vcombine_u16(E0, E1));
|
||||||
vst1_u8(dst + x_out, F);
|
vst1_u8(dst + x_out, F);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
@ -110,8 +109,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
|||||||
+ (uint64_t)B * irow[x_out];
|
+ (uint64_t)B * irow[x_out];
|
||||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||||
const int v = (int)MULT_FIX_C(J, fy_scale);
|
const int v = (int)MULT_FIX_C(J, fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,23 +133,22 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
|
|||||||
for (x_out = 0; x_out < max_span; x_out += 8) {
|
for (x_out = 0; x_out < max_span; x_out += 8) {
|
||||||
LOAD_32x8(frow + x_out, in0, in1);
|
LOAD_32x8(frow + x_out, in0, in1);
|
||||||
LOAD_32x8(irow + x_out, in2, in3);
|
LOAD_32x8(irow + x_out, in2, in3);
|
||||||
const uint32x4_t A0 = MULT_FIX(in0, yscale_half);
|
const uint32x4_t A0 = MULT_FIX_FLOOR(in0, yscale_half);
|
||||||
const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
|
const uint32x4_t A1 = MULT_FIX_FLOOR(in1, yscale_half);
|
||||||
const uint32x4_t B0 = vqsubq_u32(in2, A0);
|
const uint32x4_t B0 = vqsubq_u32(in2, A0);
|
||||||
const uint32x4_t B1 = vqsubq_u32(in3, A1);
|
const uint32x4_t B1 = vqsubq_u32(in3, A1);
|
||||||
const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
|
const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
|
||||||
const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half);
|
const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
|
||||||
const uint16x4_t D0 = vmovn_u32(C0);
|
const uint16x4_t D0 = vmovn_u32(C0);
|
||||||
const uint16x4_t D1 = vmovn_u32(C1);
|
const uint16x4_t D1 = vmovn_u32(C1);
|
||||||
const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
|
const uint8x8_t E = vqmovn_u16(vcombine_u16(D0, D1));
|
||||||
vst1_u8(dst + x_out, E);
|
vst1_u8(dst + x_out, E);
|
||||||
STORE_32x8(A0, A1, irow + x_out);
|
STORE_32x8(A0, A1, irow + x_out);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
|
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR_C(frow[x_out], yscale);
|
||||||
const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
|
const int v = (int)MULT_FIX_C(irow[x_out] - frac, fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = frac; // new fractional start
|
irow[x_out] = frac; // new fractional start
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -161,14 +158,13 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
|
|||||||
const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half);
|
const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half);
|
||||||
const uint16x4_t B0 = vmovn_u32(A0);
|
const uint16x4_t B0 = vmovn_u32(A0);
|
||||||
const uint16x4_t B1 = vmovn_u32(A1);
|
const uint16x4_t B1 = vmovn_u32(A1);
|
||||||
const uint8x8_t C = vmovn_u16(vcombine_u16(B0, B1));
|
const uint8x8_t C = vqmovn_u16(vcombine_u16(B0, B1));
|
||||||
vst1_u8(dst + x_out, C);
|
vst1_u8(dst + x_out, C);
|
||||||
STORE_32x8(zero, zero, irow + x_out);
|
STORE_32x8(zero, zero, irow + x_out);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
|
const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = 0;
|
irow[x_out] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,35 +225,6 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
|
|||||||
_mm_storel_epi64((__m128i*)dst, G);
|
_mm_storel_epi64((__m128i*)dst, G);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
|
|
||||||
const __m128i* const A1,
|
|
||||||
const __m128i* const A2,
|
|
||||||
const __m128i* const A3,
|
|
||||||
const __m128i* const mult,
|
|
||||||
uint8_t* const dst) {
|
|
||||||
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
|
|
||||||
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
|
|
||||||
const __m128i B1 = _mm_mul_epu32(*A1, *mult);
|
|
||||||
const __m128i B2 = _mm_mul_epu32(*A2, *mult);
|
|
||||||
const __m128i B3 = _mm_mul_epu32(*A3, *mult);
|
|
||||||
const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
|
|
||||||
const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
|
|
||||||
#if (WEBP_RESCALER_RFIX < 32)
|
|
||||||
const __m128i D2 =
|
|
||||||
_mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
|
|
||||||
const __m128i D3 =
|
|
||||||
_mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
|
|
||||||
#else
|
|
||||||
const __m128i D2 = _mm_and_si128(B2, mask);
|
|
||||||
const __m128i D3 = _mm_and_si128(B3, mask);
|
|
||||||
#endif
|
|
||||||
const __m128i E0 = _mm_or_si128(D0, D2);
|
|
||||||
const __m128i E1 = _mm_or_si128(D1, D3);
|
|
||||||
const __m128i F = _mm_packs_epi32(E0, E1);
|
|
||||||
const __m128i G = _mm_packus_epi16(F, F);
|
|
||||||
_mm_storel_epi64((__m128i*)dst, G);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
@ -274,8 +245,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
|||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t J = frow[x_out];
|
const uint32_t J = frow[x_out];
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||||
@ -308,8 +278,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
|||||||
+ (uint64_t)B * irow[x_out];
|
+ (uint64_t)B * irow[x_out];
|
||||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,20 +297,15 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
|||||||
const int scale_xy = wrk->fxy_scale;
|
const int scale_xy = wrk->fxy_scale;
|
||||||
const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy);
|
const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy);
|
||||||
const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale);
|
const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale);
|
||||||
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
|
||||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||||
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
||||||
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
||||||
LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
|
LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
|
||||||
{
|
{
|
||||||
const __m128i C0 = _mm_add_epi64(B0, rounder);
|
const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX); // = frac
|
||||||
const __m128i C1 = _mm_add_epi64(B1, rounder);
|
const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
|
||||||
const __m128i C2 = _mm_add_epi64(B2, rounder);
|
const __m128i D2 = _mm_srli_epi64(B2, WEBP_RESCALER_RFIX);
|
||||||
const __m128i C3 = _mm_add_epi64(B3, rounder);
|
const __m128i D3 = _mm_srli_epi64(B3, WEBP_RESCALER_RFIX);
|
||||||
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX); // = frac
|
|
||||||
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
|
|
||||||
const __m128i D2 = _mm_srli_epi64(C2, WEBP_RESCALER_RFIX);
|
|
||||||
const __m128i D3 = _mm_srli_epi64(C3, WEBP_RESCALER_RFIX);
|
|
||||||
const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac
|
const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac
|
||||||
const __m128i E1 = _mm_sub_epi64(A1, D1);
|
const __m128i E1 = _mm_sub_epi64(A1, D1);
|
||||||
const __m128i E2 = _mm_sub_epi64(A2, D2);
|
const __m128i E2 = _mm_sub_epi64(A2, D2);
|
||||||
@ -352,14 +316,13 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
|||||||
const __m128i G1 = _mm_or_si128(D1, F3);
|
const __m128i G1 = _mm_or_si128(D1, F3);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
|
||||||
ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
|
const uint32_t frac = (int)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = frac; // new fractional start
|
irow[x_out] = frac; // new fractional start
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -375,8 +338,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
|||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const int v = (int)MULT_FIX(irow[x_out], scale);
|
const int v = (int)MULT_FIX(irow[x_out], scale);
|
||||||
assert(v >= 0 && v <= 255);
|
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||||
dst[x_out] = v;
|
|
||||||
irow[x_out] = 0;
|
irow[x_out] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,7 +577,7 @@ static int BackwardReferencesHashChainDistanceOnly(
|
|||||||
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
|
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
|
||||||
VP8LColorCache hashers;
|
VP8LColorCache hashers;
|
||||||
CostManager* cost_manager =
|
CostManager* cost_manager =
|
||||||
(CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager));
|
(CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager));
|
||||||
int offset_prev = -1, len_prev = -1;
|
int offset_prev = -1, len_prev = -1;
|
||||||
double offset_cost = -1;
|
double offset_cost = -1;
|
||||||
int first_offset_is_constant = -1; // initialized with 'impossible' value
|
int first_offset_is_constant = -1; // initialized with 'impossible' value
|
||||||
|
@ -911,13 +911,14 @@ static VP8LBackwardRefs* GetBackwardReferences(
|
|||||||
quality >= 25) {
|
quality >= 25) {
|
||||||
const VP8LHashChain* const hash_chain_tmp =
|
const VP8LHashChain* const hash_chain_tmp =
|
||||||
(lz77_type_best == kLZ77Standard) ? hash_chain : &hash_chain_box;
|
(lz77_type_best == kLZ77Standard) ? hash_chain : &hash_chain_box;
|
||||||
if (VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits,
|
double bit_cost_trace;
|
||||||
hash_chain_tmp, best, worst)) {
|
if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits,
|
||||||
double bit_cost_trace;
|
hash_chain_tmp, best, worst)) {
|
||||||
VP8LHistogramCreate(histo, worst, *cache_bits);
|
goto Error;
|
||||||
bit_cost_trace = VP8LHistogramEstimateBits(histo);
|
|
||||||
if (bit_cost_trace < bit_cost_best) best = worst;
|
|
||||||
}
|
}
|
||||||
|
VP8LHistogramCreate(histo, worst, *cache_bits);
|
||||||
|
bit_cost_trace = VP8LHistogramEstimateBits(histo);
|
||||||
|
if (bit_cost_trace < bit_cost_best) best = worst;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackwardReferences2DLocality(width, best);
|
BackwardReferences2DLocality(width, best);
|
||||||
|
@ -165,7 +165,7 @@ VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
|
|||||||
void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
|
void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
|
||||||
int i;
|
int i;
|
||||||
const int cache_bits = set->histograms[0]->palette_code_bits_;
|
const int cache_bits = set->histograms[0]->palette_code_bits_;
|
||||||
const int size = set->size;
|
const int size = set->max_size;
|
||||||
const size_t total_size = HistogramSetTotalSize(size, cache_bits);
|
const size_t total_size = HistogramSetTotalSize(size, cache_bits);
|
||||||
uint8_t* memory = (uint8_t*)set;
|
uint8_t* memory = (uint8_t*)set;
|
||||||
|
|
||||||
@ -180,6 +180,20 @@ void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removes the histogram 'i' from 'set' by setting it to NULL.
|
||||||
|
static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i,
|
||||||
|
int* const num_used) {
|
||||||
|
assert(set->histograms[i] != NULL);
|
||||||
|
set->histograms[i] = NULL;
|
||||||
|
--*num_used;
|
||||||
|
// If we remove the last valid one, shrink until the next valid one.
|
||||||
|
if (i == set->size - 1) {
|
||||||
|
while (set->size >= 1 && set->histograms[set->size - 1] == NULL) {
|
||||||
|
--set->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
||||||
@ -447,7 +461,9 @@ static double HistogramAddEval(const VP8LHistogram* const a,
|
|||||||
static double HistogramAddThresh(const VP8LHistogram* const a,
|
static double HistogramAddThresh(const VP8LHistogram* const a,
|
||||||
const VP8LHistogram* const b,
|
const VP8LHistogram* const b,
|
||||||
double cost_threshold) {
|
double cost_threshold) {
|
||||||
double cost = -a->bit_cost_;
|
double cost;
|
||||||
|
assert(a != NULL && b != NULL);
|
||||||
|
cost = -a->bit_cost_;
|
||||||
GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
|
GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
@ -561,14 +577,17 @@ static void HistogramBuild(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copies the histograms and computes its bit_cost.
|
// Copies the histograms and computes its bit_cost.
|
||||||
static void HistogramCopyAndAnalyze(
|
static const uint16_t kInvalidHistogramSymbol = (uint16_t)(-1);
|
||||||
VP8LHistogramSet* const orig_histo, VP8LHistogramSet* const image_histo) {
|
static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo,
|
||||||
int i;
|
VP8LHistogramSet* const image_histo,
|
||||||
const int histo_size = orig_histo->size;
|
int* const num_used,
|
||||||
|
uint16_t* const histogram_symbols) {
|
||||||
|
int i, cluster_id;
|
||||||
|
int num_used_orig = *num_used;
|
||||||
VP8LHistogram** const orig_histograms = orig_histo->histograms;
|
VP8LHistogram** const orig_histograms = orig_histo->histograms;
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
image_histo->size = 0;
|
assert(image_histo->max_size == orig_histo->max_size);
|
||||||
for (i = 0; i < histo_size; ++i) {
|
for (cluster_id = 0, i = 0; i < orig_histo->max_size; ++i) {
|
||||||
VP8LHistogram* const histo = orig_histograms[i];
|
VP8LHistogram* const histo = orig_histograms[i];
|
||||||
UpdateHistogramCost(histo);
|
UpdateHistogramCost(histo);
|
||||||
|
|
||||||
@ -576,10 +595,19 @@ static void HistogramCopyAndAnalyze(
|
|||||||
// with no information (when they are skipped because of LZ77).
|
// with no information (when they are skipped because of LZ77).
|
||||||
if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2]
|
if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2]
|
||||||
&& !histo->is_used_[3] && !histo->is_used_[4]) {
|
&& !histo->is_used_[3] && !histo->is_used_[4]) {
|
||||||
continue;
|
// The first histogram is always used. If an histogram is empty, we set
|
||||||
|
// its id to be the same as the previous one: this will improve
|
||||||
|
// compressibility for later LZ77.
|
||||||
|
assert(i > 0);
|
||||||
|
HistogramSetRemoveHistogram(image_histo, i, num_used);
|
||||||
|
HistogramSetRemoveHistogram(orig_histo, i, &num_used_orig);
|
||||||
|
histogram_symbols[i] = kInvalidHistogramSymbol;
|
||||||
|
} else {
|
||||||
|
// Copy histograms from orig_histo[] to image_histo[].
|
||||||
|
HistogramCopy(histo, histograms[i]);
|
||||||
|
histogram_symbols[i] = cluster_id++;
|
||||||
|
assert(cluster_id <= image_histo->max_size);
|
||||||
}
|
}
|
||||||
// Copy histograms from orig_histo[] to image_histo[].
|
|
||||||
HistogramCopy(histo, histograms[image_histo->size++]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,29 +624,33 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
|
|||||||
|
|
||||||
// Analyze the dominant (literal, red and blue) entropy costs.
|
// Analyze the dominant (literal, red and blue) entropy costs.
|
||||||
for (i = 0; i < histo_size; ++i) {
|
for (i = 0; i < histo_size; ++i) {
|
||||||
|
if (histograms[i] == NULL) continue;
|
||||||
UpdateDominantCostRange(histograms[i], &cost_range);
|
UpdateDominantCostRange(histograms[i], &cost_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bin-hash histograms on three of the dominant (literal, red and blue)
|
// bin-hash histograms on three of the dominant (literal, red and blue)
|
||||||
// symbol costs and store the resulting bin_id for each histogram.
|
// symbol costs and store the resulting bin_id for each histogram.
|
||||||
for (i = 0; i < histo_size; ++i) {
|
for (i = 0; i < histo_size; ++i) {
|
||||||
|
// bin_map[i] is not set to a special value as its use will later be guarded
|
||||||
|
// by another (histograms[i] == NULL).
|
||||||
|
if (histograms[i] == NULL) continue;
|
||||||
bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort);
|
bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact image_histo[] by merging some histograms with same bin_id together if
|
// Merges some histograms with same bin_id together if it's advantageous.
|
||||||
// it's advantageous.
|
// Sets the remaining histograms to NULL.
|
||||||
static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
|
static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
|
||||||
|
int *num_used,
|
||||||
|
const uint16_t* const clusters,
|
||||||
|
uint16_t* const cluster_mappings,
|
||||||
VP8LHistogram* cur_combo,
|
VP8LHistogram* cur_combo,
|
||||||
const uint16_t* const bin_map,
|
const uint16_t* const bin_map,
|
||||||
int bin_map_size, int num_bins,
|
int num_bins,
|
||||||
double combine_cost_factor,
|
double combine_cost_factor,
|
||||||
int low_effort) {
|
int low_effort) {
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
int idx;
|
int idx;
|
||||||
// Work in-place: processed histograms are put at the beginning of
|
|
||||||
// image_histo[]. At the end, we just have to truncate the array.
|
|
||||||
int size = 0;
|
|
||||||
struct {
|
struct {
|
||||||
int16_t first; // position of the histogram that accumulates all
|
int16_t first; // position of the histogram that accumulates all
|
||||||
// histograms with the same bin_id
|
// histograms with the same bin_id
|
||||||
@ -631,16 +663,19 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
|
|||||||
bin_info[idx].num_combine_failures = 0;
|
bin_info[idx].num_combine_failures = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (idx = 0; idx < bin_map_size; ++idx) {
|
// By default, a cluster matches itself.
|
||||||
const int bin_id = bin_map[idx];
|
for (idx = 0; idx < *num_used; ++idx) cluster_mappings[idx] = idx;
|
||||||
const int first = bin_info[bin_id].first;
|
for (idx = 0; idx < image_histo->size; ++idx) {
|
||||||
assert(size <= idx);
|
int bin_id, first;
|
||||||
|
if (histograms[idx] == NULL) continue;
|
||||||
|
bin_id = bin_map[idx];
|
||||||
|
first = bin_info[bin_id].first;
|
||||||
if (first == -1) {
|
if (first == -1) {
|
||||||
// just move histogram #idx to its final position
|
bin_info[bin_id].first = idx;
|
||||||
histograms[size] = histograms[idx];
|
|
||||||
bin_info[bin_id].first = size++;
|
|
||||||
} else if (low_effort) {
|
} else if (low_effort) {
|
||||||
HistogramAdd(histograms[idx], histograms[first], histograms[first]);
|
HistogramAdd(histograms[idx], histograms[first], histograms[first]);
|
||||||
|
HistogramSetRemoveHistogram(image_histo, idx, num_used);
|
||||||
|
cluster_mappings[clusters[idx]] = clusters[first];
|
||||||
} else {
|
} else {
|
||||||
// try to merge #idx into #first (both share the same bin_id)
|
// try to merge #idx into #first (both share the same bin_id)
|
||||||
const double bit_cost = histograms[idx]->bit_cost_;
|
const double bit_cost = histograms[idx]->bit_cost_;
|
||||||
@ -663,19 +698,18 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
|
|||||||
bin_info[bin_id].num_combine_failures >= max_combine_failures) {
|
bin_info[bin_id].num_combine_failures >= max_combine_failures) {
|
||||||
// move the (better) merged histogram to its final slot
|
// move the (better) merged histogram to its final slot
|
||||||
HistogramSwap(&cur_combo, &histograms[first]);
|
HistogramSwap(&cur_combo, &histograms[first]);
|
||||||
|
HistogramSetRemoveHistogram(image_histo, idx, num_used);
|
||||||
|
cluster_mappings[clusters[idx]] = clusters[first];
|
||||||
} else {
|
} else {
|
||||||
histograms[size++] = histograms[idx];
|
|
||||||
++bin_info[bin_id].num_combine_failures;
|
++bin_info[bin_id].num_combine_failures;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
histograms[size++] = histograms[idx];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
image_histo->size = size;
|
|
||||||
if (low_effort) {
|
if (low_effort) {
|
||||||
// for low_effort case, update the final cost when everything is merged
|
// for low_effort case, update the final cost when everything is merged
|
||||||
for (idx = 0; idx < size; ++idx) {
|
for (idx = 0; idx < image_histo->size; ++idx) {
|
||||||
|
if (histograms[idx] == NULL) continue;
|
||||||
UpdateHistogramCost(histograms[idx]);
|
UpdateHistogramCost(histograms[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,16 +740,9 @@ typedef struct {
|
|||||||
int max_size;
|
int max_size;
|
||||||
} HistoQueue;
|
} HistoQueue;
|
||||||
|
|
||||||
static int HistoQueueInit(HistoQueue* const histo_queue, const int max_index) {
|
static int HistoQueueInit(HistoQueue* const histo_queue, const int max_size) {
|
||||||
histo_queue->size = 0;
|
histo_queue->size = 0;
|
||||||
// max_index^2 for the queue size is safe. If you look at
|
histo_queue->max_size = max_size;
|
||||||
// HistogramCombineGreedy, and imagine that UpdateQueueFront always pushes
|
|
||||||
// data to the queue, you insert at most:
|
|
||||||
// - max_index*(max_index-1)/2 (the first two for loops)
|
|
||||||
// - max_index - 1 in the last for loop at the first iteration of the while
|
|
||||||
// loop, max_index - 2 at the second iteration ... therefore
|
|
||||||
// max_index*(max_index-1)/2 overall too
|
|
||||||
histo_queue->max_size = max_index * max_index;
|
|
||||||
// We allocate max_size + 1 because the last element at index "size" is
|
// We allocate max_size + 1 because the last element at index "size" is
|
||||||
// used as temporary data (and it could be up to max_size).
|
// used as temporary data (and it could be up to max_size).
|
||||||
histo_queue->queue = (HistogramPair*)WebPSafeMalloc(
|
histo_queue->queue = (HistogramPair*)WebPSafeMalloc(
|
||||||
@ -778,6 +805,8 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
|
|||||||
const VP8LHistogram* h2;
|
const VP8LHistogram* h2;
|
||||||
HistogramPair pair;
|
HistogramPair pair;
|
||||||
|
|
||||||
|
// Stop here if the queue is full.
|
||||||
|
if (histo_queue->size == histo_queue->max_size) return 0.;
|
||||||
assert(threshold <= 0.);
|
assert(threshold <= 0.);
|
||||||
if (idx1 > idx2) {
|
if (idx1 > idx2) {
|
||||||
const int tmp = idx2;
|
const int tmp = idx2;
|
||||||
@ -794,8 +823,6 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
|
|||||||
// Do not even consider the pair if it does not improve the entropy.
|
// Do not even consider the pair if it does not improve the entropy.
|
||||||
if (pair.cost_diff >= threshold) return 0.;
|
if (pair.cost_diff >= threshold) return 0.;
|
||||||
|
|
||||||
// We cannot add more elements than the capacity.
|
|
||||||
assert(histo_queue->size < histo_queue->max_size);
|
|
||||||
histo_queue->queue[histo_queue->size++] = pair;
|
histo_queue->queue[histo_queue->size++] = pair;
|
||||||
HistoQueueUpdateHead(histo_queue, &histo_queue->queue[histo_queue->size - 1]);
|
HistoQueueUpdateHead(histo_queue, &histo_queue->queue[histo_queue->size - 1]);
|
||||||
|
|
||||||
@ -806,42 +833,43 @@ static double HistoQueuePush(HistoQueue* const histo_queue,
|
|||||||
|
|
||||||
// Combines histograms by continuously choosing the one with the highest cost
|
// Combines histograms by continuously choosing the one with the highest cost
|
||||||
// reduction.
|
// reduction.
|
||||||
static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
|
static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
|
||||||
|
int* const num_used) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int image_histo_size = image_histo->size;
|
const int image_histo_size = image_histo->size;
|
||||||
int i, j;
|
int i, j;
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
// Indexes of remaining histograms.
|
|
||||||
int* const clusters =
|
|
||||||
(int*)WebPSafeMalloc(image_histo_size, sizeof(*clusters));
|
|
||||||
// Priority queue of histogram pairs.
|
// Priority queue of histogram pairs.
|
||||||
HistoQueue histo_queue;
|
HistoQueue histo_queue;
|
||||||
|
|
||||||
if (!HistoQueueInit(&histo_queue, image_histo_size) || clusters == NULL) {
|
// image_histo_size^2 for the queue size is safe. If you look at
|
||||||
|
// HistogramCombineGreedy, and imagine that UpdateQueueFront always pushes
|
||||||
|
// data to the queue, you insert at most:
|
||||||
|
// - image_histo_size*(image_histo_size-1)/2 (the first two for loops)
|
||||||
|
// - image_histo_size - 1 in the last for loop at the first iteration of
|
||||||
|
// the while loop, image_histo_size - 2 at the second iteration ...
|
||||||
|
// therefore image_histo_size*(image_histo_size-1)/2 overall too
|
||||||
|
if (!HistoQueueInit(&histo_queue, image_histo_size * image_histo_size)) {
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < image_histo_size; ++i) {
|
for (i = 0; i < image_histo_size; ++i) {
|
||||||
// Initialize clusters indexes.
|
if (image_histo->histograms[i] == NULL) continue;
|
||||||
clusters[i] = i;
|
|
||||||
for (j = i + 1; j < image_histo_size; ++j) {
|
for (j = i + 1; j < image_histo_size; ++j) {
|
||||||
// Initialize positions array.
|
// Initialize queue.
|
||||||
|
if (image_histo->histograms[j] == NULL) continue;
|
||||||
HistoQueuePush(&histo_queue, histograms, i, j, 0.);
|
HistoQueuePush(&histo_queue, histograms, i, j, 0.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (image_histo_size > 1 && histo_queue.size > 0) {
|
while (histo_queue.size > 0) {
|
||||||
const int idx1 = histo_queue.queue[0].idx1;
|
const int idx1 = histo_queue.queue[0].idx1;
|
||||||
const int idx2 = histo_queue.queue[0].idx2;
|
const int idx2 = histo_queue.queue[0].idx2;
|
||||||
HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]);
|
HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]);
|
||||||
histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo;
|
histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo;
|
||||||
|
|
||||||
// Remove merged histogram.
|
// Remove merged histogram.
|
||||||
for (i = 0; i + 1 < image_histo_size; ++i) {
|
HistogramSetRemoveHistogram(image_histo, idx2, num_used);
|
||||||
if (clusters[i] >= idx2) {
|
|
||||||
clusters[i] = clusters[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--image_histo_size;
|
|
||||||
|
|
||||||
// Remove pairs intersecting the just combined best pair.
|
// Remove pairs intersecting the just combined best pair.
|
||||||
for (i = 0; i < histo_queue.size;) {
|
for (i = 0; i < histo_queue.size;) {
|
||||||
@ -856,24 +884,15 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push new pairs formed with combined histogram to the queue.
|
// Push new pairs formed with combined histogram to the queue.
|
||||||
for (i = 0; i < image_histo_size; ++i) {
|
for (i = 0; i < image_histo->size; ++i) {
|
||||||
if (clusters[i] != idx1) {
|
if (i == idx1 || image_histo->histograms[i] == NULL) continue;
|
||||||
HistoQueuePush(&histo_queue, histograms, idx1, clusters[i], 0.);
|
HistoQueuePush(&histo_queue, image_histo->histograms, idx1, i, 0.);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move remaining histograms to the beginning of the array.
|
|
||||||
for (i = 0; i < image_histo_size; ++i) {
|
|
||||||
if (i != clusters[i]) { // swap the two histograms
|
|
||||||
HistogramSwap(&histograms[i], &histograms[clusters[i]]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image_histo->size = image_histo_size;
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
End:
|
End:
|
||||||
WebPSafeFree(clusters);
|
|
||||||
HistoQueueClear(&histo_queue);
|
HistoQueueClear(&histo_queue);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -881,47 +900,68 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
|
|||||||
// Perform histogram aggregation using a stochastic approach.
|
// Perform histogram aggregation using a stochastic approach.
|
||||||
// 'do_greedy' is set to 1 if a greedy approach needs to be performed
|
// 'do_greedy' is set to 1 if a greedy approach needs to be performed
|
||||||
// afterwards, 0 otherwise.
|
// afterwards, 0 otherwise.
|
||||||
|
static int PairComparison(const void* idx1, const void* idx2) {
|
||||||
|
// To be used with bsearch: <0 when *idx1<*idx2, >0 if >, 0 when ==.
|
||||||
|
return (*(int*) idx1 - *(int*) idx2);
|
||||||
|
}
|
||||||
static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
||||||
int min_cluster_size,
|
int* const num_used, int min_cluster_size,
|
||||||
int* const do_greedy) {
|
int* const do_greedy) {
|
||||||
int iter;
|
int j, iter;
|
||||||
uint32_t seed = 1;
|
uint32_t seed = 1;
|
||||||
int tries_with_no_success = 0;
|
int tries_with_no_success = 0;
|
||||||
int image_histo_size = image_histo->size;
|
const int outer_iters = *num_used;
|
||||||
const int outer_iters = image_histo_size;
|
|
||||||
const int num_tries_no_success = outer_iters / 2;
|
const int num_tries_no_success = outer_iters / 2;
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
// Priority queue of histogram pairs. Its size of "kCostHeapSizeSqrt"^2
|
// Priority queue of histogram pairs. Its size of 'kHistoQueueSize'
|
||||||
// impacts the quality of the compression and the speed: the smaller the
|
// impacts the quality of the compression and the speed: the smaller the
|
||||||
// faster but the worse for the compression.
|
// faster but the worse for the compression.
|
||||||
HistoQueue histo_queue;
|
HistoQueue histo_queue;
|
||||||
const int kHistoQueueSizeSqrt = 3;
|
const int kHistoQueueSize = 9;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
// mapping from an index in image_histo with no NULL histogram to the full
|
||||||
|
// blown image_histo.
|
||||||
|
int* mappings;
|
||||||
|
|
||||||
if (!HistoQueueInit(&histo_queue, kHistoQueueSizeSqrt)) {
|
if (*num_used < min_cluster_size) {
|
||||||
goto End;
|
*do_greedy = 1;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings));
|
||||||
|
if (mappings == NULL) return 0;
|
||||||
|
if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End;
|
||||||
|
// Fill the initial mapping.
|
||||||
|
for (j = 0, iter = 0; iter < image_histo->size; ++iter) {
|
||||||
|
if (histograms[iter] == NULL) continue;
|
||||||
|
mappings[j++] = iter;
|
||||||
|
}
|
||||||
|
assert(j == *num_used);
|
||||||
|
|
||||||
// Collapse similar histograms in 'image_histo'.
|
// Collapse similar histograms in 'image_histo'.
|
||||||
++min_cluster_size;
|
for (iter = 0;
|
||||||
for (iter = 0; iter < outer_iters && image_histo_size >= min_cluster_size &&
|
iter < outer_iters && *num_used >= min_cluster_size &&
|
||||||
++tries_with_no_success < num_tries_no_success;
|
++tries_with_no_success < num_tries_no_success;
|
||||||
++iter) {
|
++iter) {
|
||||||
|
int* mapping_index;
|
||||||
double best_cost =
|
double best_cost =
|
||||||
(histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff;
|
(histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff;
|
||||||
int best_idx1 = -1, best_idx2 = 1;
|
int best_idx1 = -1, best_idx2 = 1;
|
||||||
int j;
|
const uint32_t rand_range = (*num_used - 1) * (*num_used);
|
||||||
const uint32_t rand_range = (image_histo_size - 1) * image_histo_size;
|
// (*num_used) / 2 was chosen empirically. Less means faster but worse
|
||||||
// image_histo_size / 2 was chosen empirically. Less means faster but worse
|
|
||||||
// compression.
|
// compression.
|
||||||
const int num_tries = image_histo_size / 2;
|
const int num_tries = (*num_used) / 2;
|
||||||
|
|
||||||
for (j = 0; j < num_tries; ++j) {
|
// Pick random samples.
|
||||||
|
for (j = 0; *num_used >= 2 && j < num_tries; ++j) {
|
||||||
double curr_cost;
|
double curr_cost;
|
||||||
// Choose two different histograms at random and try to combine them.
|
// Choose two different histograms at random and try to combine them.
|
||||||
const uint32_t tmp = MyRand(&seed) % rand_range;
|
const uint32_t tmp = MyRand(&seed) % rand_range;
|
||||||
const uint32_t idx1 = tmp / (image_histo_size - 1);
|
uint32_t idx1 = tmp / (*num_used - 1);
|
||||||
uint32_t idx2 = tmp % (image_histo_size - 1);
|
uint32_t idx2 = tmp % (*num_used - 1);
|
||||||
if (idx2 >= idx1) ++idx2;
|
if (idx2 >= idx1) ++idx2;
|
||||||
|
idx1 = mappings[idx1];
|
||||||
|
idx2 = mappings[idx2];
|
||||||
|
|
||||||
// Calculate cost reduction on combination.
|
// Calculate cost reduction on combination.
|
||||||
curr_cost =
|
curr_cost =
|
||||||
@ -934,18 +974,21 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
|||||||
}
|
}
|
||||||
if (histo_queue.size == 0) continue;
|
if (histo_queue.size == 0) continue;
|
||||||
|
|
||||||
// Merge the two best histograms.
|
// Get the best histograms.
|
||||||
best_idx1 = histo_queue.queue[0].idx1;
|
best_idx1 = histo_queue.queue[0].idx1;
|
||||||
best_idx2 = histo_queue.queue[0].idx2;
|
best_idx2 = histo_queue.queue[0].idx2;
|
||||||
assert(best_idx1 < best_idx2);
|
assert(best_idx1 < best_idx2);
|
||||||
HistogramAddEval(histograms[best_idx1], histograms[best_idx2],
|
// Pop best_idx2 from mappings.
|
||||||
histograms[best_idx1], 0);
|
mapping_index = (int*) bsearch(&best_idx2, mappings, *num_used,
|
||||||
// Swap the best_idx2 histogram with the last one (which is now unused).
|
sizeof(best_idx2), &PairComparison);
|
||||||
--image_histo_size;
|
assert(mapping_index != NULL);
|
||||||
if (best_idx2 != image_histo_size) {
|
memmove(mapping_index, mapping_index + 1, sizeof(*mapping_index) *
|
||||||
HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]);
|
((*num_used) - (mapping_index - mappings) - 1));
|
||||||
}
|
// Merge the histograms and remove best_idx2 from the queue.
|
||||||
histograms[image_histo_size] = NULL;
|
HistogramAdd(histograms[best_idx2], histograms[best_idx1],
|
||||||
|
histograms[best_idx1]);
|
||||||
|
histograms[best_idx1]->bit_cost_ = histo_queue.queue[0].cost_combo;
|
||||||
|
HistogramSetRemoveHistogram(image_histo, best_idx2, num_used);
|
||||||
// Parse the queue and update each pair that deals with best_idx1,
|
// Parse the queue and update each pair that deals with best_idx1,
|
||||||
// best_idx2 or image_histo_size.
|
// best_idx2 or image_histo_size.
|
||||||
for (j = 0; j < histo_queue.size;) {
|
for (j = 0; j < histo_queue.size;) {
|
||||||
@ -968,12 +1011,6 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
|||||||
p->idx2 = best_idx1;
|
p->idx2 = best_idx1;
|
||||||
do_eval = 1;
|
do_eval = 1;
|
||||||
}
|
}
|
||||||
if (p->idx2 == image_histo_size) {
|
|
||||||
// No need to re-evaluate here as it does not involve a pair
|
|
||||||
// containing best_idx1 or best_idx2.
|
|
||||||
p->idx2 = best_idx2;
|
|
||||||
}
|
|
||||||
assert(p->idx2 < image_histo_size);
|
|
||||||
// Make sure the index order is respected.
|
// Make sure the index order is respected.
|
||||||
if (p->idx1 > p->idx2) {
|
if (p->idx1 > p->idx2) {
|
||||||
const int tmp = p->idx2;
|
const int tmp = p->idx2;
|
||||||
@ -991,15 +1028,14 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
|||||||
HistoQueueUpdateHead(&histo_queue, p);
|
HistoQueueUpdateHead(&histo_queue, p);
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
|
|
||||||
tries_with_no_success = 0;
|
tries_with_no_success = 0;
|
||||||
}
|
}
|
||||||
image_histo->size = image_histo_size;
|
*do_greedy = (*num_used <= min_cluster_size);
|
||||||
*do_greedy = (image_histo->size <= min_cluster_size);
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
End:
|
End:
|
||||||
HistoQueueClear(&histo_queue);
|
HistoQueueClear(&histo_queue);
|
||||||
|
WebPSafeFree(mappings);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,23 +1043,29 @@ End:
|
|||||||
// Histogram refinement
|
// Histogram refinement
|
||||||
|
|
||||||
// Find the best 'out' histogram for each of the 'in' histograms.
|
// Find the best 'out' histogram for each of the 'in' histograms.
|
||||||
|
// At call-time, 'out' contains the histograms of the clusters.
|
||||||
// Note: we assume that out[]->bit_cost_ is already up-to-date.
|
// Note: we assume that out[]->bit_cost_ is already up-to-date.
|
||||||
static void HistogramRemap(const VP8LHistogramSet* const in,
|
static void HistogramRemap(const VP8LHistogramSet* const in,
|
||||||
const VP8LHistogramSet* const out,
|
VP8LHistogramSet* const out,
|
||||||
uint16_t* const symbols) {
|
uint16_t* const symbols) {
|
||||||
int i;
|
int i;
|
||||||
VP8LHistogram** const in_histo = in->histograms;
|
VP8LHistogram** const in_histo = in->histograms;
|
||||||
VP8LHistogram** const out_histo = out->histograms;
|
VP8LHistogram** const out_histo = out->histograms;
|
||||||
const int in_size = in->size;
|
const int in_size = out->max_size;
|
||||||
const int out_size = out->size;
|
const int out_size = out->size;
|
||||||
if (out_size > 1) {
|
if (out_size > 1) {
|
||||||
for (i = 0; i < in_size; ++i) {
|
for (i = 0; i < in_size; ++i) {
|
||||||
int best_out = 0;
|
int best_out = 0;
|
||||||
double best_bits = MAX_COST;
|
double best_bits = MAX_COST;
|
||||||
int k;
|
int k;
|
||||||
|
if (in_histo[i] == NULL) {
|
||||||
|
// Arbitrarily set to the previous value if unused to help future LZ77.
|
||||||
|
symbols[i] = symbols[i - 1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (k = 0; k < out_size; ++k) {
|
for (k = 0; k < out_size; ++k) {
|
||||||
const double cur_bits =
|
double cur_bits;
|
||||||
HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
|
cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
|
||||||
if (k == 0 || cur_bits < best_bits) {
|
if (k == 0 || cur_bits < best_bits) {
|
||||||
best_bits = cur_bits;
|
best_bits = cur_bits;
|
||||||
best_out = k;
|
best_out = k;
|
||||||
@ -1039,12 +1081,13 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recompute each out based on raw and symbols.
|
// Recompute each out based on raw and symbols.
|
||||||
for (i = 0; i < out_size; ++i) {
|
VP8LHistogramSetClear(out);
|
||||||
HistogramClear(out_histo[i]);
|
out->size = out_size;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < in_size; ++i) {
|
for (i = 0; i < in_size; ++i) {
|
||||||
const int idx = symbols[i];
|
int idx;
|
||||||
|
if (in_histo[i] == NULL) continue;
|
||||||
|
idx = symbols[i];
|
||||||
HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]);
|
HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1060,6 +1103,70 @@ static double GetCombineCostFactor(int histo_size, int quality) {
|
|||||||
return combine_cost_factor;
|
return combine_cost_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a HistogramSet 'set', the mapping of clusters 'cluster_mapping' and the
|
||||||
|
// current assignment of the cells in 'symbols', merge the clusters and
|
||||||
|
// assign the smallest possible clusters values.
|
||||||
|
static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set,
|
||||||
|
uint16_t* const cluster_mappings,
|
||||||
|
int num_clusters,
|
||||||
|
uint16_t* const cluster_mappings_tmp,
|
||||||
|
uint16_t* const symbols) {
|
||||||
|
int i, cluster_max;
|
||||||
|
int do_continue = 1;
|
||||||
|
// First, assign the lowest cluster to each pixel.
|
||||||
|
while (do_continue) {
|
||||||
|
do_continue = 0;
|
||||||
|
for (i = 0; i < num_clusters; ++i) {
|
||||||
|
int k;
|
||||||
|
k = cluster_mappings[i];
|
||||||
|
while (k != cluster_mappings[k]) {
|
||||||
|
cluster_mappings[k] = cluster_mappings[cluster_mappings[k]];
|
||||||
|
k = cluster_mappings[k];
|
||||||
|
}
|
||||||
|
if (k != cluster_mappings[i]) {
|
||||||
|
do_continue = 1;
|
||||||
|
cluster_mappings[i] = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create a mapping from a cluster id to its minimal version.
|
||||||
|
cluster_max = 0;
|
||||||
|
memset(cluster_mappings_tmp, 0,
|
||||||
|
set->max_size * sizeof(*cluster_mappings_tmp));
|
||||||
|
assert(cluster_mappings[0] == 0);
|
||||||
|
// Re-map the ids.
|
||||||
|
for (i = 0; i < set->max_size; ++i) {
|
||||||
|
int cluster;
|
||||||
|
if (symbols[i] == kInvalidHistogramSymbol) continue;
|
||||||
|
cluster = cluster_mappings[symbols[i]];
|
||||||
|
assert(symbols[i] < num_clusters);
|
||||||
|
if (cluster > 0 && cluster_mappings_tmp[cluster] == 0) {
|
||||||
|
++cluster_max;
|
||||||
|
cluster_mappings_tmp[cluster] = cluster_max;
|
||||||
|
}
|
||||||
|
symbols[i] = cluster_mappings_tmp[cluster];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure all cluster values are used.
|
||||||
|
cluster_max = 0;
|
||||||
|
for (i = 0; i < set->max_size; ++i) {
|
||||||
|
if (symbols[i] == kInvalidHistogramSymbol) continue;
|
||||||
|
if (symbols[i] <= cluster_max) continue;
|
||||||
|
++cluster_max;
|
||||||
|
assert(symbols[i] == cluster_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
|
||||||
|
uint32_t size;
|
||||||
|
int i;
|
||||||
|
for (i = 0, size = 0; i < image_histo->size; ++i) {
|
||||||
|
if (image_histo->histograms[i] == NULL) continue;
|
||||||
|
image_histo->histograms[size++] = image_histo->histograms[i];
|
||||||
|
}
|
||||||
|
image_histo->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||||
const VP8LBackwardRefs* const refs,
|
const VP8LBackwardRefs* const refs,
|
||||||
int quality, int low_effort,
|
int quality, int low_effort,
|
||||||
@ -1078,27 +1185,36 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
// maximum quality q==100 (to preserve the compression gains at that level).
|
// maximum quality q==100 (to preserve the compression gains at that level).
|
||||||
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
|
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
|
||||||
int entropy_combine;
|
int entropy_combine;
|
||||||
|
uint16_t* const map_tmp =
|
||||||
if (orig_histo == NULL) goto Error;
|
WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
|
||||||
|
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
|
||||||
|
int num_used = image_histo_raw_size;
|
||||||
|
if (orig_histo == NULL || map_tmp == NULL) goto Error;
|
||||||
|
|
||||||
// Construct the histograms from backward references.
|
// Construct the histograms from backward references.
|
||||||
HistogramBuild(xsize, histo_bits, refs, orig_histo);
|
HistogramBuild(xsize, histo_bits, refs, orig_histo);
|
||||||
// Copies the histograms and computes its bit_cost.
|
// Copies the histograms and computes its bit_cost.
|
||||||
HistogramCopyAndAnalyze(orig_histo, image_histo);
|
// histogram_symbols is optimized
|
||||||
|
HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used,
|
||||||
|
histogram_symbols);
|
||||||
|
|
||||||
entropy_combine =
|
entropy_combine =
|
||||||
(image_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
|
(num_used > entropy_combine_num_bins * 2) && (quality < 100);
|
||||||
|
|
||||||
if (entropy_combine) {
|
if (entropy_combine) {
|
||||||
const int bin_map_size = image_histo->size;
|
uint16_t* const bin_map = map_tmp;
|
||||||
// Reuse histogram_symbols storage. By definition, it's guaranteed to be ok.
|
|
||||||
uint16_t* const bin_map = histogram_symbols;
|
|
||||||
const double combine_cost_factor =
|
const double combine_cost_factor =
|
||||||
GetCombineCostFactor(image_histo_raw_size, quality);
|
GetCombineCostFactor(image_histo_raw_size, quality);
|
||||||
|
const uint32_t num_clusters = num_used;
|
||||||
|
|
||||||
HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
|
HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
|
||||||
// Collapse histograms with similar entropy.
|
// Collapse histograms with similar entropy.
|
||||||
HistogramCombineEntropyBin(image_histo, tmp_histo, bin_map, bin_map_size,
|
HistogramCombineEntropyBin(image_histo, &num_used, histogram_symbols,
|
||||||
|
cluster_mappings, tmp_histo, bin_map,
|
||||||
entropy_combine_num_bins, combine_cost_factor,
|
entropy_combine_num_bins, combine_cost_factor,
|
||||||
low_effort);
|
low_effort);
|
||||||
|
OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters,
|
||||||
|
map_tmp, histogram_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't combine the histograms using stochastic and greedy heuristics for
|
// Don't combine the histograms using stochastic and greedy heuristics for
|
||||||
@ -1108,21 +1224,26 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
||||||
const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
|
const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
|
||||||
int do_greedy;
|
int do_greedy;
|
||||||
if (!HistogramCombineStochastic(image_histo, threshold_size, &do_greedy)) {
|
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
|
||||||
|
&do_greedy)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (do_greedy && !HistogramCombineGreedy(image_histo)) {
|
if (do_greedy) {
|
||||||
goto Error;
|
RemoveEmptyHistograms(image_histo);
|
||||||
|
if (!HistogramCombineGreedy(image_histo, &num_used)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(vrabaud): Optimize HistogramRemap for low-effort compression mode.
|
|
||||||
// Find the optimal map from original histograms to the final ones.
|
// Find the optimal map from original histograms to the final ones.
|
||||||
|
RemoveEmptyHistograms(image_histo);
|
||||||
HistogramRemap(orig_histo, image_histo, histogram_symbols);
|
HistogramRemap(orig_histo, image_histo, histogram_symbols);
|
||||||
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
VP8LFreeHistogramSet(orig_histo);
|
VP8LFreeHistogramSet(orig_histo);
|
||||||
|
WebPSafeFree(map_tmp);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -177,12 +177,15 @@ static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) {
|
||||||
|
return (uint8_t)((((int)(a) - (int)(b))) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
// Quantize every component of the difference between the actual pixel value and
|
// Quantize every component of the difference between the actual pixel value and
|
||||||
// its prediction to a multiple of a quantization (a power of 2, not larger than
|
// its prediction to a multiple of a quantization (a power of 2, not larger than
|
||||||
// max_quantization which is a power of 2, smaller than max_diff). Take care if
|
// max_quantization which is a power of 2, smaller than max_diff). Take care if
|
||||||
// value and predict have undergone subtract green, which means that red and
|
// value and predict have undergone subtract green, which means that red and
|
||||||
// blue are represented as offsets from green.
|
// blue are represented as offsets from green.
|
||||||
#define NEAR_LOSSLESS_DIFF(a, b) (uint8_t)((((int)(a) - (int)(b))) & 0xff)
|
|
||||||
static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
||||||
int max_quantization, int max_diff,
|
int max_quantization, int max_diff,
|
||||||
int used_subtract_green) {
|
int used_subtract_green) {
|
||||||
@ -199,7 +202,7 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
|||||||
}
|
}
|
||||||
if ((value >> 24) == 0 || (value >> 24) == 0xff) {
|
if ((value >> 24) == 0 || (value >> 24) == 0xff) {
|
||||||
// Preserve transparency of fully transparent or fully opaque pixels.
|
// Preserve transparency of fully transparent or fully opaque pixels.
|
||||||
a = NEAR_LOSSLESS_DIFF(value >> 24, predict >> 24);
|
a = NearLosslessDiff(value >> 24, predict >> 24);
|
||||||
} else {
|
} else {
|
||||||
a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
|
a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
|
||||||
}
|
}
|
||||||
@ -212,16 +215,15 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
|||||||
// The amount by which green has been adjusted during quantization. It is
|
// The amount by which green has been adjusted during quantization. It is
|
||||||
// subtracted from red and blue for compensation, to avoid accumulating two
|
// subtracted from red and blue for compensation, to avoid accumulating two
|
||||||
// quantization errors in them.
|
// quantization errors in them.
|
||||||
green_diff = NEAR_LOSSLESS_DIFF(new_green, value >> 8);
|
green_diff = NearLosslessDiff(new_green, value >> 8);
|
||||||
}
|
}
|
||||||
r = NearLosslessComponent(NEAR_LOSSLESS_DIFF(value >> 16, green_diff),
|
r = NearLosslessComponent(NearLosslessDiff(value >> 16, green_diff),
|
||||||
(predict >> 16) & 0xff, 0xff - new_green,
|
(predict >> 16) & 0xff, 0xff - new_green,
|
||||||
quantization);
|
quantization);
|
||||||
b = NearLosslessComponent(NEAR_LOSSLESS_DIFF(value, green_diff),
|
b = NearLosslessComponent(NearLosslessDiff(value, green_diff),
|
||||||
predict & 0xff, 0xff - new_green, quantization);
|
predict & 0xff, 0xff - new_green, quantization);
|
||||||
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||||
}
|
}
|
||||||
#undef NEAR_LOSSLESS_DIFF
|
|
||||||
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
|
||||||
// Stores the difference between the pixel and its prediction in "out".
|
// Stores the difference between the pixel and its prediction in "out".
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h> // for abs()
|
#include <stdlib.h> // for abs()
|
||||||
|
|
||||||
|
#include "src/dsp/quant.h"
|
||||||
#include "src/enc/vp8i_enc.h"
|
#include "src/enc/vp8i_enc.h"
|
||||||
#include "src/enc/cost_enc.h"
|
#include "src/enc/cost_enc.h"
|
||||||
|
|
||||||
@ -977,19 +978,6 @@ static void SwapOut(VP8EncIterator* const it) {
|
|||||||
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
|
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static score_t IsFlat(const int16_t* levels, int num_blocks, score_t thresh) {
|
|
||||||
score_t score = 0;
|
|
||||||
while (num_blocks-- > 0) { // TODO(skal): refine positional scoring?
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC
|
|
||||||
score += (levels[i] != 0);
|
|
||||||
if (score > thresh) return 0;
|
|
||||||
}
|
|
||||||
levels += 16;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
|
static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
|
||||||
const int kNumBlocks = 16;
|
const int kNumBlocks = 16;
|
||||||
VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
|
VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
|
||||||
|
@ -32,7 +32,7 @@ extern "C" {
|
|||||||
// version numbers
|
// version numbers
|
||||||
#define ENC_MAJ_VERSION 1
|
#define ENC_MAJ_VERSION 1
|
||||||
#define ENC_MIN_VERSION 0
|
#define ENC_MIN_VERSION 0
|
||||||
#define ENC_REV_VERSION 1
|
#define ENC_REV_VERSION 2
|
||||||
|
|
||||||
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
||||||
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
|
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
|
||||||
|
@ -462,6 +462,7 @@ static int GetHuffBitLengthsAndCodes(
|
|||||||
for (i = 0; i < histogram_image_size; ++i) {
|
for (i = 0; i < histogram_image_size; ++i) {
|
||||||
const VP8LHistogram* const histo = histogram_image->histograms[i];
|
const VP8LHistogram* const histo = histogram_image->histograms[i];
|
||||||
HuffmanTreeCode* const codes = &huffman_codes[5 * i];
|
HuffmanTreeCode* const codes = &huffman_codes[5 * i];
|
||||||
|
assert(histo != NULL);
|
||||||
for (k = 0; k < 5; ++k) {
|
for (k = 0; k < 5; ++k) {
|
||||||
const int num_symbols =
|
const int num_symbols =
|
||||||
(k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
|
(k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
|
||||||
@ -1692,11 +1693,16 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface();
|
const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface();
|
||||||
int ok_main;
|
int ok_main;
|
||||||
|
|
||||||
|
if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) {
|
||||||
|
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||||
|
VP8LEncoderDelete(enc_main);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Analyze image (entropy, num_palettes etc)
|
// Analyze image (entropy, num_palettes etc)
|
||||||
if (enc_main == NULL ||
|
if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
|
||||||
!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
|
|
||||||
&red_and_blue_always_zero) ||
|
&red_and_blue_always_zero) ||
|
||||||
!EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) {
|
!EncoderInit(enc_main)) {
|
||||||
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,0,1
|
FILEVERSION 1,0,0,2
|
||||||
PRODUCTVERSION 1,0,0,1
|
PRODUCTVERSION 1,0,0,2
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -24,12 +24,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Google, Inc."
|
VALUE "CompanyName", "Google, Inc."
|
||||||
VALUE "FileDescription", "libwebp DLL"
|
VALUE "FileDescription", "libwebp DLL"
|
||||||
VALUE "FileVersion", "1.0.1"
|
VALUE "FileVersion", "1.0.2"
|
||||||
VALUE "InternalName", "libwebp.dll"
|
VALUE "InternalName", "libwebp.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2018"
|
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||||
VALUE "OriginalFilename", "libwebp.dll"
|
VALUE "OriginalFilename", "libwebp.dll"
|
||||||
VALUE "ProductName", "WebP Image Codec"
|
VALUE "ProductName", "WebP Image Codec"
|
||||||
VALUE "ProductVersion", "1.0.1"
|
VALUE "ProductVersion", "1.0.2"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,0,1
|
FILEVERSION 1,0,0,2
|
||||||
PRODUCTVERSION 1,0,0,1
|
PRODUCTVERSION 1,0,0,2
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -24,12 +24,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Google, Inc."
|
VALUE "CompanyName", "Google, Inc."
|
||||||
VALUE "FileDescription", "libwebpdecoder DLL"
|
VALUE "FileDescription", "libwebpdecoder DLL"
|
||||||
VALUE "FileVersion", "1.0.1"
|
VALUE "FileVersion", "1.0.2"
|
||||||
VALUE "InternalName", "libwebpdecoder.dll"
|
VALUE "InternalName", "libwebpdecoder.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2018"
|
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||||
VALUE "OriginalFilename", "libwebpdecoder.dll"
|
VALUE "OriginalFilename", "libwebpdecoder.dll"
|
||||||
VALUE "ProductName", "WebP Image Decoder"
|
VALUE "ProductName", "WebP Image Decoder"
|
||||||
VALUE "ProductVersion", "1.0.1"
|
VALUE "ProductVersion", "1.0.2"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -17,6 +17,6 @@ noinst_HEADERS =
|
|||||||
noinst_HEADERS += ../webp/format_constants.h
|
noinst_HEADERS += ../webp/format_constants.h
|
||||||
|
|
||||||
libwebpmux_la_LIBADD = ../libwebp.la
|
libwebpmux_la_LIBADD = ../libwebp.la
|
||||||
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:3:0 -lm
|
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:4:0 -lm
|
||||||
libwebpmuxincludedir = $(includedir)/webp
|
libwebpmuxincludedir = $(includedir)/webp
|
||||||
pkgconfig_DATA = libwebpmux.pc
|
pkgconfig_DATA = libwebpmux.pc
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,0,1
|
FILEVERSION 1,0,0,2
|
||||||
PRODUCTVERSION 1,0,0,1
|
PRODUCTVERSION 1,0,0,2
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -24,12 +24,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Google, Inc."
|
VALUE "CompanyName", "Google, Inc."
|
||||||
VALUE "FileDescription", "libwebpmux DLL"
|
VALUE "FileDescription", "libwebpmux DLL"
|
||||||
VALUE "FileVersion", "1.0.1"
|
VALUE "FileVersion", "1.0.2"
|
||||||
VALUE "InternalName", "libwebpmux.dll"
|
VALUE "InternalName", "libwebpmux.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2018"
|
VALUE "LegalCopyright", "Copyright (C) 2019"
|
||||||
VALUE "OriginalFilename", "libwebpmux.dll"
|
VALUE "OriginalFilename", "libwebpmux.dll"
|
||||||
VALUE "ProductName", "WebP Image Muxer"
|
VALUE "ProductName", "WebP Image Muxer"
|
||||||
VALUE "ProductVersion", "1.0.1"
|
VALUE "ProductVersion", "1.0.2"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -29,7 +29,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define MUX_MAJ_VERSION 1
|
#define MUX_MAJ_VERSION 1
|
||||||
#define MUX_MIN_VERSION 0
|
#define MUX_MIN_VERSION 0
|
||||||
#define MUX_REV_VERSION 1
|
#define MUX_REV_VERSION 2
|
||||||
|
|
||||||
// Chunk object.
|
// Chunk object.
|
||||||
typedef struct WebPChunk WebPChunk;
|
typedef struct WebPChunk WebPChunk;
|
||||||
|
@ -248,6 +248,7 @@ int VP8LBitWriterClone(const VP8LBitWriter* const src,
|
|||||||
dst->bits_ = src->bits_;
|
dst->bits_ = src->bits_;
|
||||||
dst->used_ = src->used_;
|
dst->used_ = src->used_;
|
||||||
dst->error_ = src->error_;
|
dst->error_ = src->error_;
|
||||||
|
dst->cur_ = dst->buf_ + current_size;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,19 +107,6 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
|
|||||||
PutLE16(data + 2, (int)(val >> 16));
|
PutLE16(data + 2, (int)(val >> 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
|
|
||||||
// based on table or not. Can be used as fallback if clz() is not available.
|
|
||||||
#define WEBP_NEED_LOG_TABLE_8BIT
|
|
||||||
extern const uint8_t WebPLogTable8bit[256];
|
|
||||||
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
|
|
||||||
int log_value = 0;
|
|
||||||
while (n >= 256) {
|
|
||||||
log_value += 8;
|
|
||||||
n >>= 8;
|
|
||||||
}
|
|
||||||
return log_value + WebPLogTable8bit[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns (int)floor(log2(n)). n must be > 0.
|
// Returns (int)floor(log2(n)). n must be > 0.
|
||||||
// use GNU builtins where available.
|
// use GNU builtins where available.
|
||||||
#if defined(__GNUC__) && \
|
#if defined(__GNUC__) && \
|
||||||
@ -138,6 +125,19 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
|
|||||||
return first_set_bit;
|
return first_set_bit;
|
||||||
}
|
}
|
||||||
#else // default: use the C-version.
|
#else // default: use the C-version.
|
||||||
|
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
|
||||||
|
// based on table or not. Can be used as fallback if clz() is not available.
|
||||||
|
#define WEBP_NEED_LOG_TABLE_8BIT
|
||||||
|
extern const uint8_t WebPLogTable8bit[256];
|
||||||
|
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
|
||||||
|
int log_value = 0;
|
||||||
|
while (n >= 256) {
|
||||||
|
log_value += 8;
|
||||||
|
n >>= 8;
|
||||||
|
}
|
||||||
|
return log_value + WebPLogTable8bit[n];
|
||||||
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
|
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -42,6 +42,12 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
|
|||||||
// This function will also validate the header, returning true on success,
|
// This function will also validate the header, returning true on success,
|
||||||
// false otherwise. '*width' and '*height' are only valid on successful return.
|
// false otherwise. '*width' and '*height' are only valid on successful return.
|
||||||
// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
|
// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
|
||||||
|
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
|
||||||
|
// considered valid by this function:
|
||||||
|
// RIFF + VP8(L)
|
||||||
|
// RIFF + VP8X + (optional chunks) + VP8(L)
|
||||||
|
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
|
||||||
|
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
|
||||||
WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
@ -425,6 +431,12 @@ WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(
|
|||||||
// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
|
// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
|
||||||
// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the
|
// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the
|
||||||
// features from headers. Returns error in other cases.
|
// features from headers. Returns error in other cases.
|
||||||
|
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
|
||||||
|
// considered valid by this function:
|
||||||
|
// RIFF + VP8(L)
|
||||||
|
// RIFF + VP8X + (optional chunks) + VP8(L)
|
||||||
|
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
|
||||||
|
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
|
||||||
static WEBP_INLINE VP8StatusCode WebPGetFeatures(
|
static WEBP_INLINE VP8StatusCode WebPGetFeatures(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
WebPBitstreamFeatures* features) {
|
WebPBitstreamFeatures* features) {
|
||||||
|
Reference in New Issue
Block a user