Compare commits

..

3 Commits
1.0.0 ... 0.5.2

Author SHA1 Message Date
e1f1bce9dc Fix invalid incremental decoding check.
(cherry picked from commit 95ea5226c8)

Change-Id: I80c2165aa9fdf43077db155d2d00e0e99db73eab
2023-10-06 11:53:43 +02:00
90d47113bc Fix OOB write in BuildHuffmanTable.
First, BuildHuffmanTable is called to check if the data is valid.
If it is and the table is not big enough, more memory is allocated.

This will make sure that valid (but unoptimized because of unbalanced
codes) streams are still decodable.
(cherry picked from commit 902bc91)

Change-Id: I3abe4db460dcac62c14a84832284c0b530630af2
2023-10-06 11:53:43 +02:00
bc99ef0699 Limit memory allocation when reading invalid Huffman codes.
This is a backported fix for: CVE-2020-36332

This is a merge of:
dce5d76431
39cb9aad85
067031eaed

Change-Id: Iab84d2ca459327cdcee1038499842d30370fe486
2023-10-06 11:53:40 +02:00
257 changed files with 14218 additions and 29154 deletions

5
.gitignore vendored
View File

@ -22,7 +22,6 @@ Makefile.in
examples/anim_diff examples/anim_diff
examples/[cdv]webp examples/[cdv]webp
examples/gif2webp examples/gif2webp
examples/img2webp
examples/webpmux examples/webpmux
src/webp/config.h* src/webp/config.h*
src/webp/stamp-h1 src/webp/stamp-h1
@ -35,7 +34,3 @@ src/webp/stamp-h1
CMakeCache.txt CMakeCache.txt
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
.gradle
/build
extras/get_disto
extras/webp_quality

View File

@ -5,7 +5,6 @@ Contributors:
- Hui Su (huisu at google dot com) - Hui Su (huisu at google dot com)
- James Zern (jzern at google dot com) - James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de) - Jan Engelhardt (jengelh at medozas dot de)
- Jehan (jehan at girinstud dot io)
- Johann (johann dot koenig at duck dot com) - Johann (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)
@ -18,7 +17,6 @@ Contributors:
- Mislav Bradac (mislavm at google dot com) - Mislav Bradac (mislavm at google dot com)
- Nico Weber (thakis at chromium dot org) - Nico Weber (thakis at chromium dot org)
- Noel Chromium (noel at chromium dot org) - Noel Chromium (noel at chromium dot org)
- Owen Rodley (orodley at google dot com)
- Parag Salasakar (img dot mips1 at gmail dot com) - Parag Salasakar (img dot mips1 at gmail dot com)
- Pascal Massimino (pascal dot massimino at gmail dot com) - Pascal Massimino (pascal dot massimino at gmail dot com)
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org) - Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
@ -35,5 +33,4 @@ Contributors:
- Urvang Joshi (urvang at google dot com) - Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com) - Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com) - Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Yang Zhang (yang dot zhang at arm dot com) - Yang Zhang (yang dot zhang at arm dot com)

View File

@ -11,39 +11,27 @@ ifeq ($(APP_OPTIM),release)
endif endif
endif endif
# mips32 fails to build with clang from r14b
# https://bugs.chromium.org/p/webp/issues/detail?id=343
ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),clang)
ifeq ($(TARGET_ARCH),mips)
clang_version := $(shell $(TARGET_CC) --version)
ifneq ($(findstring clang version 3,$(clang_version)),)
WEBP_CFLAGS += -no-integrated-as
endif
endif
endif
ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),) ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),)
# Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal # Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal
# instructions to be generated for armv7a code. Instead target the neon code # instructions to be generated for armv7a code. Instead target the neon code
# specifically. # specifically.
NEON := c.neon NEON := c.neon
USE_CPUFEATURES := yes USE_CPUFEATURES := yes
WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H
else else
NEON := c NEON := c
endif endif
dec_srcs := \ dec_srcs := \
src/dec/alpha_dec.c \ src/dec/alpha.c \
src/dec/buffer_dec.c \ src/dec/buffer.c \
src/dec/frame_dec.c \ src/dec/frame.c \
src/dec/idec_dec.c \ src/dec/idec.c \
src/dec/io_dec.c \ src/dec/io.c \
src/dec/quant_dec.c \ src/dec/quant.c \
src/dec/tree_dec.c \ src/dec/tree.c \
src/dec/vp8_dec.c \ src/dec/vp8.c \
src/dec/vp8l_dec.c \ src/dec/vp8l.c \
src/dec/webp_dec.c \ src/dec/webp.c \
demux_srcs := \ demux_srcs := \
src/demux/anim_decode.c \ src/demux/anim_decode.c \
@ -52,9 +40,11 @@ demux_srcs := \
dsp_dec_srcs := \ dsp_dec_srcs := \
src/dsp/alpha_processing.c \ src/dsp/alpha_processing.c \
src/dsp/alpha_processing_mips_dsp_r2.c \ src/dsp/alpha_processing_mips_dsp_r2.c \
src/dsp/alpha_processing_neon.$(NEON) \
src/dsp/alpha_processing_sse2.c \ src/dsp/alpha_processing_sse2.c \
src/dsp/alpha_processing_sse41.c \ src/dsp/alpha_processing_sse41.c \
src/dsp/argb.c \
src/dsp/argb_mips_dsp_r2.c \
src/dsp/argb_sse2.c \
src/dsp/cpu.c \ src/dsp/cpu.c \
src/dsp/dec.c \ src/dsp/dec.c \
src/dsp/dec_clip_tables.c \ src/dsp/dec_clip_tables.c \
@ -66,32 +56,24 @@ dsp_dec_srcs := \
src/dsp/dec_sse41.c \ src/dsp/dec_sse41.c \
src/dsp/filters.c \ src/dsp/filters.c \
src/dsp/filters_mips_dsp_r2.c \ src/dsp/filters_mips_dsp_r2.c \
src/dsp/filters_msa.c \
src/dsp/filters_neon.$(NEON) \
src/dsp/filters_sse2.c \ src/dsp/filters_sse2.c \
src/dsp/lossless.c \ src/dsp/lossless.c \
src/dsp/lossless_mips_dsp_r2.c \ src/dsp/lossless_mips_dsp_r2.c \
src/dsp/lossless_msa.c \
src/dsp/lossless_neon.$(NEON) \ src/dsp/lossless_neon.$(NEON) \
src/dsp/lossless_sse2.c \ src/dsp/lossless_sse2.c \
src/dsp/rescaler.c \ src/dsp/rescaler.c \
src/dsp/rescaler_mips32.c \ src/dsp/rescaler_mips32.c \
src/dsp/rescaler_mips_dsp_r2.c \ src/dsp/rescaler_mips_dsp_r2.c \
src/dsp/rescaler_msa.c \
src/dsp/rescaler_neon.$(NEON) \ src/dsp/rescaler_neon.$(NEON) \
src/dsp/rescaler_sse2.c \ src/dsp/rescaler_sse2.c \
src/dsp/upsampling.c \ src/dsp/upsampling.c \
src/dsp/upsampling_mips_dsp_r2.c \ src/dsp/upsampling_mips_dsp_r2.c \
src/dsp/upsampling_msa.c \
src/dsp/upsampling_neon.$(NEON) \ src/dsp/upsampling_neon.$(NEON) \
src/dsp/upsampling_sse2.c \ src/dsp/upsampling_sse2.c \
src/dsp/upsampling_sse41.c \
src/dsp/yuv.c \ src/dsp/yuv.c \
src/dsp/yuv_mips32.c \ src/dsp/yuv_mips32.c \
src/dsp/yuv_mips_dsp_r2.c \ src/dsp/yuv_mips_dsp_r2.c \
src/dsp/yuv_neon.$(NEON) \
src/dsp/yuv_sse2.c \ src/dsp/yuv_sse2.c \
src/dsp/yuv_sse41.c \
dsp_enc_srcs := \ dsp_enc_srcs := \
src/dsp/cost.c \ src/dsp/cost.c \
@ -102,44 +84,39 @@ dsp_enc_srcs := \
src/dsp/enc_avx2.c \ src/dsp/enc_avx2.c \
src/dsp/enc_mips32.c \ src/dsp/enc_mips32.c \
src/dsp/enc_mips_dsp_r2.c \ src/dsp/enc_mips_dsp_r2.c \
src/dsp/enc_msa.c \
src/dsp/enc_neon.$(NEON) \ src/dsp/enc_neon.$(NEON) \
src/dsp/enc_sse2.c \ src/dsp/enc_sse2.c \
src/dsp/enc_sse41.c \ src/dsp/enc_sse41.c \
src/dsp/lossless_enc.c \ src/dsp/lossless_enc.c \
src/dsp/lossless_enc_mips32.c \ src/dsp/lossless_enc_mips32.c \
src/dsp/lossless_enc_mips_dsp_r2.c \ src/dsp/lossless_enc_mips_dsp_r2.c \
src/dsp/lossless_enc_msa.c \
src/dsp/lossless_enc_neon.$(NEON) \ src/dsp/lossless_enc_neon.$(NEON) \
src/dsp/lossless_enc_sse2.c \ src/dsp/lossless_enc_sse2.c \
src/dsp/lossless_enc_sse41.c \ src/dsp/lossless_enc_sse41.c \
src/dsp/ssim.c \
src/dsp/ssim_sse2.c \
enc_srcs := \ enc_srcs := \
src/enc/alpha_enc.c \ src/enc/alpha.c \
src/enc/analysis_enc.c \ src/enc/analysis.c \
src/enc/backward_references_cost_enc.c \ src/enc/backward_references.c \
src/enc/backward_references_enc.c \ src/enc/config.c \
src/enc/config_enc.c \ src/enc/cost.c \
src/enc/cost_enc.c \ src/enc/delta_palettization.c \
src/enc/filter_enc.c \ src/enc/filter.c \
src/enc/frame_enc.c \ src/enc/frame.c \
src/enc/histogram_enc.c \ src/enc/histogram.c \
src/enc/iterator_enc.c \ src/enc/iterator.c \
src/enc/near_lossless_enc.c \ src/enc/near_lossless.c \
src/enc/picture_enc.c \ src/enc/picture.c \
src/enc/picture_csp_enc.c \ src/enc/picture_csp.c \
src/enc/picture_psnr_enc.c \ src/enc/picture_psnr.c \
src/enc/picture_rescale_enc.c \ src/enc/picture_rescale.c \
src/enc/picture_tools_enc.c \ src/enc/picture_tools.c \
src/enc/predictor_enc.c \ src/enc/quant.c \
src/enc/quant_enc.c \ src/enc/syntax.c \
src/enc/syntax_enc.c \ src/enc/token.c \
src/enc/token_enc.c \ src/enc/tree.c \
src/enc/tree_enc.c \ src/enc/vp8l.c \
src/enc/vp8l_enc.c \ src/enc/webpenc.c \
src/enc/webp_enc.c \
mux_srcs := \ mux_srcs := \
src/mux/anim_encode.c \ src/mux/anim_encode.c \
@ -148,20 +125,20 @@ mux_srcs := \
src/mux/muxread.c \ src/mux/muxread.c \
utils_dec_srcs := \ utils_dec_srcs := \
src/utils/bit_reader_utils.c \ src/utils/bit_reader.c \
src/utils/color_cache_utils.c \ src/utils/color_cache.c \
src/utils/filters_utils.c \ src/utils/filters.c \
src/utils/huffman_utils.c \ src/utils/huffman.c \
src/utils/quant_levels_dec_utils.c \ src/utils/quant_levels_dec.c \
src/utils/random_utils.c \ src/utils/random.c \
src/utils/rescaler_utils.c \ src/utils/rescaler.c \
src/utils/thread_utils.c \ src/utils/thread.c \
src/utils/utils.c \ src/utils/utils.c \
utils_enc_srcs := \ utils_enc_srcs := \
src/utils/bit_writer_utils.c \ src/utils/bit_writer.c \
src/utils/huffman_encode_utils.c \ src/utils/huffman_encode.c \
src/utils/quant_levels_utils.c \ src/utils/quant_levels.c \
################################################################################ ################################################################################
# libwebpdecoder # libwebpdecoder
@ -271,9 +248,7 @@ endif
################################################################################ ################################################################################
WEBP_SRC_PATH := $(LOCAL_PATH) include $(LOCAL_PATH)/examples/Android.mk
include $(WEBP_SRC_PATH)/imageio/Android.mk
include $(WEBP_SRC_PATH)/examples/Android.mk
ifeq ($(USE_CPUFEATURES),yes) ifeq ($(USE_CPUFEATURES),yes)
$(call import-module,android/cpufeatures) $(call import-module,android/cpufeatures)

View File

@ -3,20 +3,12 @@ cmake_minimum_required(VERSION 2.8.7)
project(libwebp C) project(libwebp C)
# Options for coder / decoder executables. # Options for coder / decoder executables.
option(WEBP_ENABLE_SIMD "Enable any SIMD optimization." ON)
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF) option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF)
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF) option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF)
option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." OFF) option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." OFF) option(WEBP_FORCE_ALIGNED "Force aligned memory operations." OFF)
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." OFF)
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF) option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF)
if(WEBP_BUILD_WEBP_JS)
set(WEBP_ENABLE_SIMD OFF)
endif()
set(WEBP_DEP_LIBRARIES) set(WEBP_DEP_LIBRARIES)
set(WEBP_DEP_INCLUDE_DIRS) set(WEBP_DEP_INCLUDE_DIRS)
@ -26,13 +18,12 @@ if(NOT CMAKE_BUILD_TYPE)
) )
endif() endif()
# Include dependencies. include(cmake/config.h.cmake)
include(cmake/deps.cmake)
################################################################################ ################################################################################
# Options. # Options.
if(WEBP_ENABLE_SWAP_16BIT_CSP) if(WEBP_ENABLE_SWAP_16BIT_CSP)
add_definitions(-DWEBP_SWAP_16BIT_CSP=1) add_definitions(-DWEBP_SWAP_16BIT_CSP)
endif() endif()
################################################################################ ################################################################################
@ -47,118 +38,48 @@ if(ANDROID)
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS}
${ANDROID_NDK}/sources/android/cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures
) )
add_definitions(-DHAVE_CPU_FEATURES_H=1)
set(HAVE_CPU_FEATURES_H 1)
else()
set(HAVE_CPU_FEATURES_H 0)
endif() endif()
################################################################################ ################################################################################
# WebP source files. # WebP source files.
# Read the Makefile.am to get the source files. # Read the Makefile.am to get the source files.
set(WEBP_SRCS)
# We expect the Makefiles to define the sources as defined in function(parse_Makefile_am FOLDER WEBP_SRCS)
# the first regex. E.g.:
# libimagedec_la_SOURCES = image_dec.c image_dec.h
function(parse_Makefile_am FOLDER VAR SRC_REGEX)
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM) file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
string(REGEX MATCHALL "${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*" string(REGEX MATCHALL "_SOURCES \\+= [^\n]*"
FILES_PER_LINE ${MAKEFILE_AM} FILES_PER_LINE ${MAKEFILE_AM}
) )
set(SRCS ${${VAR}}) set(SRCS ${WEBP_SRCS})
foreach(FILES ${FILES_PER_LINE}) foreach(FILES ${FILES_PER_LINE})
string(FIND ${FILES} "=" OFFSET) string(SUBSTRING ${FILES} 12 -1 FILES)
math(EXPR OFFSET "${OFFSET} + 2") string(REGEX MATCHALL "[0-9a-z\\._]+"
string(SUBSTRING ${FILES} ${OFFSET} -1 FILES) FILES ${FILES}
if(FILES) )
string(REGEX MATCHALL "[0-9a-z\\._]+" foreach(FILE ${FILES})
FILES ${FILES} list(APPEND SRCS ${FOLDER}/${FILE})
) endforeach()
foreach(FILE ${FILES})
list(APPEND SRCS ${FOLDER}/${FILE})
endforeach()
endif()
endforeach() endforeach()
set(${VAR} ${SRCS} PARENT_SCOPE) set(WEBP_SRCS ${SRCS} PARENT_SCOPE)
endfunction() endfunction()
set(WEBP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dec "${WEBP_SRCS}")
parse_Makefile_am(${WEBP_SRC_DIR}/dec "WEBP_DEC_SRCS" "") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/demux "${WEBP_SRCS}")
parse_Makefile_am(${WEBP_SRC_DIR}/demux "WEBP_DEMUX_SRCS" "") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/dsp "${WEBP_SRCS}")
parse_Makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_COMMON_SRCS" "COMMON") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/enc "${WEBP_SRCS}")
parse_Makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "ENC") parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/utils "${WEBP_SRCS}")
parse_Makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "dsp_[^ ]*")
parse_Makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_DEC_SRCS" "decode_[^ ]*")
parse_Makefile_am(${WEBP_SRC_DIR}/enc "WEBP_ENC_SRCS" "")
parse_Makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_COMMON_SRCS" "COMMON")
parse_Makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_ENC_SRCS" "ENC")
parse_Makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_DEC_SRCS" "decode_[^ ]*")
# Remove the files specific to SIMD we don't use. # Remove the files specific to SIMD we don't use.
foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE}) foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
list(REMOVE_ITEM WEBP_DSP_ENC_SRCS ${FILE}) list(REMOVE_ITEM WEBP_SRCS ${FILE})
list(REMOVE_ITEM WEBP_DSP_DEC_SRCS ${FILE})
endforeach() endforeach()
### Define the mandatory libraries. # Build the library.
# Build the webpdecoder library. add_definitions(-Wall)
if(MSVC) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/ ${WEBP_DEP_INCLUDE_DIRS})
# avoid security warnings for e.g., fopen() used in the examples. add_library(webp ${WEBP_SRCS})
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_definitions(-Wall)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${WEBP_DEP_INCLUDE_DIRS})
add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
add_library(webputilsdecode OBJECT ${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS})
add_library(webpdecoder $<TARGET_OBJECTS:webpdecode>
$<TARGET_OBJECTS:webpdspdecode> $<TARGET_OBJECTS:webputilsdecode>)
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
# Build the webp library.
add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
add_library(webpdsp OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS}
${WEBP_DSP_ENC_SRCS})
add_library(webputils OBJECT ${WEBP_UTILS_COMMON_SRCS} ${WEBP_UTILS_DEC_SRCS}
${WEBP_UTILS_ENC_SRCS})
add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
target_link_libraries(webp ${WEBP_DEP_LIBRARIES}) target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
# Make sure the OBJECT libraries are built with position independent code
# (it is not ON by default).
set_target_properties(webpdecode webpdspdecode webputilsdecode
webpencode webpdsp webputils PROPERTIES POSITION_INDEPENDENT_CODE ON)
# Build the webp demux library.
add_library(webpdemux ${WEBP_DEMUX_SRCS})
target_link_libraries(webpdemux webp)
# Set the version numbers.
function(parse_version FILE NAME VAR)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/${FILE} SOURCE_FILE)
string(REGEX MATCH "${NAME}_la_LDFLAGS[^\n]* -version-info [0-9:]+" TMP
${SOURCE_FILE})
string(REGEX MATCH "[0-9:]+" TMP ${TMP})
string(REGEX REPLACE ":" "." VERSION ${TMP})
set(${VAR} "${VERSION}" PARENT_SCOPE)
endfunction()
parse_version(Makefile.am webp WEBP_WEBP_SOVERSION)
set_target_properties(webp PROPERTIES VERSION ${PACKAGE_VERSION}
SOVERSION ${WEBP_WEBP_SOVERSION})
parse_version(Makefile.am webpdecoder WEBP_DECODER_SOVERSION)
set_target_properties(webpdecoder PROPERTIES VERSION ${PACKAGE_VERSION}
SOVERSION ${WEBP_DECODER_SOVERSION})
parse_version(demux/Makefile.am webpdemux WEBP_DEMUX_SOVERSION)
set_target_properties(webpdemux PROPERTIES VERSION ${PACKAGE_VERSION}
SOVERSION ${WEBP_DEMUX_SOVERSION})
# Define the libraries to install.
set(INSTALLED_LIBRARIES webpdecoder webp webpdemux)
### Deal with SIMD.
# Change the compile flags for SIMD files we use. # Change the compile flags for SIMD files we use.
list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH) list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH)
math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE
@ -174,198 +95,57 @@ foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
endforeach() endforeach()
# Build the executables if asked for. # Build the executables if asked for.
if(WEBP_BUILD_CWEBP OR WEBP_BUILD_DWEBP OR if(WEBP_BUILD_CWEBP OR WEBP_BUILD_DWEBP)
WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP OR WEBP_BUILD_WEBP_JS)
# Example utility library. # Example utility library.
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS" set(exampleutil_SRCS
"example_util_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.c
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/example_util.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h) ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
add_library(exampleutil ${EXAMPLEUTIL_SRCS}) add_library(exampleutil ${exampleutil_SRCS})
target_link_libraries(exampleutil webp ${WEBP_DEP_LIBRARIES})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS" endif()
"imageio_util_[^ ]*")
add_library(imageioutil ${IMAGEIOUTILS_SRCS})
target_link_libraries(imageioutil webp)
if(WEBP_BUILD_CWEBP)
# Image-decoding utility library. # Image-decoding utility library.
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS" set(exampledec_SRCS
"imagedec_[^ ]*") ${CMAKE_CURRENT_SOURCE_DIR}/examples/image_dec.c
add_library(imagedec ${IMAGEDEC_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/examples/image_dec.h
target_link_libraries(imagedec imageioutil webpdemux webp ${CMAKE_CURRENT_SOURCE_DIR}/examples/jpegdec.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/jpegdec.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/metadata.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/metadata.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/pngdec.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/pngdec.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/tiffdec.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/tiffdec.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/webpdec.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/webpdec.h
${CMAKE_CURRENT_SOURCE_DIR}/examples/wicdec.c
${CMAKE_CURRENT_SOURCE_DIR}/examples/wicdec.h)
add_library(exampledec ${exampledec_SRCS})
target_link_libraries(exampledec webp ${WEBP_DEP_LIBRARIES}
${WEBP_DEP_IMG_LIBRARIES}) ${WEBP_DEP_IMG_LIBRARIES})
# Image-encoding utility library.
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEENC_SRCS"
"imageenc_[^ ]*")
add_library(imageenc ${IMAGEENC_SRCS})
target_link_libraries(imageenc webp)
set_property(TARGET exampleutil imageioutil imagedec imageenc
PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src)
endif() endif()
if(WEBP_BUILD_DWEBP) if(WEBP_BUILD_DWEBP)
# dwebp # dwebp
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "DWEBP_SRCS" add_executable(dwebp
"dwebp") ${CMAKE_CURRENT_SOURCE_DIR}/examples/dwebp.c
add_executable(dwebp ${DWEBP_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h
target_link_libraries(dwebp exampleutil imagedec imageenc webpdecoder) )
install(TARGETS dwebp RUNTIME DESTINATION bin) target_link_libraries(dwebp webp exampleutil ${WEBP_DEP_LIBRARIES}
set_property(TARGET dwebp PROPERTY INCLUDE_DIRECTORIES ${WEBP_DEP_IMG_LIBRARIES}
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src) )
endif() endif()
if(WEBP_BUILD_CWEBP) if(WEBP_BUILD_CWEBP)
# cwebp # cwebp
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" add_executable(cwebp
"cwebp") ${CMAKE_CURRENT_SOURCE_DIR}/examples/cwebp.c
add_executable(cwebp ${CWEBP_SRCS}) ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
target_link_libraries(cwebp exampleutil imagedec webp) target_link_libraries(cwebp exampledec webp exampleutil
install(TARGETS cwebp RUNTIME DESTINATION bin) ${WEBP_DEP_LIBRARIES} ${WEBP_DEP_IMG_LIBRARIES}
set_property(TARGET cwebp PROPERTY INCLUDE_DIRECTORIES )
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src)
endif() endif()
if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
unset(WEBP_BUILD_GIF2WEBP CACHE)
endif()
if(WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS"
"")
add_library(webpmux ${WEBP_MUX_SRCS})
target_link_libraries(webpmux webp)
parse_version(mux/Makefile.am webpmux WEBP_MUX_SOVERSION)
set_target_properties(webpmux PROPERTIES VERSION ${PACKAGE_VERSION}
SOVERSION ${WEBP_MUX_SOVERSION})
list(APPEND INSTALLED_LIBRARIES webpmux)
endif()
if(WEBP_BUILD_GIF2WEBP)
# gif2webp
include_directories(${WEBP_DEP_GIF_INCLUDE_DIRS})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "GIF2WEBP_SRCS"
"gif2webp")
add_executable(gif2webp ${GIF2WEBP_SRCS})
target_link_libraries(gif2webp exampleutil imageioutil webp webpmux
${WEBP_DEP_GIF_LIBRARIES})
install(TARGETS gif2webp RUNTIME DESTINATION bin)
set_property(TARGET gif2webp PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
if(WEBP_BUILD_IMG2WEBP)
# img2webp
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "IMG2WEBP_SRCS"
"img2webp")
add_executable(img2webp ${IMG2WEBP_SRCS})
target_link_libraries(img2webp exampleutil imagedec imageioutil webp webpmux)
install(TARGETS img2webp RUNTIME DESTINATION bin)
set_property(TARGET img2webp PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
if (WEBP_BUILD_WEBPINFO)
# webpinfo
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_Makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPINFO_SRCS"
"webpinfo")
add_executable(webpinfo ${WEBPINFO_SRCS})
target_link_libraries(webpinfo exampleutil imageioutil)
install(TARGETS webpinfo RUNTIME DESTINATION bin)
set_property(TARGET webpinfo PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
if(WEBP_BUILD_WEBP_JS)
# JavaScript version
add_executable(webp_js
${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_js webpdecoder SDL)
set(WEBP_HAVE_SDL 1)
set_target_properties(webp_js PROPERTIES LINK_FLAGS
"-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
# WASM version
add_executable(webp_wasm
${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
target_link_libraries(webp_wasm webpdecoder SDL)
set_target_properties(webp_wasm PROPERTIES LINK_FLAGS
"-s WASM=1 -s 'BINARYEN_METHOD=\"native-wasm\"' \
-s EXPORTED_FUNCTIONS='[\"_WebpToSDL\"]' -s INVOKE_RUN=0 \
-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
target_compile_definitions(webpdecoder PUBLIC EMSCRIPTEN)
endif()
# Generate the config.h file.
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h)
add_definitions(-DHAVE_CONFIG_H)
# The webp folder is included as we reference config.h as
# ../webp/config.h or webp/config.h
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Install the different headers and libraries.
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h
DESTINATION include/webp)
install(TARGETS ${INSTALLED_LIBRARIES}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# Create the CMake version file.
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion
)
# Create the Config file.
include(CMakePackageConfigHelpers)
set(ConfigPackageLocation share/WebP/cmake/)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake
INSTALL_DESTINATION ${ConfigPackageLocation}
)
# Install the generated CMake files.
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake"
DESTINATION ${ConfigPackageLocation}
)
# Install the man pages.
set(MAN_PAGES cwebp.1 dwebp.1 gif2webp.1 img2webp.1 vwebp.1 webpmux.1
webpinfo.1)
set(EXEC_BUILDS "CWEBP" "DWEBP" "GIF2WEBP" "IMG2WEBP" "VWEBP" "WEBPMUX"
"WEBPINFO")
list(LENGTH MAN_PAGES MAN_PAGES_LENGTH)
math(EXPR MAN_PAGES_RANGE "${MAN_PAGES_LENGTH} - 1")
foreach(I_MAN RANGE ${MAN_PAGES_RANGE})
list(GET EXEC_BUILDS ${I_MAN} EXEC_BUILD)
if(WEBP_BUILD_${EXEC_BUILD})
list(GET MAN_PAGES ${I_MAN} MAN_PAGE)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man/${MAN_PAGE}
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1
COMPONENT doc
)
endif()
endforeach()

7011
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,3 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src imageio man SUBDIRS = src examples man
EXTRA_DIST = COPYING autogen.sh EXTRA_DIST = COPYING autogen.sh
if WANT_EXTRAS
SUBDIRS += extras
endif
SUBDIRS += examples

View File

@ -29,7 +29,7 @@ PLATFORM_LDFLAGS = /SAFESEH
NOLOGO = /nologo NOLOGO = /nologo
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
CCDEBUG = cl.exe $(NOLOGO) /Od /Gm /Zi /D_DEBUG /RTC1 CCDEBUG = cl.exe $(NOLOGO) /Od /Gm /Zi /D_DEBUG /RTC1
CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c CFLAGS = /Isrc $(NOLOGO) /W3 /EHsc /c
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS) LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
@ -37,8 +37,6 @@ LNKDLL = link.exe /DLL $(NOLOGO)
LNKEXE = link.exe $(NOLOGO) LNKEXE = link.exe $(NOLOGO)
LNKLIB = lib.exe $(NOLOGO) LNKLIB = lib.exe $(NOLOGO)
MT = mt.exe $(NOLOGO) MT = mt.exe $(NOLOGO)
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
RCDEBUG = $(RCNODBG) /D_DEBUG
!IF "$(ARCH)" == "ARM" !IF "$(ARCH)" == "ARM"
CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD
@ -84,8 +82,6 @@ OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \
$(DIROBJ)\dsp \ $(DIROBJ)\dsp \
$(DIROBJ)\enc \ $(DIROBJ)\enc \
$(DIROBJ)\examples \ $(DIROBJ)\examples \
$(DIROBJ)\extras \
$(DIROBJ)\imageio \
$(DIROBJ)\mux \ $(DIROBJ)\mux \
$(DIROBJ)\utils \ $(DIROBJ)\utils \
@ -103,11 +99,9 @@ LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug
LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug
!ELSE IF "$(CFG)" == "release-dynamic" !ELSE IF "$(CFG)" == "release-dynamic"
CC = $(CCNODBG) CC = $(CCNODBG)
RC = $(RCNODBG)
DLLBUILD = TRUE DLLBUILD = TRUE
!ELSE IF "$(CFG)" == "debug-dynamic" !ELSE IF "$(CFG)" == "debug-dynamic"
CC = $(CCDEBUG) CC = $(CCDEBUG)
RC = $(RCDEBUG)
RTLIB = $(RTLIBD) RTLIB = $(RTLIBD)
DLLBUILD = TRUE DLLBUILD = TRUE
LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug
@ -155,7 +149,6 @@ CFGSET = TRUE
!MESSAGE - all - build (de)mux-based targets for CFG !MESSAGE - all - build (de)mux-based targets for CFG
!MESSAGE - gif2webp - requires libgif & >= VS2013 !MESSAGE - gif2webp - requires libgif & >= VS2013
!MESSAGE - anim_diff - requires libgif & >= VS2013 !MESSAGE - anim_diff - requires libgif & >= VS2013
!MESSAGE - anim_dump
!MESSAGE !MESSAGE
!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'. !MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'.
!MESSAGE 'legacy' will produce a Windows 2000 compatible library. !MESSAGE 'legacy' will produce a Windows 2000 compatible library.
@ -176,16 +169,16 @@ CFGSET = TRUE
# #
DEC_OBJS = \ DEC_OBJS = \
$(DIROBJ)\dec\alpha_dec.obj \ $(DIROBJ)\dec\alpha.obj \
$(DIROBJ)\dec\buffer_dec.obj \ $(DIROBJ)\dec\buffer.obj \
$(DIROBJ)\dec\frame_dec.obj \ $(DIROBJ)\dec\frame.obj \
$(DIROBJ)\dec\idec_dec.obj \ $(DIROBJ)\dec\idec.obj \
$(DIROBJ)\dec\io_dec.obj \ $(DIROBJ)\dec\io.obj \
$(DIROBJ)\dec\quant_dec.obj \ $(DIROBJ)\dec\quant.obj \
$(DIROBJ)\dec\tree_dec.obj \ $(DIROBJ)\dec\tree.obj \
$(DIROBJ)\dec\vp8_dec.obj \ $(DIROBJ)\dec\vp8.obj \
$(DIROBJ)\dec\vp8l_dec.obj \ $(DIROBJ)\dec\vp8l.obj \
$(DIROBJ)\dec\webp_dec.obj \ $(DIROBJ)\dec\webp.obj \
DEMUX_OBJS = \ DEMUX_OBJS = \
$(DIROBJ)\demux\anim_decode.obj \ $(DIROBJ)\demux\anim_decode.obj \
@ -194,7 +187,6 @@ DEMUX_OBJS = \
DSP_DEC_OBJS = \ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\alpha_processing.obj \ $(DIROBJ)\dsp\alpha_processing.obj \
$(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \ $(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \
$(DIROBJ)\dsp\alpha_processing_neon.obj \
$(DIROBJ)\dsp\alpha_processing_sse2.obj \ $(DIROBJ)\dsp\alpha_processing_sse2.obj \
$(DIROBJ)\dsp\alpha_processing_sse41.obj \ $(DIROBJ)\dsp\alpha_processing_sse41.obj \
$(DIROBJ)\dsp\cpu.obj \ $(DIROBJ)\dsp\cpu.obj \
@ -208,34 +200,29 @@ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\dec_sse41.obj \ $(DIROBJ)\dsp\dec_sse41.obj \
$(DIROBJ)\dsp\filters.obj \ $(DIROBJ)\dsp\filters.obj \
$(DIROBJ)\dsp\filters_mips_dsp_r2.obj \ $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \
$(DIROBJ)\dsp\filters_msa.obj \
$(DIROBJ)\dsp\filters_neon.obj \
$(DIROBJ)\dsp\filters_sse2.obj \ $(DIROBJ)\dsp\filters_sse2.obj \
$(DIROBJ)\dsp\lossless.obj \ $(DIROBJ)\dsp\lossless.obj \
$(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \ $(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \
$(DIROBJ)\dsp\lossless_msa.obj \
$(DIROBJ)\dsp\lossless_neon.obj \ $(DIROBJ)\dsp\lossless_neon.obj \
$(DIROBJ)\dsp\lossless_sse2.obj \ $(DIROBJ)\dsp\lossless_sse2.obj \
$(DIROBJ)\dsp\rescaler.obj \ $(DIROBJ)\dsp\rescaler.obj \
$(DIROBJ)\dsp\rescaler_mips32.obj \ $(DIROBJ)\dsp\rescaler_mips32.obj \
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \ $(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
$(DIROBJ)\dsp\rescaler_msa.obj \
$(DIROBJ)\dsp\rescaler_neon.obj \ $(DIROBJ)\dsp\rescaler_neon.obj \
$(DIROBJ)\dsp\rescaler_sse2.obj \ $(DIROBJ)\dsp\rescaler_sse2.obj \
$(DIROBJ)\dsp\upsampling.obj \ $(DIROBJ)\dsp\upsampling.obj \
$(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \ $(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \
$(DIROBJ)\dsp\upsampling_msa.obj \
$(DIROBJ)\dsp\upsampling_neon.obj \ $(DIROBJ)\dsp\upsampling_neon.obj \
$(DIROBJ)\dsp\upsampling_sse2.obj \ $(DIROBJ)\dsp\upsampling_sse2.obj \
$(DIROBJ)\dsp\upsampling_sse41.obj \
$(DIROBJ)\dsp\yuv.obj \ $(DIROBJ)\dsp\yuv.obj \
$(DIROBJ)\dsp\yuv_mips32.obj \ $(DIROBJ)\dsp\yuv_mips32.obj \
$(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \ $(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \
$(DIROBJ)\dsp\yuv_neon.obj \
$(DIROBJ)\dsp\yuv_sse2.obj \ $(DIROBJ)\dsp\yuv_sse2.obj \
$(DIROBJ)\dsp\yuv_sse41.obj \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\argb.obj \
$(DIROBJ)\dsp\argb_mips_dsp_r2.obj \
$(DIROBJ)\dsp\argb_sse2.obj \
$(DIROBJ)\dsp\cost.obj \ $(DIROBJ)\dsp\cost.obj \
$(DIROBJ)\dsp\cost_mips32.obj \ $(DIROBJ)\dsp\cost_mips32.obj \
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \ $(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
@ -244,35 +231,27 @@ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\enc_avx2.obj \ $(DIROBJ)\dsp\enc_avx2.obj \
$(DIROBJ)\dsp\enc_mips32.obj \ $(DIROBJ)\dsp\enc_mips32.obj \
$(DIROBJ)\dsp\enc_mips_dsp_r2.obj \ $(DIROBJ)\dsp\enc_mips_dsp_r2.obj \
$(DIROBJ)\dsp\enc_msa.obj \
$(DIROBJ)\dsp\enc_neon.obj \ $(DIROBJ)\dsp\enc_neon.obj \
$(DIROBJ)\dsp\enc_sse2.obj \ $(DIROBJ)\dsp\enc_sse2.obj \
$(DIROBJ)\dsp\enc_sse41.obj \ $(DIROBJ)\dsp\enc_sse41.obj \
$(DIROBJ)\dsp\lossless_enc.obj \ $(DIROBJ)\dsp\lossless_enc.obj \
$(DIROBJ)\dsp\lossless_enc_mips32.obj \ $(DIROBJ)\dsp\lossless_enc_mips32.obj \
$(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \ $(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \
$(DIROBJ)\dsp\lossless_enc_msa.obj \
$(DIROBJ)\dsp\lossless_enc_neon.obj \ $(DIROBJ)\dsp\lossless_enc_neon.obj \
$(DIROBJ)\dsp\lossless_enc_sse2.obj \ $(DIROBJ)\dsp\lossless_enc_sse2.obj \
$(DIROBJ)\dsp\lossless_enc_sse41.obj \ $(DIROBJ)\dsp\lossless_enc_sse41.obj \
$(DIROBJ)\dsp\ssim.obj \
$(DIROBJ)\dsp\ssim_sse2.obj \
EX_ANIM_UTIL_OBJS = \ EX_ANIM_UTIL_OBJS = \
$(DIROBJ)\examples\anim_util.obj \ $(DIROBJ)\examples\anim_util.obj \
IMAGEIO_DEC_OBJS = \ EX_FORMAT_DEC_OBJS = \
$(DIROBJ)\imageio\image_dec.obj \ $(DIROBJ)\examples\image_dec.obj \
$(DIROBJ)\imageio\jpegdec.obj \ $(DIROBJ)\examples\jpegdec.obj \
$(DIROBJ)\imageio\metadata.obj \ $(DIROBJ)\examples\metadata.obj \
$(DIROBJ)\imageio\pngdec.obj \ $(DIROBJ)\examples\pngdec.obj \
$(DIROBJ)\imageio\pnmdec.obj \ $(DIROBJ)\examples\tiffdec.obj \
$(DIROBJ)\imageio\tiffdec.obj \ $(DIROBJ)\examples\webpdec.obj \
$(DIROBJ)\imageio\webpdec.obj \ $(DIROBJ)\examples\wicdec.obj \
$(DIROBJ)\imageio\wicdec.obj \
IMAGEIO_ENC_OBJS = \
$(DIROBJ)\imageio\image_enc.obj \
EX_GIF_DEC_OBJS = \ EX_GIF_DEC_OBJS = \
$(DIROBJ)\examples\gifdec.obj \ $(DIROBJ)\examples\gifdec.obj \
@ -281,36 +260,28 @@ EX_UTIL_OBJS = \
$(DIROBJ)\examples\example_util.obj \ $(DIROBJ)\examples\example_util.obj \
ENC_OBJS = \ ENC_OBJS = \
$(DIROBJ)\enc\alpha_enc.obj \ $(DIROBJ)\enc\alpha.obj \
$(DIROBJ)\enc\analysis_enc.obj \ $(DIROBJ)\enc\analysis.obj \
$(DIROBJ)\enc\backward_references_cost_enc.obj \ $(DIROBJ)\enc\backward_references.obj \
$(DIROBJ)\enc\backward_references_enc.obj \ $(DIROBJ)\enc\config.obj \
$(DIROBJ)\enc\config_enc.obj \ $(DIROBJ)\enc\cost.obj \
$(DIROBJ)\enc\cost_enc.obj \ $(DIROBJ)\enc\delta_palettization.obj \
$(DIROBJ)\enc\filter_enc.obj \ $(DIROBJ)\enc\filter.obj \
$(DIROBJ)\enc\frame_enc.obj \ $(DIROBJ)\enc\frame.obj \
$(DIROBJ)\enc\histogram_enc.obj \ $(DIROBJ)\enc\histogram.obj \
$(DIROBJ)\enc\iterator_enc.obj \ $(DIROBJ)\enc\iterator.obj \
$(DIROBJ)\enc\near_lossless_enc.obj \ $(DIROBJ)\enc\near_lossless.obj \
$(DIROBJ)\enc\picture_enc.obj \ $(DIROBJ)\enc\picture.obj \
$(DIROBJ)\enc\picture_csp_enc.obj \ $(DIROBJ)\enc\picture_csp.obj \
$(DIROBJ)\enc\picture_psnr_enc.obj \ $(DIROBJ)\enc\picture_psnr.obj \
$(DIROBJ)\enc\picture_rescale_enc.obj \ $(DIROBJ)\enc\picture_rescale.obj \
$(DIROBJ)\enc\picture_tools_enc.obj \ $(DIROBJ)\enc\picture_tools.obj \
$(DIROBJ)\enc\predictor_enc.obj \ $(DIROBJ)\enc\quant.obj \
$(DIROBJ)\enc\quant_enc.obj \ $(DIROBJ)\enc\syntax.obj \
$(DIROBJ)\enc\syntax_enc.obj \ $(DIROBJ)\enc\token.obj \
$(DIROBJ)\enc\token_enc.obj \ $(DIROBJ)\enc\tree.obj \
$(DIROBJ)\enc\tree_enc.obj \ $(DIROBJ)\enc\vp8l.obj \
$(DIROBJ)\enc\vp8l_enc.obj \ $(DIROBJ)\enc\webpenc.obj \
$(DIROBJ)\enc\webp_enc.obj \
EXTRAS_OBJS = \
$(DIROBJ)\extras\extras.obj \
$(DIROBJ)\extras\quality_estimate.obj \
IMAGEIO_UTIL_OBJS = \
$(DIROBJ)\imageio\imageio_util.obj \
MUX_OBJS = \ MUX_OBJS = \
$(DIROBJ)\mux\anim_encode.obj \ $(DIROBJ)\mux\anim_encode.obj \
@ -319,20 +290,20 @@ MUX_OBJS = \
$(DIROBJ)\mux\muxread.obj \ $(DIROBJ)\mux\muxread.obj \
UTILS_DEC_OBJS = \ UTILS_DEC_OBJS = \
$(DIROBJ)\utils\bit_reader_utils.obj \ $(DIROBJ)\utils\bit_reader.obj \
$(DIROBJ)\utils\color_cache_utils.obj \ $(DIROBJ)\utils\color_cache.obj \
$(DIROBJ)\utils\filters_utils.obj \ $(DIROBJ)\utils\filters.obj \
$(DIROBJ)\utils\huffman_utils.obj \ $(DIROBJ)\utils\huffman.obj \
$(DIROBJ)\utils\quant_levels_dec_utils.obj \ $(DIROBJ)\utils\quant_levels_dec.obj \
$(DIROBJ)\utils\rescaler_utils.obj \ $(DIROBJ)\utils\rescaler.obj \
$(DIROBJ)\utils\random_utils.obj \ $(DIROBJ)\utils\random.obj \
$(DIROBJ)\utils\thread_utils.obj \ $(DIROBJ)\utils\thread.obj \
$(DIROBJ)\utils\utils.obj \ $(DIROBJ)\utils\utils.obj \
UTILS_ENC_OBJS = \ UTILS_ENC_OBJS = \
$(DIROBJ)\utils\bit_writer_utils.obj \ $(DIROBJ)\utils\bit_writer.obj \
$(DIROBJ)\utils\huffman_encode_utils.obj \ $(DIROBJ)\utils\huffman_encode.obj \
$(DIROBJ)\utils\quant_levels_utils.obj \ $(DIROBJ)\utils\quant_levels.obj \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS) LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \ LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
@ -346,10 +317,7 @@ ex: $(OUT_LIBS)
all: ex all: ex
!ELSE !ELSE
OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe
EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \ EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe
$(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \
$(DIRBIN)\webp_quality.exe $(DIRBIN)\vwebp_sdl.exe \
$(DIRBIN)\webpinfo.exe
ex: $(OUT_LIBS) $(OUT_EXAMPLES) ex: $(OUT_LIBS) $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES) all: ex $(EXTRA_EXAMPLES)
@ -357,52 +325,27 @@ all: ex $(EXTRA_EXAMPLES)
# C99 support which is only available from VS2013 onward. # C99 support which is only available from VS2013 onward.
gif2webp: $(DIRBIN)\gif2webp.exe gif2webp: $(DIRBIN)\gif2webp.exe
anim_diff: $(DIRBIN)\anim_diff.exe anim_diff: $(DIRBIN)\anim_diff.exe
anim_dump: $(DIRBIN)\anim_dump.exe
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS) $(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) $(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS) $(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS)
$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj
$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS) $(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX) $(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(LIBWEBPMUX) $(LIBWEBP)
$(DIRBIN)\gif2webp.exe: $(LIBWEBP) $(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS) $(DIRBIN)\vwebp.exe: $(EX_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\webp_to_sdl.obj
$(DIRBIN)\vwebp_sdl.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX) $(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX)
$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP) $(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj
$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) $(LIBWEBP)
$(DIRBIN)\webpinfo.exe: $(DIROBJ)\examples\webpinfo.obj
$(DIRBIN)\webpinfo.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\webpinfo.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\webpinfo.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP) $(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP)
$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS) $(EX_UTIL_OBJS) $(EX_FORMAT_DEC_OBJS): $(OUTPUT_DIRS)
$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS)
!ENDIF # ARCH == ARM !ENDIF # ARCH == ARM
experimental:
$(MAKE) /f Makefile.vc \
CFG=$(CFG) \
CFLAGS="$(CFLAGS) /DWEBP_EXPERIMENTAL_FEATURES" /$(MAKEFLAGS)
$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS) $(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS)
$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBWEBP): $(LIBWEBP_OBJS)
$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS) $(LIBWEBPMUX): $(LIBWEBPMUX_OBJS)
@ -417,17 +360,8 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
{$(DIROBJ)}.c{$(DIROBJ)}.obj: {$(DIROBJ)}.c{$(DIROBJ)}.obj:
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $<
{src}.rc{$(DIROBJ)}.res: $(LIBWEBPMUX): $(LIBWEBP)
$(RC) /fo$@ $< $(LIBWEBPDEMUX): $(LIBWEBP)
{src\demux}.rc{$(DIROBJ)\demux}.res:
$(RC) /fo$@ $<
{src\mux}.rc{$(DIROBJ)\mux}.res:
$(RC) /fo$@ $<
$(LIBWEBP): $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res
$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res
$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res
$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $** $(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $**
@ -448,7 +382,7 @@ $(OUTPUT_DIRS):
$(DIROBJ)\$(DLLINC): $(DIROBJ)\$(DLLINC):
@echo #ifndef WEBP_DLL_H_ > $@ @echo #ifndef WEBP_DLL_H_ > $@
@echo #define WEBP_DLL_H_ >> $@ @echo #define WEBP_DLL_H_ >> $@
@echo #define WEBP_EXTERN __declspec(dllexport) >> $@ @echo #define WEBP_EXTERN(type) __declspec(dllexport) type >> $@
@echo #endif /* WEBP_DLL_H_ */ >> $@ @echo #endif /* WEBP_DLL_H_ */ >> $@
.SUFFIXES: .c .obj .res .exe .SUFFIXES: .c .obj .res .exe
@ -460,9 +394,6 @@ $(DIROBJ)\dsp\enc_avx2.obj: src\dsp\enc_avx2.c
$(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c $(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c /Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c $(DIROBJ)\examples\anim_util.obj: examples\anim_util.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c /Fo$(DIROBJ)\examples\ examples\$(@B).c
@ -475,10 +406,6 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
# Batch rules # Batch rules
{examples}.c{$(DIROBJ)\examples}.obj:: {examples}.c{$(DIROBJ)\examples}.obj::
$(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $< $(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $<
{extras}.c{$(DIROBJ)\extras}.obj::
$(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $<
{imageio}.c{$(DIROBJ)\imageio}.obj::
$(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $<
{src\dec}.c{$(DIROBJ)\dec}.obj:: {src\dec}.c{$(DIROBJ)\dec}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $<
{src\demux}.c{$(DIROBJ)\demux}.obj:: {src\demux}.c{$(DIROBJ)\demux}.obj::
@ -498,12 +425,6 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
$(MT) -manifest $@.manifest -outputresource:$@;1 $(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest del $@.manifest
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
ole32.lib windowscodecs.lib shlwapi.lib
$(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest
clean:: clean::
@-erase /s $(DIROBJ)\*.dll 2> NUL @-erase /s $(DIROBJ)\*.dll 2> NUL
@-erase /s $(DIROBJ)\*.exp 2> NUL @-erase /s $(DIROBJ)\*.exp 2> NUL

38
NEWS
View File

@ -1,41 +1,3 @@
- 4/2/2018: version 1.0.0
This is a binary compatible release.
* lossy encoder improvements to avoid chroma shifts in various circumstances
(issues #308, #340)
* big-endian fixes for decode, RGBA import and WebPPictureDistortion
Tool updates:
gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
web browsers, transcoding tools (issue #379)
img2webp, webpmux - allow options to be passed in via a file (issue #355)
- 11/24/2017: version 0.6.1
This is a binary compatible release.
* lossless performance and compression improvements + a new 'cruncher' mode
(-m 6 -q 100)
* ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
* webp-js: emscripten/webassembly based javascript decoder
* miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
#363)
Tool updates / additions:
added webpinfo - prints file format information (issue #330)
gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
'-loop_compatibility' can be used for the old behavior
- 1/26/2017: version 0.6.0
* lossless performance and compression improvements
* miscellaneous performance improvements (SSE2, NEON, MSA)
* webpmux gained a -duration option allowing for frame timing modification
* new img2webp utility allowing a sequence of images to be converted to
animated webp
* API changes:
- libwebp:
WebPPictureSharpARGBToYUVA
WebPPlaneDistortion
- libwebpmux / gif2webp:
WebPAnimEncoderOptions: kmax <= 0 now disables keyframes, kmax == 1
forces all keyframes. See mux.h and the gif2webp
manpage for details.
- 12/13/2016: version 0.5.2 - 12/13/2016: version 0.5.2
This is a binary compatible release. This is a binary compatible release.
This release covers CVE-2016-8888 and CVE-2016-9085. This release covers CVE-2016-8888 and CVE-2016-9085.

75
README
View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.0.0 \____/____/\_____/_____/____/v0.5.2
Description: Description:
============ ============
@ -113,8 +113,8 @@ make install
CMake: CMake:
------ ------
With CMake, you can compile libwebp, cwebp, dwebp, gif2web, img2webp, webpinfo The support for CMake is minimal: it only helps you compile libwebp, cwebp and
and the JS bindings. dwebp.
Prerequisites: Prerequisites:
A compiler (e.g., gcc with autotools) and CMake. A compiler (e.g., gcc with autotools) and CMake.
@ -123,25 +123,18 @@ minimal build:
$ sudo apt-get install build-essential cmake $ sudo apt-get install build-essential cmake
When building from git sources, you will need to run cmake to generate the When building from git sources, you will need to run cmake to generate the
makefiles. configure script.
mkdir build && cd build && cmake ../ mkdir build && cd build && cmake ../
make make
make install make install
If you also want any of the executables, you will need to enable them through If you also want cwebp or dwebp, you will need to enable them through CMake:
CMake, e.g.:
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../ 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).
Finally, once installed, you can also use WebP in your CMake project by doing:
find_package(WebP)
which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
Gradle: Gradle:
------- -------
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
@ -248,7 +241,6 @@ Options:
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0 -sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0
-strong ................ use strong filter instead of simple (default) -strong ................ use strong filter instead of simple (default)
-nostrong .............. use simple filter instead of strong -nostrong .............. use simple filter instead of strong
-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
-partition_limit <int> . limit quality to fit the 512k limit on -partition_limit <int> . limit quality to fit the 512k limit on
the first partition (0=no degradation ... 100=full) the first partition (0=no degradation ... 100=full)
-pass <int> ............ analysis pass number (1..10) -pass <int> ............ analysis pass number (1..10)
@ -367,23 +359,6 @@ Use following options to convert into alternate image formats:
-quiet ....... quiet mode, don't print anything -quiet ....... quiet mode, don't print anything
-noasm ....... disable all assembly optimizations -noasm ....... disable all assembly optimizations
WebP file analysis tool:
========================
'webpinfo' can be used to print out the chunk level structure and bitstream
header information of WebP files. It can also check if the files are of valid
WebP format.
Usage: webpinfo [options] in_files
Note: there could be multiple input files;
options must come before input files.
Options:
-version ........... Print version number and exit.
-quiet ............. Do not show chunk parsing information.
-diag .............. Show parsing error diagnosis.
-summary ........... Show chunk stats summary.
-bitstream_info .... Parse bitstream header.
Visualization tool: Visualization tool:
=================== ===================
@ -409,7 +384,6 @@ Options are:
Keyboard shortcuts: Keyboard shortcuts:
'c' ................ toggle use of color profile 'c' ................ toggle use of color profile
'i' ................ overlay file information 'i' ................ overlay file information
'd' ................ disable blending & disposal (debug)
'q' / 'Q' / ESC .... quit 'q' / 'Q' / ESC .... quit
Building: Building:
@ -438,38 +412,6 @@ $ make -f makefile.unix examples/vwebp
> nmake /f Makefile.vc CFG=release-static \ > nmake /f Makefile.vc CFG=release-static \
../obj/x64/release-static/bin/vwebp.exe ../obj/x64/release-static/bin/vwebp.exe
Animation creation tool:
========================
The utility 'img2webp' can turn a sequence of input images (PNG, JPEG, ...)
into an animated WebP file. It offers fine control over duration, encoding
modes, etc.
Usage:
img2webp [file-level options] [image files...] [per-frame options...]
File-level options (only used at the start of compression):
-min_size ............ minimize size
-loop <int> .......... loop count (default: 0, = infinite loop)
-kmax <int> .......... maximum number of frame between key-frames
(0=only keyframes)
-kmin <int> .......... minimum number of frame between key-frames
(0=disable key-frames altogether)
-mixed ............... use mixed lossy/lossless automatic mode
-v ................... verbose mode
-h ................... this help
-version ............. print version number and exit
Per-frame options (only used for subsequent images input):
-d <int> ............. frame duration in ms (default: 100)
-lossless ........... use lossless mode (default)
-lossy ... ........... use lossy mode
-q <float> ........... quality
-m <int> ............. method to use
example: img2webp -loop 2 in0.png -lossy in1.jpg
-d 80 in2.tiff -o out.webp
Animated GIF conversion: Animated GIF conversion:
======================== ========================
Animated GIF files can be converted to WebP files with animation using the Animated GIF files can be converted to WebP files with animation using the
@ -495,8 +437,6 @@ Options:
-metadata <string> ..... comma separated list of metadata to -metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present copy from the input to the output if present
Valid values: all, none, icc, xmp (default) Valid values: all, none, icc, xmp (default)
-loop_compatibility .... use compatibility mode for Chrome
version prior to M62 (inclusive)
-mt .................... use multi-threading if available -mt .................... use multi-threading if available
-version ............... print version number and exit -version ............... print version number and exit
@ -525,11 +465,6 @@ Options:
-min_psnr <float> ... minimum per-frame PSNR -min_psnr <float> ... minimum per-frame PSNR
-raw_comparison ..... if this flag is not used, RGB is -raw_comparison ..... if this flag is not used, RGB is
premultiplied before comparison premultiplied before comparison
-max_diff <int> ..... maximum allowed difference per channel
between corresponding pixels in subsequent
frames
-h .................. this help
-version ............ print version number and exit
Building: Building:
--------- ---------

View File

@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __  __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\ / \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__ \ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.0 \__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.3.2
Description: Description:
@ -25,15 +25,12 @@ A list of options is available using the -help command line flag:
> webpmux -help > webpmux -help
Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
webpmux -set SET_OPTIONS INPUT -o OUTPUT webpmux -set SET_OPTIONS INPUT -o OUTPUT
webpmux -duration DURATION_OPTIONS [-duration ...]
INPUT -o OUTPUT
webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT
webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT] webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]
[-bgcolor BACKGROUND_COLOR] -o OUTPUT [-bgcolor BACKGROUND_COLOR] -o OUTPUT
webpmux -info INPUT webpmux -info INPUT
webpmux [-h|-help] webpmux [-h|-help]
webpmux -version webpmux -version
webpmux argument_file_name
GET_OPTIONS: GET_OPTIONS:
Extract relevant data: Extract relevant data:
@ -51,17 +48,6 @@ SET_OPTIONS:
'file.exif' contains the EXIF metadata to be set 'file.exif' contains the EXIF metadata to be set
'file.xmp' contains the XMP metadata to be set 'file.xmp' contains the XMP metadata to be set
DURATION_OPTIONS:
Set duration of selected frames:
duration set duration for each frames
duration,frame set duration of a particular frame
duration,start,end set duration of frames in the
interval [start,end])
where: 'duration' is the duration in milliseconds
'start' is the start frame index
'end' is the inclusive end frame index
The special 'end' value '0' means: last frame.
STRIP_OPTIONS: STRIP_OPTIONS:
Strip color profile/metadata: Strip color profile/metadata:
icc strip ICC profile icc strip ICC profile
@ -93,9 +79,6 @@ INPUT & OUTPUT are in WebP format.
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
valid. valid.
Note: if a single file name is passed as the argument, the arguments will be
tokenized from this file. The file name must not start with the character '-'.
Visualization tool: Visualization tool:
=================== ===================

View File

@ -1,76 +0,0 @@
__ __ ____ ____ ____ __ ____
/ \\/ \ _ \ _ \ _ \ (__)/ __\
\ / __/ _ \ __/ _) \_ \
\__\__/_____/____/_/ /____/____/
Description:
============
This file describes the compilation of libwebp into a JavaScript decoder
using Emscripten and CMake.
- install the Emscripten SDK following the procedure described at:
https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
After installation, you should have some global variable positioned to the
location of the SDK. In particular, $EMSCRIPTEN should point to the
top-level directory containing Emscripten tools.
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
accessible. This is the toolchain file used by CMake to invoke Emscripten.
- configure the project 'WEBP_JS' with CMake using:
cd webp_js && \
cmake -DWEBP_BUILD_WEBP_JS=ON \
-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 \
-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake \
../
- compile webp.js using 'make'.
- that's it! Upon completion, you should have the webp.js and
webp.js.mem files generated.
The callable JavaScript function is WebPToSDL(), which decodes a raw WebP
bitstream into a canvas. See webp_js/index.html for a simple usage sample
(see below for instructions).
Demo HTML page:
===============
The HTML page webp_js/index.html requires an HTTP server to serve the WebP
image example. It's easy to just use Python for that.
cd webp_js && python -m SimpleHTTPServer 8080
and then navigate to http://localhost:8080 in your favorite browser.
Web-Assembly (WASM) version:
============================
CMakeLists.txt is configured to build the WASM version when using
the option WEBP_BUILD_WEBP_JS=ON. The compilation step will assemble
the files 'webp_wasm.js', 'webp_wasm.wasm' in the webp_js/ directory.
See webp_js/index_wasm.html for a simple demo page using the WASM version
of the library.
You will need a fairly recent version of Emscripten (at least 1.37.8) and of
your WASM-enabled browser to run this version. Consider it very experimental!
Caveat:
=======
- First decoding using the library is usually slower, due to just-in-time
compilation.
- Some versions of llvm produce the following compile error when SSE2 is
enabled.
"Unsupported: %516 = bitcast <8 x i16> %481 to i128
LLVM ERROR: BitCast Instruction not yet supported for integer types larger than 64 bits"
The corresponding Emscripten bug is at:
https://github.com/kripken/emscripten/issues/3788
Therefore, SSE2 optimization is currently disabled in CMakeLists.txt.

View File

@ -74,22 +74,12 @@ model {
cCompiler.args "-frename-registers -s" cCompiler.args "-frename-registers -s"
} }
} }
// mips32 fails to build with clang from r14b
// https://bugs.chromium.org/p/webp/issues/detail?id=343
if (toolChain in Clang) {
if (getTargetPlatform() == "mips") {
cCompiler.args "-no-integrated-as"
}
}
// Check for NEON usage. // Check for NEON usage.
if (getTargetPlatform() == "arm") { if (getTargetPlatform() == "arm" || getTargetPlatform() == "arm64") {
NEON = "c.neon" NEON = "c.neon"
cCompiler.define "HAVE_CPU_FEATURES_H"
} else { } else {
NEON = "c" NEON = "c"
} }
cCompiler.args "-I" + file(".").absolutePath
} }
// Link to pthread for shared libraries. // Link to pthread for shared libraries.
withType(SharedLibraryBinarySpec) { withType(SharedLibraryBinarySpec) {
@ -106,22 +96,24 @@ model {
c { c {
source { source {
srcDir "src/dec" srcDir "src/dec"
include "alpha_dec.c" include "alpha.c"
include "buffer_dec.c" include "buffer.c"
include "frame_dec.c" include "frame.c"
include "idec_dec.c" include "idec.c"
include "io_dec.c" include "io.c"
include "quant_dec.c" include "quant.c"
include "tree_dec.c" include "tree.c"
include "vp8_dec.c" include "vp8.c"
include "vp8l_dec.c" include "vp8l.c"
include "webp_dec.c" include "webp.c"
srcDir "src/dsp" srcDir "src/dsp"
include "alpha_processing.c" include "alpha_processing.c"
include "alpha_processing_mips_dsp_r2.c" include "alpha_processing_mips_dsp_r2.c"
include "alpha_processing_neon.$NEON"
include "alpha_processing_sse2.c" include "alpha_processing_sse2.c"
include "alpha_processing_sse41.c" include "alpha_processing_sse41.c"
include "argb.c"
include "argb_mips_dsp_r2.c"
include "argb_sse2.c"
include "cpu.c" include "cpu.c"
include "dec.c" include "dec.c"
include "dec_clip_tables.c" include "dec_clip_tables.c"
@ -133,41 +125,34 @@ model {
include "dec_sse41.c" include "dec_sse41.c"
include "filters.c" include "filters.c"
include "filters_mips_dsp_r2.c" include "filters_mips_dsp_r2.c"
include "filters_msa.c"
include "filters_neon.$NEON"
include "filters_sse2.c" include "filters_sse2.c"
include "lossless.c" include "lossless.c"
include "lossless_mips_dsp_r2.c" include "lossless_mips_dsp_r2.c"
include "lossless_msa.c"
include "lossless_neon.$NEON" include "lossless_neon.$NEON"
include "lossless_sse2.c" include "lossless_sse2.c"
include "rescaler.c" include "rescaler.c"
include "rescaler_mips32.c" include "rescaler_mips32.c"
include "rescaler_mips_dsp_r2.c" include "rescaler_mips_dsp_r2.c"
include "rescaler_msa.c"
include "rescaler_neon.$NEON" include "rescaler_neon.$NEON"
include "rescaler_sse2.c" include "rescaler_sse2.c"
include "upsampling.c" include "upsampling.c"
include "upsampling_mips_dsp_r2.c" include "upsampling_mips_dsp_r2.c"
include "upsampling_msa.c"
include "upsampling_neon.$NEON" include "upsampling_neon.$NEON"
include "upsampling_sse2.c" include "upsampling_sse2.c"
include "upsampling_sse41.c"
include "yuv.c" include "yuv.c"
include "yuv_mips32.c" include "yuv_mips32.c"
include "yuv_mips_dsp_r2.c" include "yuv_mips_dsp_r2.c"
include "yuv_neon.$NEON"
include "yuv_sse2.c" include "yuv_sse2.c"
include "yuv_sse41.c"
srcDir "src/utils" srcDir "src/utils"
include "bit_reader_utils.c" include "ans.c"
include "color_cache_utils.c" include "bit_reader.c"
include "filters_utils.c" include "color_cache.c"
include "huffman_utils.c" include "filters.c"
include "quant_levels_dec_utils.c" include "huffman.c"
include "random_utils.c" include "quant_levels_dec.c"
include "rescaler_utils.c" include "random.c"
include "thread_utils.c" include "rescaler.c"
include "thread.c"
include "utils.c" include "utils.c"
srcDir "src/dsp" srcDir "src/dsp"
include "cost.c" include "cost.c"
@ -178,47 +163,42 @@ model {
include "enc_avx2.c" include "enc_avx2.c"
include "enc_mips32.c" include "enc_mips32.c"
include "enc_mips_dsp_r2.c" include "enc_mips_dsp_r2.c"
include "enc_msa.c"
include "enc_neon.$NEON" include "enc_neon.$NEON"
include "enc_sse2.c" include "enc_sse2.c"
include "enc_sse41.c" include "enc_sse41.c"
include "lossless_enc.c" include "lossless_enc.c"
include "lossless_enc_mips32.c" include "lossless_enc_mips32.c"
include "lossless_enc_mips_dsp_r2.c" include "lossless_enc_mips_dsp_r2.c"
include "lossless_enc_msa.c"
include "lossless_enc_neon.$NEON" include "lossless_enc_neon.$NEON"
include "lossless_enc_sse2.c" include "lossless_enc_sse2.c"
include "lossless_enc_sse41.c" include "lossless_enc_sse41.c"
include "ssim.c"
include "ssim_sse2.c"
srcDir "src/enc" srcDir "src/enc"
include "alpha_enc.c" include "alpha.c"
include "analysis_enc.c" include "analysis.c"
include "backward_references_cost_enc.c" include "backward_references.c"
include "backward_references_enc.c" include "config.c"
include "config_enc.c" include "cost.c"
include "cost_enc.c" include "delta_palettization.c"
include "filter_enc.c" include "filter.c"
include "frame_enc.c" include "frame.c"
include "histogram_enc.c" include "histogram.c"
include "iterator_enc.c" include "iterator.c"
include "near_lossless_enc.c" include "near_lossless.c"
include "picture_enc.c" include "picture.c"
include "picture_csp_enc.c" include "picture_csp.c"
include "picture_psnr_enc.c" include "picture_psnr.c"
include "picture_rescale_enc.c" include "picture_rescale.c"
include "picture_tools_enc.c" include "picture_tools.c"
include "predictor_enc.c" include "quant.c"
include "quant_enc.c" include "syntax.c"
include "syntax_enc.c" include "token.c"
include "token_enc.c" include "tree.c"
include "tree_enc.c" include "vp8l.c"
include "vp8l_enc.c" include "webpenc.c"
include "webp_enc.c"
srcDir "src/utils" srcDir "src/utils"
include "bit_writer_utils.c" include "bit_writer.c"
include "huffman_encode_utils.c" include "huffman_encode.c"
include "quant_levels_utils.c" include "quant_levels.c"
} }
exportedHeaders { exportedHeaders {
srcDir "src" srcDir "src"
@ -270,7 +250,7 @@ model {
} }
} }
imageio_util(NativeLibrarySpec) { example_dec(NativeLibrarySpec) {
binaries { binaries {
all { all {
lib library: "webp", linkage: "static" lib library: "webp", linkage: "static"
@ -279,60 +259,22 @@ model {
sources { sources {
c { c {
source { source {
srcDir "./imageio" srcDir "./examples"
include "imageio_util.c"
}
}
}
}
imagedec(NativeLibrarySpec) {
binaries {
all {
lib library: "webpdemux", linkage: "static"
lib library: "webp", linkage: "static"
}
}
sources {
c {
source {
srcDir "./imageio"
include "image_dec.c" include "image_dec.c"
include "jpegdec.c" include "jpegdec.c"
include "metadata.c" include "metadata.c"
include "pngdec.c" include "pngdec.c"
include "pnmdec.c"
include "tiffdec.c" include "tiffdec.c"
include "webpdec.c" include "webpdec.c"
} }
} }
} }
} }
imageenc(NativeLibrarySpec) {
binaries {
all {
lib library: "webp", linkage: "static"
lib library: "imageio_util", linkage: "static"
}
}
sources {
c {
source {
srcDir "./imageio"
include "image_enc.c"
}
}
}
}
cwebp(NativeExecutableSpec) { cwebp(NativeExecutableSpec) {
binaries { binaries {
all { all {
lib library: "example_util", linkage: "static" lib library: "example_util", linkage: "static"
lib library: "imagedec", linkage: "static" lib library: "example_dec", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp", linkage: "static" lib library: "webp", linkage: "static"
} }
} }
@ -350,10 +292,6 @@ model {
binaries { binaries {
all { all {
lib library: "example_util", linkage: "static" lib library: "example_util", linkage: "static"
lib library: "imagedec", linkage: "static"
lib library: "imageenc", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp" lib library: "webp"
} }
} }
@ -371,7 +309,6 @@ model {
binaries { binaries {
all { all {
lib library: "example_util", linkage: "static" lib library: "example_util", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpmux", linkage: "static" lib library: "webpmux", linkage: "static"
lib library: "webp" lib library: "webp"
} }
@ -385,45 +322,6 @@ model {
} }
} }
} }
img2webp_example(NativeExecutableSpec) {
binaries {
all {
lib library: "example_util", linkage: "static"
lib library: "imagedec", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpmux", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp"
}
}
sources {
c {
source {
srcDir "./examples"
include "img2webp.c"
}
}
}
}
webpinfo_example(NativeExecutableSpec) {
binaries {
all {
lib library: "example_util", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webp"
}
}
sources {
c {
source {
srcDir "./examples"
include "webpinfo.c"
}
}
}
}
} }
tasks { tasks {
// Task to test all possible configurations. // Task to test all possible configurations.

View File

@ -1,6 +0,0 @@
@PACKAGE_INIT@
set(WebP_INCLUDE_DIRS "webp")
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")

View File

@ -65,49 +65,14 @@ endif()
# Find the standard image libraries. # Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES) set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS) set(WEBP_DEP_IMG_INCLUDE_DIRS)
foreach(I_LIB PNG JPEG TIFF) foreach(I_LIB PNG JPEG TIFF GIF)
find_package(${I_LIB}) find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND}) set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND) if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES}) list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIRS})
${${I_LIB}_INCLUDE_DIR} ${${I_LIB}_INCLUDE_DIRS})
endif() endif()
endforeach() endforeach()
if(WEBP_DEP_IMG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
# GIF detection, gifdec isn't part of the imageio lib.
include(CMakePushCheckState)
set(WEBP_DEP_GIF_LIBRARIES)
set(WEBP_DEP_GIF_INCLUDE_DIRS)
find_package(GIF)
set(WEBP_HAVE_GIF ${GIF_FOUND})
if(GIF_FOUND)
# GIF find_package only locates the header and library, it doesn't fail
# compile tests when detecting the version, but falls back to 3 (as of at
# least cmake 3.7.2). Make sure the library links to avoid incorrect
# detection when cross compiling.
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
check_c_source_compiles("
#include <gif_lib.h>
int main(void) {
(void)DGifOpenFileHandle;
return 0;
}
" GIF_COMPILES
)
cmake_pop_check_state()
if(GIF_COMPILES)
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
else()
unset(GIF_FOUND)
endif()
endif()
## Check for specific headers. ## Check for specific headers.
include(CheckIncludeFiles) include(CheckIncludeFiles)
@ -164,3 +129,13 @@ strip_bracket(PACKAGE_URL)
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME ${PACKAGE_NAME}) set(PACKAGE_TARNAME ${PACKAGE_NAME})
set(VERSION ${PACKAGE_VERSION}) set(VERSION ${PACKAGE_VERSION})
## Generate the config.h header.
configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/webp/config.h)
add_definitions(-DHAVE_CONFIG_H)
# The webp folder is included as we reference config.h as
# ../webp/config.h or webp/config.h
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/include/webp
)

View File

@ -13,9 +13,6 @@
/* Set to 1 if __builtin_bswap64 is available */ /* Set to 1 if __builtin_bswap64 is available */
#cmakedefine HAVE_BUILTIN_BSWAP64 1 #cmakedefine HAVE_BUILTIN_BSWAP64 1
/* Define to 1 if you have the <cpu-features.h> header file. */
#cmakedefine HAVE_CPU_FEATURES_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1 #cmakedefine HAVE_DLFCN_H 1
@ -103,6 +100,12 @@
/* Version number of package */ /* Version number of package */
#cmakedefine VERSION "@VERSION@" #cmakedefine VERSION "@VERSION@"
/* Enable experimental code */
#cmakedefine WEBP_EXPERIMENTAL_FEATURES 1
/* Define to 1 to force aligned memory operations */
#cmakedefine WEBP_FORCE_ALIGNED 1
/* Set to 1 if AVX2 is supported */ /* Set to 1 if AVX2 is supported */
#cmakedefine WEBP_HAVE_AVX2 1 #cmakedefine WEBP_HAVE_AVX2 1
@ -115,19 +118,9 @@
/* Set to 1 if JPEG library is installed */ /* Set to 1 if JPEG library is installed */
#cmakedefine WEBP_HAVE_JPEG 1 #cmakedefine WEBP_HAVE_JPEG 1
/* Set to 1 if NEON is supported */
#cmakedefine WEBP_HAVE_NEON
/* Set to 1 if runtime detection of NEON is enabled */
/* TODO: handle properly in CMake */
#cmakedefine WEBP_HAVE_NEON_RTCD
/* Set to 1 if PNG library is installed */ /* Set to 1 if PNG library is installed */
#cmakedefine WEBP_HAVE_PNG 1 #cmakedefine WEBP_HAVE_PNG 1
/* Set to 1 if SDL library is installed */
#cmakedefine WEBP_HAVE_SDL 1
/* Set to 1 if SSE2 is supported */ /* Set to 1 if SSE2 is supported */
#cmakedefine WEBP_HAVE_SSE2 1 #cmakedefine WEBP_HAVE_SSE2 1
@ -137,9 +130,6 @@
/* Set to 1 if TIFF library is installed */ /* Set to 1 if TIFF library is installed */
#cmakedefine WEBP_HAVE_TIFF 1 #cmakedefine WEBP_HAVE_TIFF 1
/* Enable near lossless encoding */
#cmakedefine WEBP_NEAR_LOSSLESS 1
/* Undefine this to disable thread support. */ /* Undefine this to disable thread support. */
#cmakedefine WEBP_USE_THREAD 1 #cmakedefine WEBP_USE_THREAD 1

View File

@ -1,15 +1,7 @@
## Check for SIMD extensions. ## Check for SIMD extensions.
include(CMakePushCheckState)
function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD) function(webp_check_compiler_flag WEBP_SIMD_FLAG)
if(NOT ENABLE_SIMD)
message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.")
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
return()
endif()
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE) unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
check_c_source_compiles(" check_c_source_compiles("
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\" #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
int main(void) { int main(void) {
@ -20,7 +12,6 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
} }
" WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} " WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}
) )
cmake_pop_check_state()
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE) set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
else() else()
@ -64,13 +55,12 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
# First try with no extra flag added as the compiler might have default flags # First try with no extra flag added as the compiler might have default flags
# (especially on Android). # (especially on Android).
unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE) unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS) set(CMAKE_REQUIRED_FLAGS)
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) webp_check_compiler_flag(${WEBP_SIMD_FLAG})
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG}) if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG}) set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) webp_check_compiler_flag(${WEBP_SIMD_FLAG})
else() else()
set(SIMD_COMPILE_FLAG " ") set(SIMD_COMPILE_FLAG " ")
endif() endif()
@ -97,29 +87,10 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
if(SIMD_COMPILE_FLAG) if(SIMD_COMPILE_FLAG)
unset(HAS_COMPILE_FLAG CACHE) unset(HAS_COMPILE_FLAG CACHE)
check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG) check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG)
if(HAS_COMPILE_FLAG)
# Do one more check for Clang to circumvent CMake issue 13194.
if(COMMAND check_compiler_flag_common_patterns)
# Only in CMake 3.0 and above.
check_compiler_flag_common_patterns(COMMON_PATTERNS)
else()
set(COMMON_PATTERNS)
endif()
set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG})
check_c_source_compiles("int main(void) {return 0;}"
FLAG_${SIMD_COMPILE_FLAG}
FAIL_REGEX "warning: argument unused during compilation:"
${COMMON_PATTERNS}
)
if(NOT FLAG_${SIMD_COMPILE_FLAG})
unset(HAS_COMPILE_FLAG CACHE)
endif()
endif()
if(HAS_COMPILE_FLAG) if(HAS_COMPILE_FLAG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
endif() endif()
endif() endif()
endif() endif()
endif() endif()
cmake_pop_check_state()
endforeach() endforeach()

View File

@ -1,4 +1,4 @@
AC_INIT([libwebp], [1.0.0], AC_INIT([libwebp], [0.5.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
@ -67,7 +67,6 @@ AC_DEFUN([TEST_AND_ADD_CFLAGS],
CFLAGS="$SAVED_CFLAGS"]) CFLAGS="$SAVED_CFLAGS"])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
@ -76,10 +75,8 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused-but-set-variable])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused]) TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunused])
@ -244,13 +241,9 @@ AS_IF([test "x$enable_neon" != "xno"], [
NEON_FLAGS=""], NEON_FLAGS=""],
[AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1], [AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
[Set to 1 if runtime detection of NEON is enabled])])]) [Set to 1 if runtime detection of NEON is enabled])])])
;;
case "$host_os" in esac
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;; AC_SUBST([NEON_FLAGS])])
esac
;;
esac
AC_SUBST([NEON_FLAGS])])
dnl === CLEAR_LIBVARS([var_pfx]) dnl === CLEAR_LIBVARS([var_pfx])
dnl === Clears <var_pfx>_{INCLUDES,LIBS}. dnl === Clears <var_pfx>_{INCLUDES,LIBS}.
@ -347,8 +340,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
# override with --with-gl* # override with --with-gl*
glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL" glut_cflags="$glut_cflags|-framework GLUT -framework OpenGL"
glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL" glut_ldflags="$glut_ldflags|-framework GLUT -framework OpenGL"
# quiet deprecation warnings for glut
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wno-deprecated-declarations])
;; ;;
esac esac
@ -437,67 +428,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
]) ])
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"]) AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
dnl === check for SDL support ===
AC_ARG_ENABLE([sdl],
AS_HELP_STRING([--disable-sdl],
[Disable detection of SDL support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sdl" != "xno"], [
CLEAR_LIBVARS([SDL])
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
if test -n "$LIBSDL_CONFIG"; then
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
fi
WITHLIB_OPTION([sdl], [SDL])
sdl_header="no"
LIBCHECK_PROLOGUE([SDL])
AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
[AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
[AC_MSG_WARN(SDL library not available - no sdl.h)])])
if test x"$sdl_header" != "xno"; then
AC_LANG_PUSH(C)
SDL_SAVED_LIBS="$LIBS"
for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
LIBS="$SDL_SAVED_LIBS $lib"
# Perform a full link to ensure SDL_main is resolved if needed.
AC_LINK_IFELSE(
[AC_LANG_SOURCE([
#include <$sdl_header>
int main(int argc, char** argv) {
SDL_Init(0);
return 0;
}])],
[SDL_LIBS="$LDFLAGS $LIBS"
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_SDL"
AC_DEFINE(WEBP_HAVE_SDL, [1],
[Set to 1 if SDL library is installed])
sdl_support=yes]
)
if test x"$sdl_support" = "xyes"; then
break
fi
done
# LIBS is restored by LIBCHECK_EPILOGUE
AC_LANG_POP
if test x"$sdl_header" = "xSDL.h"; then
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_JUST_SDL_H"
fi
fi
LIBCHECK_EPILOGUE([SDL])
if test x"$sdl_support" = "xyes"; then
build_vwebp_sdl=yes
else
AC_MSG_WARN(Optional SDL library not found)
fi
])
AM_CONDITIONAL([BUILD_VWEBP_SDL], [test "$build_vwebp_sdl" = "yes"])
dnl === check for PNG support === dnl === check for PNG support ===
AC_ARG_ENABLE([png], AS_HELP_STRING([--disable-png], AC_ARG_ENABLE([png], AS_HELP_STRING([--disable-png],
@ -615,7 +545,7 @@ AS_IF([test "x$enable_gif" != "xno"], [
if test "$gif_support" = "yes" -a \ if test "$gif_support" = "yes" -a \
"$enable_libwebpdemux" = "yes"; then "$enable_libwebpdemux" = "yes"; then
build_anim_diff=yes build_animdiff=yes
fi fi
if test "$gif_support" = "yes" -a \ if test "$gif_support" = "yes" -a \
@ -623,19 +553,9 @@ AS_IF([test "x$enable_gif" != "xno"], [
build_gif2webp=yes build_gif2webp=yes
fi fi
]) ])
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "yes"]) AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_animdiff}" = "yes"])
AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"]) AM_CONDITIONAL([BUILD_GIF2WEBP], [test "${build_gif2webp}" = "yes"])
if test "$enable_libwebpdemux" = "yes" -a "$enable_libwebpmux" = "yes"; then
build_img2webp=yes
fi
AM_CONDITIONAL([BUILD_IMG2WEBP], [test "${build_img2webp}" = "yes"])
if test "$enable_libwebpmux" = "yes"; then
build_webpinfo=yes
fi
AM_CONDITIONAL([BUILD_WEBPINFO], [test "${build_webpinfo}" = "yes"])
dnl === check for WIC support === dnl === check for WIC support ===
AC_ARG_ENABLE([wic], AC_ARG_ENABLE([wic],
@ -688,7 +608,20 @@ if test "$enable_wic" = "yes"; then
fi fi
esac esac
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP=1 dnl === If --enable-aligned is defined, define WEBP_FORCE_ALIGNED
AC_MSG_CHECKING(if --enable-aligned option is specified)
AC_ARG_ENABLE([aligned],
AS_HELP_STRING([--enable-aligned],
[Force aligned memory operations in non-dsp code
(may be slower)]))
if test "$enable_aligned" = "yes"; then
AC_DEFINE(WEBP_FORCE_ALIGNED, [1],
[Define to 1 to force aligned memory operations])
fi
AC_MSG_RESULT(${enable_aligned-no})
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
USE_SWAP_16BIT_CSP="" USE_SWAP_16BIT_CSP=""
AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified) AC_MSG_CHECKING(if --enable-swap-16bit-csp option is specified)
@ -696,25 +629,23 @@ AC_ARG_ENABLE([swap-16bit-csp],
AS_HELP_STRING([--enable-swap-16bit-csp], AS_HELP_STRING([--enable-swap-16bit-csp],
[Enable byte swap for 16 bit colorspaces])) [Enable byte swap for 16 bit colorspaces]))
if test "$enable_swap_16bit_csp" = "yes"; then if test "$enable_swap_16bit_csp" = "yes"; then
USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP=1" USE_SWAP_16BIT_CSP="-DWEBP_SWAP_16BIT_CSP"
fi fi
AC_MSG_RESULT(${enable_swap_16bit_csp-no}) AC_MSG_RESULT(${enable_swap_16bit_csp-no})
AC_SUBST(USE_SWAP_16BIT_CSP) AC_SUBST(USE_SWAP_16BIT_CSP)
dnl === If --disable-near-lossless is defined, add -DWEBP_NEAR_LOSSLESS=0 dnl === If --enable-experimental is defined, add -DWEBP_EXPERIMENTAL_FEATURES
AC_DEFINE(WEBP_NEAR_LOSSLESS, [1], [Enable near lossless encoding]) USE_EXPERIMENTAL_CODE=""
AC_MSG_CHECKING(if --disable-near-lossless option is specified) AC_MSG_CHECKING(if --enable-experimental option is specified)
AC_ARG_ENABLE([near_lossless], AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental],
AS_HELP_STRING([--disable-near-lossless], [Activate experimental features]))
[Disable near lossless encoding]), if test "$enable_experimental" = "yes"; then
[], [enable_near_lossless=yes]) AC_DEFINE(WEBP_EXPERIMENTAL_FEATURES, [1], [Enable experimental code])
if test "$enable_near_lossless" = "no"; then USE_EXPERIMENTAL_CODE="-DWEBP_EXPERIMENTAL_FEATURES"
AC_DEFINE(WEBP_NEAR_LOSSLESS, [0], [Enable near lossless encoding])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi fi
AC_MSG_RESULT(${enable_experimental-no})
AC_SUBST(USE_EXPERIMENTAL_CODE)
dnl === Check whether libwebpmux should be built dnl === Check whether libwebpmux should be built
AC_MSG_CHECKING(whether libwebpmux is to be built) AC_MSG_CHECKING(whether libwebpmux is to be built)
@ -727,9 +658,8 @@ AM_CONDITIONAL([WANT_MUX], [test "$enable_libwebpmux" = "yes"])
dnl === Check whether libwebpdemux should be built dnl === Check whether libwebpdemux should be built
AC_MSG_CHECKING(whether libwebpdemux is to be built) AC_MSG_CHECKING(whether libwebpdemux is to be built)
AC_ARG_ENABLE([libwebpdemux], AC_ARG_ENABLE([libwebpdemux],
AS_HELP_STRING([--disable-libwebpdemux], AS_HELP_STRING([--enable-libwebpdemux],
[Disable libwebpdemux @<:@default=no@:>@]), [Build libwebpdemux @<:@default=no@:>@]))
[], [enable_libwebpdemux=yes])
AC_MSG_RESULT(${enable_libwebpdemux-no}) AC_MSG_RESULT(${enable_libwebpdemux-no})
AM_CONDITIONAL([WANT_DEMUX], [test "$enable_libwebpdemux" = "yes"]) AM_CONDITIONAL([WANT_DEMUX], [test "$enable_libwebpdemux" = "yes"])
@ -754,12 +684,13 @@ dnl =========================
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/webp/config.h]) AC_CONFIG_HEADERS([src/webp/config.h])
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \ AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
examples/Makefile extras/Makefile imageio/Makefile \ examples/Makefile src/dec/Makefile \
src/dec/Makefile src/enc/Makefile src/dsp/Makefile \ src/enc/Makefile src/dsp/Makefile \
src/demux/Makefile src/mux/Makefile \ src/demux/Makefile src/mux/Makefile \
src/utils/Makefile \ src/utils/Makefile src/extras/Makefile \
src/libwebp.pc src/libwebpdecoder.pc \ src/libwebp.pc src/libwebpdecoder.pc \
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc]) src/demux/libwebpdemux.pc src/mux/libwebpmux.pc \
src/extras/libwebpextras.pc])
AC_OUTPUT AC_OUTPUT
@ -778,25 +709,21 @@ libwebpmux: ${enable_libwebpmux-no}
libwebpextras: ${enable_libwebpextras-no} libwebpextras: ${enable_libwebpextras-no}
Tools: Tools:
cwebp : ${enable_libwebpdemux-no} cwebp : yes
Input format support Input format support
==================== ====================
JPEG : ${jpeg_support-no} JPEG : ${jpeg_support-no}
PNG : ${png_support-no} PNG : ${png_support-no}
TIFF : ${tiff_support-no} TIFF : ${tiff_support-no}
WIC : ${wic_support-no} WIC : ${wic_support-no}
dwebp : ${enable_libwebpdemux-no} dwebp : yes
Output format support Output format support
===================== =====================
PNG : ${png_support-no} PNG : ${png_support-no}
WIC : ${wic_support-no} WIC : ${wic_support-no}
GIF support : ${gif_support-no} GIF support : ${gif_support-no}
anim_diff : ${build_anim_diff-no} anim_diff : ${build_animdiff-no}
gif2webp : ${build_gif2webp-no} gif2webp : ${build_gif2webp-no}
img2webp : ${build_img2webp-no}
webpmux : ${enable_libwebpmux-no} webpmux : ${enable_libwebpmux-no}
vwebp : ${build_vwebp-no} vwebp : ${build_vwebp-no}
webpinfo : ${build_webpinfo-no}
SDL support : ${sdl_support-no}
vwebp_sdl : ${build_vwebp_sdl-no}
]) ])

View File

@ -446,9 +446,8 @@ Frame Height Minus One: 24 bits (_uint24_)
Frame Duration: 24 bits (_uint24_) Frame Duration: 24 bits (_uint24_)
: The time to wait before displaying the next frame, in 1 millisecond units. : The time to wait before displaying the next frame, in 1 millisecond units.
Note the interpretation of frame duration of 0 (and often <= 10) is In particular, frame duration of 0 is useful when one wants to update
implementation defined. Many tools and browsers assign a minimum duration multiple areas of the canvas at once during the animation.
similar to GIF.
Reserved: 6 bits Reserved: 6 bits

View File

@ -15,6 +15,27 @@ LOCAL_MODULE := example_util
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
################################################################################
# libexample_dec
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
image_dec.c \
jpegdec.c \
metadata.c \
pngdec.c \
tiffdec.c \
webpdec.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_MODULE := example_dec
include $(BUILD_STATIC_LIBRARY)
################################################################################ ################################################################################
# cwebp # cwebp
@ -27,7 +48,7 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpdemux webp LOCAL_STATIC_LIBRARIES := example_util example_dec webp
LOCAL_MODULE := cwebp LOCAL_MODULE := cwebp
@ -43,7 +64,8 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webpdemux webp LOCAL_STATIC_LIBRARIES := example_util webp
LOCAL_MODULE := dwebp LOCAL_MODULE := dwebp
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
@ -58,41 +80,8 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := $(WEBP_CFLAGS) LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp LOCAL_STATIC_LIBRARIES := example_util webpmux webp
LOCAL_MODULE := webpmux_example LOCAL_MODULE := webpmux_example
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)
################################################################################
# img2webp
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
img2webp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webpdemux \
webp
LOCAL_MODULE := img2webp_example
include $(BUILD_EXECUTABLE)
################################################################################
# webpinfo
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
webpinfo.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := example_util imageio_util webp
LOCAL_MODULE := webpinfo_example
include $(BUILD_EXECUTABLE)

View File

@ -1,119 +1,70 @@
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
bin_PROGRAMS = bin_PROGRAMS = dwebp cwebp
if WANT_DEMUX if BUILD_VWEBP
bin_PROGRAMS += dwebp cwebp bin_PROGRAMS += vwebp
endif
if BUILD_ANIMDIFF
noinst_PROGRAMS = anim_diff anim_dump
endif
if BUILD_GIF2WEBP
bin_PROGRAMS += gif2webp
endif
if BUILD_IMG2WEBP
bin_PROGRAMS += img2webp
endif endif
if WANT_MUX if WANT_MUX
bin_PROGRAMS += webpmux bin_PROGRAMS += webpmux
endif endif
if BUILD_VWEBP
bin_PROGRAMS += vwebp if BUILD_GIF2WEBP
endif bin_PROGRAMS += gif2webp
if BUILD_WEBPINFO
bin_PROGRAMS += webpinfo
endif endif
noinst_LTLIBRARIES = libexample_util.la noinst_LTLIBRARIES = libexampleutil.la libexampledec.la
libexample_util_la_SOURCES = example_util.c example_util.h libexampleutil_la_SOURCES = example_util.c example_util.h stopwatch.h
libexample_util_la_LIBADD = ../src/libwebp.la
libexampledec_la_SOURCES = image_dec.c image_dec.h
libexampledec_la_SOURCES += jpegdec.c jpegdec.h
libexampledec_la_SOURCES += metadata.c metadata.h
libexampledec_la_SOURCES += pngdec.c pngdec.h
libexampledec_la_SOURCES += tiffdec.c tiffdec.h
libexampledec_la_SOURCES += webpdec.c webpdec.h
libexampledec_la_SOURCES += wicdec.c wicdec.h
libexampledec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
libexampledec_la_CPPFLAGS += $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
if BUILD_ANIMDIFF
noinst_PROGRAMS = anim_diff
endif
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
anim_diff_LDADD = anim_diff_LDADD = ../src/demux/libwebpdemux.la
anim_diff_LDADD += ../src/demux/libwebpdemux.la anim_diff_LDADD += libexampleutil.la
anim_diff_LDADD += libexample_util.la
anim_diff_LDADD += ../imageio/libimageio_util.la
anim_diff_LDADD += $(GIF_LIBS) -lm anim_diff_LDADD += $(GIF_LIBS) -lm
anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h dwebp_SOURCES = dwebp.c stopwatch.h
anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
anim_dump_CPPFLAGS += $(GIF_INCLUDES) dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
anim_dump_LDADD = dwebp_LDADD = libexampleutil.la $(PNG_LIBS) $(JPEG_LIBS)
anim_dump_LDADD += ../src/demux/libwebpdemux.la
anim_dump_LDADD += libexample_util.la
anim_dump_LDADD += ../imageio/libimageio_util.la
anim_dump_LDADD += ../imageio/libimageenc.la
anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm
cwebp_SOURCES = cwebp.c stopwatch.h cwebp_SOURCES = cwebp.c stopwatch.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS) cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
cwebp_LDADD = cwebp_LDADD = libexampleutil.la libexampledec.la ../src/libwebp.la
cwebp_LDADD += libexample_util.la
cwebp_LDADD += ../imageio/libimageio_util.la
cwebp_LDADD += ../imageio/libimagedec.la
cwebp_LDADD += ../src/libwebp.la
cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
dwebp_SOURCES = dwebp.c stopwatch.h
dwebp_CPPFLAGS = $(AM_CPPFLAGS)
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
dwebp_LDADD =
dwebp_LDADD += libexample_util.la
dwebp_LDADD += ../imageio/libimagedec.la
dwebp_LDADD += ../imageio/libimageenc.la
dwebp_LDADD += ../imageio/libimageio_util.la
dwebp_LDADD += ../src/libwebp.la
dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS)
gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
gif2webp_LDADD = gif2webp_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../src/libwebp.la
gif2webp_LDADD += libexample_util.la
gif2webp_LDADD += ../imageio/libimageio_util.la
gif2webp_LDADD += ../src/mux/libwebpmux.la
gif2webp_LDADD += ../src/libwebp.la
gif2webp_LDADD += $(GIF_LIBS) gif2webp_LDADD += $(GIF_LIBS)
vwebp_SOURCES = vwebp.c
vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(GL_INCLUDES)
vwebp_LDADD =
vwebp_LDADD += libexample_util.la
vwebp_LDADD += ../imageio/libimageio_util.la
vwebp_LDADD += ../src/demux/libwebpdemux.la
vwebp_LDADD += $(GL_LIBS)
webpmux_SOURCES = webpmux.c webpmux_SOURCES = webpmux.c
webpmux_CPPFLAGS = $(AM_CPPFLAGS) webpmux_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
webpmux_LDADD = webpmux_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../src/libwebp.la
webpmux_LDADD += libexample_util.la
webpmux_LDADD += ../imageio/libimageio_util.la
webpmux_LDADD += ../src/mux/libwebpmux.la
webpmux_LDADD += ../src/libwebp.la
img2webp_SOURCES = img2webp.c vwebp_SOURCES = vwebp.c
img2webp_CPPFLAGS = $(AM_CPPFLAGS) vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GL_INCLUDES)
img2webp_LDADD = vwebp_LDADD = libexampleutil.la ../src/demux/libwebpdemux.la $(GL_LIBS)
img2webp_LDADD += libexample_util.la
img2webp_LDADD += ../imageio/libimageio_util.la
img2webp_LDADD += ../imageio/libimagedec.la
img2webp_LDADD += ../src/mux/libwebpmux.la
img2webp_LDADD += ../src/libwebp.la
img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
webpinfo_SOURCES = webpinfo.c
webpinfo_CPPFLAGS = $(AM_CPPFLAGS)
webpinfo_LDADD =
webpinfo_LDADD += libexample_util.la
webpinfo_LDADD += ../imageio/libimageio_util.la
webpinfo_LDADD += ../src/libwebp.la
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
anim_diff_LDADD += ../src/libwebpdecoder.la anim_diff_LDADD += ../src/libwebpdecoder.la
anim_dump_LDADD += ../src/libwebpdecoder.la dwebp_LDADD += ../src/libwebpdecoder.la
vwebp_LDADD += ../src/libwebpdecoder.la vwebp_LDADD += ../src/libwebpdecoder.la
else else
anim_diff_LDADD += ../src/libwebp.la anim_diff_LDADD += ../src/libwebp.la
anim_dump_LDADD += ../src/libwebp.la dwebp_LDADD += ../src/libwebp.la
vwebp_LDADD += ../src/libwebp.la vwebp_LDADD += ../src/libwebp.la
endif endif

View File

@ -143,18 +143,8 @@ static int CompareAnimatedImagePair(const AnimatedImage* const img1,
if (!ok) return 0; // These are fatal failures, can't proceed. if (!ok) return 0; // These are fatal failures, can't proceed.
if (is_multi_frame_image) { // Checks relevant for multi-frame images only. if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
int max_loop_count_workaround = 0; ok = CompareValues(img1->loop_count, img2->loop_count,
// Transcodes to webp increase the gif loop count by 1 for compatibility. "Loop count mismatch") && ok;
// When the gif has the maximum value the webp value will be off by one.
if ((img1->format == ANIM_GIF && img1->loop_count == 65536 &&
img2->format == ANIM_WEBP && img2->loop_count == 65535) ||
(img1->format == ANIM_WEBP && img1->loop_count == 65535 &&
img2->format == ANIM_GIF && img2->loop_count == 65536)) {
max_loop_count_workaround = 1;
}
ok = (max_loop_count_workaround ||
CompareValues(img1->loop_count, img2->loop_count,
"Loop count mismatch")) && ok;
ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor, ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor,
premultiply) && ok; premultiply) && ok;
} }
@ -197,11 +187,11 @@ static void Help(void) {
printf(" -min_psnr <float> ... minimum per-frame PSNR\n"); printf(" -min_psnr <float> ... minimum per-frame PSNR\n");
printf(" -raw_comparison ..... if this flag is not used, RGB is\n"); printf(" -raw_comparison ..... if this flag is not used, RGB is\n");
printf(" premultiplied before comparison\n"); printf(" premultiplied before comparison\n");
printf(" -max_diff <int> ..... maximum allowed difference per channel\n" #ifdef WEBP_EXPERIMENTAL_FEATURES
" between corresponding pixels in subsequent\n" printf(" -max_diff <int> ..... maximum allowed difference per channel "
" between corresponding pixels in subsequent"
" frames\n"); " frames\n");
printf(" -h .................. this help\n"); #endif
printf(" -version ............ print version number and exit\n");
} }
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
@ -217,6 +207,11 @@ 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];
if (argc < 3) {
Help();
return -1;
}
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0; int parse_error = 0;
if (!strcmp(argv[c], "-dump_frames")) { if (!strcmp(argv[c], "-dump_frames")) {
@ -241,6 +236,7 @@ int main(int argc, const char* argv[]) {
} }
} else if (!strcmp(argv[c], "-raw_comparison")) { } else if (!strcmp(argv[c], "-raw_comparison")) {
premultiply = 0; premultiply = 0;
#ifdef WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-max_diff")) { } else if (!strcmp(argv[c], "-max_diff")) {
if (c < argc - 1) { if (c < argc - 1) {
const char* const v = argv[++c]; const char* const v = argv[++c];
@ -254,18 +250,7 @@ int main(int argc, const char* argv[]) {
} else { } else {
parse_error = 1; parse_error = 1;
} }
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { #endif
Help();
return 0;
} else if (!strcmp(argv[c], "-version")) {
int dec_version, demux_version;
GetAnimatedImageVersions(&dec_version, &demux_version);
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
(dec_version >> 0) & 0xff,
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
(demux_version >> 0) & 0xff);
return 0;
} else { } else {
if (!got_input1) { if (!got_input1) {
files[0] = argv[c]; files[0] = argv[c];
@ -282,12 +267,6 @@ int main(int argc, const char* argv[]) {
return -1; return -1;
} }
} }
if (argc < 3) {
Help();
return -1;
}
if (!got_input2) { if (!got_input2) {
Help(); Help();
return -1; return -1;

View File

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

View File

@ -16,13 +16,13 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#if defined(WEBP_HAVE_GIF) #ifdef WEBP_HAVE_GIF
#include <gif_lib.h> #include <gif_lib.h>
#endif #endif
#include "webp/format_constants.h" #include "webp/format_constants.h"
#include "webp/decode.h" #include "webp/decode.h"
#include "webp/demux.h" #include "webp/demux.h"
#include "../imageio/imageio_util.h" #include "./example_util.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -33,13 +33,11 @@ static const int kNumChannels = 4;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Common utilities. // Common utilities.
#if defined(WEBP_HAVE_GIF)
// Returns true if the frame covers the full canvas. // Returns true if the frame covers the full canvas.
static int IsFullFrame(int width, int height, static int IsFullFrame(int width, int height,
int canvas_width, int canvas_height) { int canvas_width, int canvas_height) {
return (width == canvas_width && height == canvas_height); return (width == canvas_width && height == canvas_height);
} }
#endif // WEBP_HAVE_GIF
static int CheckSizeForOverflow(uint64_t size) { static int CheckSizeForOverflow(uint64_t size) {
return (size == (size_t)size); return (size == (size_t)size);
@ -87,7 +85,6 @@ void ClearAnimatedImage(AnimatedImage* const image) {
} }
} }
#if defined(WEBP_HAVE_GIF)
// Clear the canvas to transparent. // Clear the canvas to transparent.
static void ZeroFillCanvas(uint8_t* rgba, static void ZeroFillCanvas(uint8_t* rgba,
uint32_t canvas_width, uint32_t canvas_height) { uint32_t canvas_width, uint32_t canvas_height) {
@ -129,7 +126,6 @@ static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride,
dst += stride; dst += stride;
} }
} }
#endif // WEBP_HAVE_GIF
// Canonicalize all transparent pixels to transparent black to aid comparison. // Canonicalize all transparent pixels to transparent black to aid comparison.
static void CleanupTransparentPixels(uint32_t* rgba, static void CleanupTransparentPixels(uint32_t* rgba,
@ -154,9 +150,6 @@ static int DumpFrame(const char filename[], const char dump_folder[],
const char* base_name = NULL; const char* base_name = NULL;
char* file_name = NULL; char* file_name = NULL;
FILE* f = NULL; FILE* f = NULL;
const char* row;
if (dump_folder == NULL) dump_folder = ".";
base_name = strrchr(filename, '/'); base_name = strrchr(filename, '/');
base_name = (base_name == NULL) ? filename : base_name + 1; base_name = (base_name == NULL) ? filename : base_name + 1;
@ -183,13 +176,12 @@ static int DumpFrame(const char filename[], const char dump_folder[],
fprintf(stderr, "Write error for file %s\n", file_name); fprintf(stderr, "Write error for file %s\n", file_name);
goto End; goto End;
} }
row = (const char*)rgba;
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((const char*)(rgba) + y * canvas_width * kNumChannels,
canvas_width * kNumChannels, 1, f) != 1) {
fprintf(stderr, "Error writing to file: %s\n", file_name); fprintf(stderr, "Error writing to file: %s\n", file_name);
goto End; goto End;
} }
row += canvas_width * kNumChannels;
} }
ok = 1; ok = 1;
End: End:
@ -206,7 +198,7 @@ static int IsWebP(const WebPData* const webp_data) {
return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0); return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0);
} }
// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct. // Read animated WebP bitstream 'file_str' into 'AnimatedImage' struct.
static int ReadAnimatedWebP(const char filename[], static int ReadAnimatedWebP(const char filename[],
const WebPData* const webp_data, const WebPData* const webp_data,
AnimatedImage* const image, int dump_frames, AnimatedImage* const image, int dump_frames,
@ -275,7 +267,6 @@ static int ReadAnimatedWebP(const char filename[],
prev_frame_timestamp = timestamp; prev_frame_timestamp = timestamp;
} }
ok = dump_ok; ok = dump_ok;
if (ok) image->format = ANIM_WEBP;
End: End:
WebPAnimDecoderDelete(dec); WebPAnimDecoderDelete(dec);
@ -285,7 +276,7 @@ static int ReadAnimatedWebP(const char filename[],
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// GIF Decoding. // GIF Decoding.
#if defined(WEBP_HAVE_GIF) #ifdef WEBP_HAVE_GIF
// Returns true if this is a valid GIF bitstream. // Returns true if this is a valid GIF bitstream.
static int IsGIF(const WebPData* const data) { static int IsGIF(const WebPData* const data) {
@ -430,11 +421,6 @@ static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
} }
// Find appropriate app extension and get loop count from the next extension. // Find appropriate app extension and get loop count from the next extension.
// We use Chrome's interpretation of the 'loop_count' semantics:
// if not present -> loop once
// if present and loop_count == 0, return 0 ('infinite').
// if present and loop_count != 0, it's the number of *extra* loops
// so we need to return loop_count + 1 as total loop number.
static uint32_t GetLoopCountGIF(const GifFileType* const gif) { static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
int i; int i;
for (i = 0; i < gif->ImageCount; ++i) { for (i = 0; i < gif->ImageCount; ++i) {
@ -452,13 +438,12 @@ static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
if (signature_is_ok && if (signature_is_ok &&
eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 && eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 &&
eb2->Bytes[0] == 1) { eb2->Bytes[0] == 1) {
const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) + return ((uint32_t)(eb2->Bytes[2]) << 8) +
((uint32_t)(eb2->Bytes[1]) << 0); ((uint32_t)(eb2->Bytes[1]) << 0);
return (extra_loop > 0) ? extra_loop + 1 : 0;
} }
} }
} }
return 1; // Default. return 0; // Default.
} }
// Get duration of 'n'th frame in milliseconds. // Get duration of 'n'th frame in milliseconds.
@ -594,9 +579,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
curr_frame = &image->frames[i]; curr_frame = &image->frames[i];
curr_rgba = curr_frame->rgba; curr_rgba = curr_frame->rgba;
curr_frame->duration = GetFrameDurationGIF(gif, i); curr_frame->duration = GetFrameDurationGIF(gif, i);
// Force frames with a small or no duration to 100ms to be consistent
// with web browsers and other transcoding tools (like gif2webp itself).
if (curr_frame->duration <= 10) curr_frame->duration = 100;
if (i == 0) { // Initialize as transparent. if (i == 0) { // Initialize as transparent.
curr_frame->is_key_frame = 1; curr_frame->is_key_frame = 1;
@ -688,7 +670,6 @@ static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
} }
} }
} }
image->format = ANIM_GIF;
DGifCloseFile(gif, NULL); DGifCloseFile(gif, NULL);
return 1; return 1;
} }
@ -723,7 +704,7 @@ int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
WebPDataInit(&webp_data); WebPDataInit(&webp_data);
memset(image, 0, sizeof(*image)); memset(image, 0, sizeof(*image));
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) { if (!ExUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
fprintf(stderr, "Error reading file: %s\n", filename); fprintf(stderr, "Error reading file: %s\n", filename);
return 0; return 0;
} }
@ -762,7 +743,7 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
for (y = 0; y < height; ++y) { for (y = 0; y < height; ++y) {
for (x = 0; x < stride; x += kNumChannels) { for (x = 0; x < stride; x += kNumChannels) {
int k; int k;
const size_t offset = (size_t)y * stride + x; const size_t offset = y * stride + x;
const int alpha1 = rgba1[offset + kAlphaChannel]; const int alpha1 = rgba1[offset + kAlphaChannel];
const int alpha2 = rgba2[offset + kAlphaChannel]; const int alpha2 = rgba2[offset + kAlphaChannel];
Accumulate(alpha1, alpha2, &f_max_diff, &sse); Accumulate(alpha1, alpha2, &f_max_diff, &sse);
@ -788,9 +769,3 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
*psnr = 4.3429448 * log(255. * 255. / sse); *psnr = 4.3429448 * log(255. * 255. / sse);
} }
} }
void GetAnimatedImageVersions(int* const decoder_version,
int* const demux_version) {
*decoder_version = WebPGetDecoderVersion();
*demux_version = WebPGetDemuxVersion();
}

View File

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

View File

@ -20,9 +20,8 @@
#include "webp/config.h" #include "webp/config.h"
#endif #endif
#include "../examples/example_util.h" #include "./example_util.h"
#include "../imageio/image_dec.h" #include "./image_dec.h"
#include "../imageio/imageio_util.h"
#include "./stopwatch.h" #include "./stopwatch.h"
#include "webp/encode.h" #include "webp/encode.h"
@ -60,12 +59,12 @@ static int ReadYUV(const uint8_t* const data, size_t data_size,
pic->use_argb = 0; pic->use_argb = 0;
if (!WebPPictureAlloc(pic)) return 0; if (!WebPPictureAlloc(pic)) return 0;
ImgIoUtilCopyPlane(data, pic->width, pic->y, pic->y_stride, ExUtilCopyPlane(data, pic->width, pic->y, pic->y_stride,
pic->width, pic->height); pic->width, pic->height);
ImgIoUtilCopyPlane(data + y_plane_size, uv_width, ExUtilCopyPlane(data + y_plane_size, uv_width,
pic->u, pic->uv_stride, uv_width, uv_height); pic->u, pic->uv_stride, uv_width, uv_height);
ImgIoUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width, ExUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width,
pic->v, pic->uv_stride, uv_width, uv_height); pic->v, pic->uv_stride, uv_width, uv_height);
return use_argb ? WebPPictureYUVAToARGB(pic) : 1; return use_argb ? WebPPictureYUVAToARGB(pic) : 1;
} }
@ -77,13 +76,13 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
const uint8_t* data = NULL; const uint8_t* data = NULL;
size_t data_size = 0; size_t data_size = 0;
if (pic->width != 0 && pic->height != 0) { if (pic->width != 0 && pic->height != 0) {
ok = ImgIoUtilReadFile(filename, &data, &data_size); ok = ExUtilReadFile(filename, &data, &data_size);
ok = ok && ReadYUV(data, data_size, pic); ok = ok && ReadYUV(data, data_size, pic);
} else { } else {
// If no size specified, try to decode it using WIC. // If no size specified, try to decode it using WIC.
ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata); ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
if (!ok) { if (!ok) {
ok = ImgIoUtilReadFile(filename, &data, &data_size); ok = ExUtilReadFile(filename, &data, &data_size);
ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata); ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata);
} }
} }
@ -102,12 +101,12 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
size_t data_size = 0; size_t data_size = 0;
int ok = 0; int ok = 0;
ok = ImgIoUtilReadFile(filename, &data, &data_size); ok = ExUtilReadFile(filename, &data, &data_size);
if (!ok) goto End; if (!ok) goto End;
if (pic->width == 0 || pic->height == 0) { if (pic->width == 0 || pic->height == 0) {
WebPImageReader reader = WebPGuessImageReader(data, data_size); WebPImageReader reader = WebPGuessImageReader(data, data_size);
ok = reader(data, data_size, pic, keep_alpha, metadata); ok = (reader != NULL) && reader(data, data_size, pic, keep_alpha, metadata);
} else { } else {
// If image size is specified, infer it as YUV format. // If image size is specified, infer it as YUV format.
ok = ReadYUV(data, data_size, pic); ok = ReadYUV(data, data_size, pic);
@ -140,11 +139,10 @@ static void PrintByteCount(const int bytes[4], int total_size,
fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size); fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size);
} }
static void PrintPercents(const int counts[4]) { static void PrintPercents(const int counts[4], int total) {
int s; int s;
const int total = counts[0] + counts[1] + counts[2] + counts[3];
for (s = 0; s < 4; ++s) { for (s = 0; s < 4; ++s) {
fprintf(stderr, "| %2d%%", (int)(100. * counts[s] / total + .5)); fprintf(stderr, "| %2d%%", 100 * counts[s] / total);
} }
fprintf(stderr, "| %7d\n", total); fprintf(stderr, "| %7d\n", total);
} }
@ -187,8 +185,7 @@ static void PrintExtraInfoLossless(const WebPPicture* const pic,
} else { } else {
fprintf(stderr, "File: %s\n", file_name); fprintf(stderr, "File: %s\n", file_name);
fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height); fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size, fprintf(stderr, "Output: %d bytes\n", stats->coded_size);
8.f * stats->coded_size / pic->width / pic->height);
PrintFullLosslessInfo(stats, "ARGB"); PrintFullLosslessInfo(stats, "ARGB");
} }
} }
@ -209,18 +206,15 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
pic->width, pic->height, pic->width, pic->height,
stats->alpha_data_size ? " (with alpha)" : ""); stats->alpha_data_size ? " (with alpha)" : "");
fprintf(stderr, "Output: " fprintf(stderr, "Output: "
"%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n" "%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n",
" (%.2f bpp)\n",
stats->coded_size, stats->coded_size,
stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3], stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3]);
8.f * stats->coded_size / pic->width / pic->height);
if (total > 0) { if (total > 0) {
int totals[4] = { 0, 0, 0, 0 }; int totals[4] = { 0, 0, 0, 0 };
fprintf(stderr, "block count: intra4: %6d (%.2f%%)\n" fprintf(stderr, "block count: intra4: %d\n"
" intra16: %6d (%.2f%%)\n" " intra16: %d (-> %.2f%%)\n",
" skipped: %6d (%.2f%%)\n", num_i4, num_i16, 100.f * num_i16 / total);
num_i4, 100.f * num_i4 / total, fprintf(stderr, " skipped block: %d (%.2f%%)\n",
num_i16, 100.f * num_i16 / total,
num_skip, 100.f * num_skip / total); num_skip, 100.f * num_skip / total);
fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n" fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
" mode-partition: %6d (%.1f%%)\n", " mode-partition: %6d (%.1f%%)\n",
@ -244,7 +238,7 @@ static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals); PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
} }
fprintf(stderr, " macroblocks: "); fprintf(stderr, " macroblocks: ");
PrintPercents(stats->segment_size); PrintPercents(stats->segment_size, total);
fprintf(stderr, " quantizer: "); fprintf(stderr, " quantizer: ");
PrintValues(stats->segment_quant); PrintValues(stats->segment_quant);
fprintf(stderr, " filter level: "); fprintf(stderr, " filter level: ");
@ -302,10 +296,6 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
const int uv_width = (picture->width + 1) / 2; const int uv_width = (picture->width + 1) / 2;
const int uv_height = (picture->height + 1) / 2; const int uv_height = (picture->height + 1) / 2;
const int stride = (picture->width + 1) & ~1; const int stride = (picture->width + 1) & ~1;
const uint8_t* src_y = picture->y;
const uint8_t* src_u = picture->u;
const uint8_t* src_v = picture->v;
const uint8_t* src_a = picture->a;
const int alpha_height = 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;
@ -313,20 +303,20 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
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) {
if (fwrite(src_y, picture->width, 1, f) != 1) return 0; if (fwrite(picture->y + y * picture->y_stride, picture->width, 1, f) != 1)
return 0;
if (picture->width & 1) fputc(0, f); // pad if (picture->width & 1) fputc(0, f); // pad
src_y += picture->y_stride;
} }
for (y = 0; y < uv_height; ++y) { for (y = 0; y < uv_height; ++y) {
if (fwrite(src_u, uv_width, 1, f) != 1) return 0; if (fwrite(picture->u + y * picture->uv_stride, uv_width, 1, f) != 1)
if (fwrite(src_v, uv_width, 1, f) != 1) return 0; return 0;
src_u += picture->uv_stride; if (fwrite(picture->v + y * picture->uv_stride, uv_width, 1, f) != 1)
src_v += picture->uv_stride; return 0;
} }
for (y = 0; y < alpha_height; ++y) { for (y = 0; y < alpha_height; ++y) {
if (fwrite(src_a, picture->width, 1, f) != 1) return 0; if (fwrite(picture->a + y * picture->a_stride, picture->width, 1, f) != 1)
return 0;
if (picture->width & 1) fputc(0, f); // pad if (picture->width & 1) fputc(0, f); // pad
src_a += picture->a_stride;
} }
fclose(f); fclose(f);
return 1; return 1;
@ -468,9 +458,8 @@ static int WriteWebPWithMetadata(FILE* const out,
} else { } else {
const int is_lossless = !memcmp(webp, "VP8L", kTagSize); const int is_lossless = !memcmp(webp, "VP8L", kTagSize);
if (is_lossless) { if (is_lossless) {
// Presence of alpha is stored in the 37th bit (29th after the // Presence of alpha is stored in the 29th bit of VP8L data.
// signature) of VP8L data. if (webp[kChunkHeaderSize + 3] & (1 << 5)) flags |= kAlphaFlag;
if (webp[kChunkHeaderSize + 4] & (1 << 4)) flags |= kAlphaFlag;
} }
ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1); ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1);
ok = ok && WriteLE32(out, flags); ok = ok && WriteLE32(out, flags);
@ -492,10 +481,10 @@ static int WriteWebPWithMetadata(FILE* const out,
*metadata_written |= METADATA_XMP; *metadata_written |= METADATA_XMP;
} }
return ok; return ok;
} else {
// No metadata, just write the original image file.
return (fwrite(webp, webp_size, 1, out) == 1);
} }
// No metadata, just write the original image file.
return (fwrite(webp, webp_size, 1, out) == 1);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -555,8 +544,6 @@ static void HelpLong(void) {
printf(" -strong ................ use strong filter instead " printf(" -strong ................ use strong filter instead "
"of simple (default)\n"); "of simple (default)\n");
printf(" -nostrong .............. use simple filter instead of strong\n"); printf(" -nostrong .............. use simple filter instead of strong\n");
printf(" -sharp_yuv ............. use sharper (and slower) RGB->YUV "
"conversion\n");
printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n"); printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
printf(" " printf(" "
"the first partition (0=no degradation ... 100=full)\n"); "the first partition (0=no degradation ... 100=full)\n");
@ -585,6 +572,9 @@ static void HelpLong(void) {
printf(" -near_lossless <int> ... use near-lossless image\n" printf(" -near_lossless <int> ... use near-lossless image\n"
" preprocessing (0..100=off), " " preprocessing (0..100=off), "
"default=100\n"); "default=100\n");
#ifdef WEBP_EXPERIMENTAL_FEATURES
printf(" -delta_palettization ... use delta palettization\n");
#endif // WEBP_EXPERIMENTAL_FEATURES
printf(" -hint <string> ......... specify image characteristics hint,\n"); printf(" -hint <string> ......... specify image characteristics hint,\n");
printf(" one of: photo, picture or graph\n"); printf(" one of: photo, picture or graph\n");
@ -753,6 +743,11 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) { } else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error); config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
config.lossless = 1; // use near-lossless only with lossless config.lossless = 1; // use near-lossless only with lossless
#ifdef WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-delta_palettization")) {
config.delta_palettization = 1;
config.lossless = 1; // use delta-palettization only with lossless
#endif // WEBP_EXPERIMENTAL_FEATURES
} else if (!strcmp(argv[c], "-hint") && c < argc - 1) { } else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
++c; ++c;
if (!strcmp(argv[c], "photo")) { if (!strcmp(argv[c], "photo")) {
@ -787,8 +782,6 @@ int main(int argc, const char *argv[]) {
config.filter_type = 0; config.filter_type = 0;
} else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) { } else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error); config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-sharp_yuv")) {
config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-pass") && c < argc - 1) { } else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
config.pass = ExUtilGetInt(argv[++c], 0, &parse_error); config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-pre") && c < argc - 1) { } else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
@ -947,8 +940,7 @@ int main(int argc, const char *argv[]) {
// Read the input. We need to decide if we prefer ARGB or YUVA // Read the input. We need to decide if we prefer ARGB or YUVA
// samples, depending on the expected compression mode (this saves // samples, depending on the expected compression mode (this saves
// some conversion steps). // some conversion steps).
picture.use_argb = (config.lossless || config.use_sharp_yuv || picture.use_argb = (config.lossless || config.preprocessing > 0 ||
config.preprocessing > 0 ||
crop || (resize_w | resize_h) > 0); crop || (resize_w | resize_h) > 0);
if (verbose) { if (verbose) {
StopwatchReset(&stop_watch); StopwatchReset(&stop_watch);
@ -972,7 +964,7 @@ 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 = !strcmp(out_file, "-");
out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(out_file, "wb"); out = use_stdout ? ExUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
if (out == NULL) { if (out == NULL) {
fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file); fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
goto Error; goto Error;
@ -1096,6 +1088,20 @@ int main(int argc, const char *argv[]) {
if (print_distortion >= 0) { // print distortion if (print_distortion >= 0) { // print distortion
static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" }; static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };
float values[5]; float values[5];
if (picture.use_argb != original_picture.use_argb) {
// Somehow, the WebPEncode() call converted the original picture.
// We need to make both match before calling WebPPictureDistortion().
int ok = 0;
if (picture.use_argb) {
ok = WebPPictureYUVAToARGB(&original_picture);
} else {
ok = WebPPictureARGBToYUVA(&original_picture, WEBP_YUV420A);
}
if (!ok) {
fprintf(stderr, "Error while converting original picture.\n");
goto Error;
}
}
if (!WebPPictureDistortion(&picture, &original_picture, if (!WebPPictureDistortion(&picture, &original_picture,
print_distortion, values)) { print_distortion, values)) {
fprintf(stderr, "Error while computing the distortion.\n"); fprintf(stderr, "Error while computing the distortion.\n");
@ -1103,8 +1109,13 @@ int main(int argc, const char *argv[]) {
} }
if (!short_output) { if (!short_output) {
fprintf(stderr, "%s: ", distortion_names[print_distortion]); fprintf(stderr, "%s: ", distortion_names[print_distortion]);
fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n", if (picture.use_argb) {
values[0], values[1], values[2], values[3], values[4]); fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n",
values[0], values[1], values[2], values[3], values[4]);
} else {
fprintf(stderr, "Y:%.2f U:%.2f V:%.2f A:%.2f Total:%.2f\n",
values[0], values[1], values[2], values[3], values[4]);
}
} else { } else {
fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]); fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]);
} }

View File

@ -20,9 +20,27 @@
#include "webp/config.h" #include "webp/config.h"
#endif #endif
#include "../examples/example_util.h" #ifdef WEBP_HAVE_PNG
#include "../imageio/image_enc.h" #include <png.h>
#include "../imageio/webpdec.h" #include <setjmp.h> // note: this must be included *after* png.h
#endif
#ifdef HAVE_WINCODEC_H
#ifdef __MINGW32__
#define INITGUID // Without this GUIDs are declared extern and fail to link
#endif
#define CINTERFACE
#define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h>
#include <windows.h>
#include <wincodec.h>
#endif
#include "webp/decode.h"
#include "./example_util.h"
#include "./stopwatch.h" #include "./stopwatch.h"
static int verbose = 0; static int verbose = 0;
@ -39,18 +57,486 @@ extern void* VP8GetCPUInfo; // opaque forward declaration.
#endif #endif
#endif // WEBP_DLL #endif // WEBP_DLL
//------------------------------------------------------------------------------
// Output types
typedef enum {
PNG = 0,
PAM,
PPM,
PGM,
BMP,
TIFF,
RAW_YUV,
ALPHA_PLANE_ONLY, // this is for experimenting only
// forced colorspace output (for testing, mostly)
RGB, RGBA, BGR, BGRA, ARGB,
RGBA_4444, RGB_565,
rgbA, bgrA, Argb, rgbA_4444,
YUV, YUVA
} OutputFileFormat;
#ifdef HAVE_WINCODEC_H
#define IFS(fn) \
do { \
if (SUCCEEDED(hr)) { \
hr = (fn); \
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
} \
} while (0)
#ifdef __cplusplus
#define MAKE_REFGUID(x) (x)
#else
#define MAKE_REFGUID(x) &(x)
#endif
static HRESULT CreateOutputStream(const char* out_file_name,
int write_to_mem, IStream** stream) {
HRESULT hr = S_OK;
if (write_to_mem) {
// Output to a memory buffer. This is freed when 'stream' is released.
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
} else {
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
}
if (FAILED(hr)) {
fprintf(stderr, "Error opening output file %s (%08lx)\n",
out_file_name, hr);
}
return hr;
}
static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
REFGUID container_guid,
uint8_t* rgb, int stride,
uint32_t width, uint32_t height, int has_alpha) {
HRESULT hr = S_OK;
IWICImagingFactory* factory = NULL;
IWICBitmapFrameEncode* frame = NULL;
IWICBitmapEncoder* encoder = NULL;
IStream* stream = NULL;
WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
: GUID_WICPixelFormat24bppBGR;
IFS(CoInitialize(NULL));
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
CLSCTX_INPROC_SERVER,
MAKE_REFGUID(IID_IWICImagingFactory),
(LPVOID*)&factory));
if (hr == REGDB_E_CLASSNOTREG) {
fprintf(stderr,
"Couldn't access Windows Imaging Component (are you running "
"Windows XP SP3 or newer?). PNG support not available. "
"Use -ppm or -pgm for available PPM and PGM formats.\n");
}
IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
&encoder));
IFS(IWICBitmapEncoder_Initialize(encoder, stream,
WICBitmapEncoderNoCache));
IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
height * stride, rgb));
IFS(IWICBitmapFrameEncode_Commit(frame));
IFS(IWICBitmapEncoder_Commit(encoder));
if (SUCCEEDED(hr) && use_stdout) {
HGLOBAL image;
IFS(GetHGlobalFromStream(stream, &image));
if (SUCCEEDED(hr)) {
HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
const BOOL update_mode = GetConsoleMode(std_output, &mode);
const void* const image_mem = GlobalLock(image);
DWORD bytes_written = 0;
// Clear output processing if necessary, then output the image.
if (update_mode) SetConsoleMode(std_output, 0);
if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image),
&bytes_written, NULL) ||
bytes_written != GlobalSize(image)) {
hr = E_FAIL;
}
if (update_mode) SetConsoleMode(std_output, mode);
GlobalUnlock(image);
}
}
if (frame != NULL) IUnknown_Release(frame);
if (encoder != NULL) IUnknown_Release(encoder);
if (factory != NULL) IUnknown_Release(factory);
if (stream != NULL) IUnknown_Release(stream);
return hr;
}
static int WritePNG(const char* out_file_name, int use_stdout,
const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
MAKE_REFGUID(GUID_ContainerFormatPng),
rgb, stride, width, height, has_alpha));
}
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
(void)dummy; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1);
}
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
volatile png_structp png;
volatile png_infop info;
png_uint_32 y;
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, PNGErrorFunction, NULL);
if (png == NULL) {
return 0;
}
info = png_create_info_struct(png);
if (info == NULL) {
png_destroy_write_struct((png_structpp)&png, NULL);
return 0;
}
if (setjmp(png_jmpbuf(png))) {
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
return 0;
}
png_init_io(png, out_file);
png_set_IHDR(png, info, width, height, 8,
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png, info);
for (y = 0; y < height; ++y) {
png_bytep row = rgb + y * stride;
png_write_rows(png, &row, 1);
}
png_write_end(png, info);
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
return 1;
}
#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
static int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
(void)out_file;
(void)buffer;
fprintf(stderr, "PNG support not compiled. Please install the libpng "
"development package before building.\n");
fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n");
return 0;
}
#endif
static int WritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const size_t bytes_per_px = alpha ? 4 : 3;
uint32_t y;
if (alpha) {
fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n"
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
} else {
fprintf(fout, "P6\n%u %u\n255\n", width, height);
}
for (y = 0; y < height; ++y) {
if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
return 0;
}
}
return 1;
}
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
static int Write16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = 2;
uint32_t y;
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
for (y = 0; y < height; ++y) {
if (fwrite(rgba + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
return 0;
}
}
return 1;
}
static void PutLE16(uint8_t* const dst, uint32_t value) {
dst[0] = (value >> 0) & 0xff;
dst[1] = (value >> 8) & 0xff;
}
static void PutLE32(uint8_t* const dst, uint32_t value) {
PutLE16(dst + 0, (value >> 0) & 0xffff);
PutLE16(dst + 2, (value >> 16) & 0xffff);
}
#define BMP_HEADER_SIZE 54
static int WriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
uint32_t y;
const uint32_t line_size = bytes_per_px * width;
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
// bitmap file header
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
PutLE32(bmp_header + 2, total_size); // size including header
PutLE32(bmp_header + 6, 0); // reserved
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
// bitmap info header
PutLE32(bmp_header + 14, 40); // DIB header size
PutLE32(bmp_header + 18, width); // dimensions
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
PutLE16(bmp_header + 26, 1); // number of planes
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
PutLE32(bmp_header + 34, 0); // image size (dummy)
PutLE32(bmp_header + 38, 2400); // x pixels/meter
PutLE32(bmp_header + 42, 2400); // y pixels/meter
PutLE32(bmp_header + 46, 0); // number of palette colors
PutLE32(bmp_header + 50, 0); // important color count
// TODO(skal): color profile
// write header
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
return 0;
}
// write pixel array
for (y = 0; y < height; ++y) {
if (fwrite(rgba + y * stride, line_size, 1, fout) != 1) {
return 0;
}
// write padding zeroes
if (bmp_stride != line_size) {
const uint8_t zeroes[3] = { 0 };
if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
return 0;
}
}
}
return 1;
}
#undef BMP_HEADER_SIZE
#define NUM_IFD_ENTRIES 15
#define EXTRA_DATA_SIZE 16
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
static int WriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1;
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
0x49, 0x49, 0x2a, 0x00, // little endian signature
8, 0, 0, 0, // offset to the unique IFD that follows
// IFD (offset = 8). Entries must be written in increasing tag order.
num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
EXTRA_DATA_OFFSET + 0, 0, 0, 0,
0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
bytes_per_px, 0, 0, 0,
0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
0, 0, 0, 0, // 190: IFD terminator
// EXTRA_DATA_OFFSET:
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
};
uint32_t y;
// Fill placeholders in IFD:
PutLE32(tiff_header + 10 + 8, width);
PutLE32(tiff_header + 22 + 8, height);
PutLE32(tiff_header + 106 + 8, height);
PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
// write header
if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
return 0;
}
// write pixel values
for (y = 0; y < height; ++y) {
if (fwrite(rgba + y * stride, bytes_per_px, width, fout) != width) {
return 0;
}
}
return 1;
}
#undef TIFF_HEADER_SIZE
#undef EXTRA_DATA_OFFSET
#undef EXTRA_DATA_SIZE
#undef NUM_IFD_ENTRIES
static int WriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* const a = buffer->u.YUVA.a;
const int a_stride = buffer->u.YUVA.a_stride;
uint32_t y;
assert(a != NULL);
fprintf(fout, "P5\n%u %u\n255\n", width, height);
for (y = 0; y < height; ++y) {
if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
return 0;
}
}
return 1;
}
// format=PGM: save a grayscale PGM file using the IMC4 layout
// (http://www.fourcc.org/yuv.php#IMC4). This is a very convenient format for
// viewing the samples, esp. for odd dimensions.
// format=RAW_YUV: just save the Y/U/V/A planes sequentially without header.
static int WritePGMOrYUV(FILE* fout, const WebPDecBuffer* const buffer,
OutputFileFormat format) {
const int width = buffer->width;
const int height = buffer->height;
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
int ok = 1;
int y;
const int pad = (format == RAW_YUV) ? 0 : 1;
const int uv_width = (width + 1) / 2;
const int uv_height = (height + 1) / 2;
const int out_stride = (width + pad) & ~pad;
const int a_height = yuv->a ? height : 0;
if (format == PGM) {
fprintf(fout, "P5\n%d %d\n255\n",
out_stride, height + uv_height + a_height);
}
for (y = 0; ok && y < height; ++y) {
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
if (format == PGM) {
if (width & 1) fputc(0, fout); // padding byte
}
}
if (format == PGM) { // IMC4 layout
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
}
} else {
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
}
}
for (y = 0; ok && y < a_height; ++y) {
ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
if (format == PGM) {
if (width & 1) fputc(0, fout); // padding byte
}
}
return ok;
}
static int SaveOutput(const WebPDecBuffer* const buffer, static int SaveOutput(const WebPDecBuffer* const buffer,
WebPOutputFileFormat format, const char* const out_file) { OutputFileFormat format, const char* const out_file) {
const int use_stdout = (out_file != NULL) && !strcmp(out_file, "-"); FILE* fout = NULL;
int needs_open_file = 1;
const int use_stdout = !strcmp(out_file, "-");
int ok = 1; int ok = 1;
Stopwatch stop_watch; Stopwatch stop_watch;
if (verbose) { if (verbose) {
StopwatchReset(&stop_watch); StopwatchReset(&stop_watch);
} }
ok = WebPSaveImage(buffer, format, out_file);
#ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG);
#endif
if (needs_open_file) {
fout = use_stdout ? ExUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file %s\n", out_file);
return 0;
}
}
if (format == PNG ||
format == RGBA || format == BGRA || format == ARGB ||
format == rgbA || format == bgrA || format == Argb) {
#ifdef HAVE_WINCODEC_H
ok &= WritePNG(out_file, use_stdout, buffer);
#else
ok &= WritePNG(fout, buffer);
#endif
} else if (format == PAM) {
ok &= WritePPM(fout, buffer, 1);
} else if (format == PPM || format == RGB || format == BGR) {
ok &= WritePPM(fout, buffer, 0);
} else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) {
ok &= Write16bAsPGM(fout, buffer);
} else if (format == BMP) {
ok &= WriteBMP(fout, buffer);
} else if (format == TIFF) {
ok &= WriteTIFF(fout, buffer);
} else if (format == PGM || format == RAW_YUV ||
format == YUV || format == YUVA) {
ok &= WritePGMOrYUV(fout, buffer, format == RAW_YUV ? RAW_YUV : PGM);
} else if (format == ALPHA_PLANE_ONLY) {
ok &= WriteAlphaPlane(fout, buffer);
}
if (fout != NULL && fout != stdout) {
fclose(fout);
}
if (ok) { if (ok) {
if (!quiet) { if (!quiet) {
if (use_stdout) { if (use_stdout) {
@ -112,7 +598,7 @@ static const char* const kFormatType[] = {
}; };
static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config, static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
WebPOutputFileFormat format, OutputFileFormat format,
int use_external_memory) { int use_external_memory) {
uint8_t* external_buffer = NULL; uint8_t* external_buffer = NULL;
WebPDecBuffer* const output_buffer = &config->output; WebPDecBuffer* const output_buffer = &config->output;
@ -183,7 +669,7 @@ int main(int argc, const char *argv[]) {
WebPDecoderConfig config; WebPDecoderConfig config;
WebPDecBuffer* const output_buffer = &config.output; WebPDecBuffer* const output_buffer = &config.output;
WebPBitstreamFeatures* const bitstream = &config.input; WebPBitstreamFeatures* const bitstream = &config.input;
WebPOutputFileFormat format = PNG; OutputFileFormat format = PNG;
uint8_t* external_buffer = NULL; uint8_t* external_buffer = NULL;
int use_external_memory = 0; int use_external_memory = 0;
const uint8_t* data = NULL; const uint8_t* data = NULL;
@ -311,7 +797,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 (!ExUtilLoadWebP(in_file, &data, &data_size, bitstream)) {
return -1; return -1;
} }
@ -332,8 +818,9 @@ int main(int argc, const char *argv[]) {
case BMP: case BMP:
output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
break; break;
case TIFF: case TIFF: // note: force pre-multiplied alpha
output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; output_buffer->colorspace =
bitstream->has_alpha ? MODE_rgbA : MODE_RGB;
break; break;
case PGM: case PGM:
case RAW_YUV: case RAW_YUV:
@ -365,24 +852,15 @@ int main(int argc, const char *argv[]) {
if (external_buffer == NULL) goto Exit; if (external_buffer == NULL) goto Exit;
} }
{ if (incremental) {
Stopwatch stop_watch; status = ExUtilDecodeWebPIncremental(data, data_size, verbose, &config);
if (verbose) StopwatchReset(&stop_watch); } else {
status = ExUtilDecodeWebP(data, data_size, verbose, &config);
if (incremental) {
status = DecodeWebPIncremental(data, data_size, &config);
} else {
status = DecodeWebP(data, data_size, &config);
}
if (verbose) {
const double decode_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
}
} }
ok = (status == VP8_STATUS_OK); ok = (status == VP8_STATUS_OK);
if (!ok) { if (!ok) {
PrintWebPError(in_file, status); ExUtilPrintWebPError(in_file, status);
goto Exit; goto Exit;
} }
} }

View File

@ -12,13 +12,16 @@
#include "./example_util.h" #include "./example_util.h"
#include <assert.h> #if defined(_WIN32)
#include <fcntl.h> // for _O_BINARY
#include <io.h> // for _setmode()
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/mux_types.h" #include "webp/decode.h"
#include "../imageio/imageio_util.h" #include "./stopwatch.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// String parsing // String parsing
@ -38,18 +41,6 @@ int ExUtilGetInt(const char* const v, int base, int* const error) {
return (int)ExUtilGetUInt(v, base, error); return (int)ExUtilGetUInt(v, base, error);
} }
int ExUtilGetInts(const char* v, int base, int max_output, int output[]) {
int n, error = 0;
for (n = 0; v != NULL && n < max_output; ++n) {
const int value = ExUtilGetInt(v, base, &error);
if (error) return -1;
output[n] = value;
v = strchr(v, ',');
if (v != NULL) ++v; // skip over the trailing ','
}
return n;
}
float ExUtilGetFloat(const char* const v, int* const error) { float ExUtilGetFloat(const char* const v, int* const error) {
char* end = NULL; char* end = NULL;
const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f; const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f;
@ -61,67 +52,237 @@ float ExUtilGetFloat(const char* const v, int* const error) {
return f; return f;
} }
//------------------------------------------------------------------------------ // -----------------------------------------------------------------------------
// File I/O
static void ResetCommandLineArguments(int argc, const char* argv[], FILE* ExUtilSetBinaryMode(FILE* file) {
CommandLineArguments* const args) { #if defined(_WIN32)
assert(args != NULL); if (_setmode(_fileno(file), _O_BINARY) == -1) {
args->argc_ = argc; fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
args->argv_ = argv; return NULL;
args->own_argv_ = 0; }
WebPDataInit(&args->argv_data_); #endif
return file;
} }
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) { int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
if (args != NULL) { static const size_t kBlockSize = 16384; // default initial size
if (args->own_argv_) { size_t max_size = 0;
free((void*)args->argv_); size_t size = 0;
WebPDataClear(&args->argv_data_); uint8_t* input = NULL;
}
ResetCommandLineArguments(0, NULL, args); if (data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
if (!ExUtilSetBinaryMode(stdin)) return 0;
while (!feof(stdin)) {
// We double the buffer size each time and read as much as possible.
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
void* const new_data = realloc(input, max_size + extra_size);
if (new_data == NULL) goto Error;
input = (uint8_t*)new_data;
max_size += extra_size;
size += fread(input + size, 1, extra_size, stdin);
if (size < max_size) break;
}
if (ferror(stdin)) goto Error;
*data = input;
*data_size = size;
return 1;
Error:
free(input);
fprintf(stderr, "Could not read from stdin\n");
return 0;
}
int ExUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size) {
int ok;
void* file_data;
size_t file_size;
FILE* in;
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
if (from_stdin) return ExUtilReadFromStdin(data, data_size);
if (data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
in = fopen(file_name, "rb");
if (in == NULL) {
fprintf(stderr, "cannot open input file '%s'\n", file_name);
return 0;
}
fseek(in, 0, SEEK_END);
file_size = ftell(in);
fseek(in, 0, SEEK_SET);
file_data = malloc(file_size);
if (file_data == NULL) return 0;
ok = (fread(file_data, file_size, 1, in) == 1);
fclose(in);
if (!ok) {
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
(int)file_size, file_name);
free(file_data);
return 0;
}
*data = (uint8_t*)file_data;
*data_size = file_size;
return 1;
}
int ExUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size) {
int ok;
FILE* out;
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
if (data == NULL) {
return 0;
}
out = to_stdout ? stdout : fopen(file_name, "wb");
if (out == NULL) {
fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
return 0;
}
ok = (fwrite(data, data_size, 1, out) == 1);
if (out != stdout) fclose(out);
return ok;
}
//------------------------------------------------------------------------------
// WebP decoding
static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
"OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
};
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
if (config->input.has_animation) {
fprintf(stderr,
"Error! Decoding of an animated WebP file is not supported.\n"
" Use webpmux to extract the individual frames or\n"
" vwebp to view this image.\n");
} }
} }
#define MAX_ARGC 16384 void ExUtilPrintWebPError(const char* const in_file, int status) {
int ExUtilInitCommandLineArguments(int argc, const char* argv[], fprintf(stderr, "Decoding of %s failed.\n", in_file);
CommandLineArguments* const args) { fprintf(stderr, "Status: %d", status);
if (args == NULL || argv == NULL) return 0; if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
ResetCommandLineArguments(argc, argv, args); fprintf(stderr, "(%s)", kStatusMessages[status]);
if (argc == 1 && argv[0][0] != '-') { }
char* cur; fprintf(stderr, "\n");
const char sep[] = " \t\r\n\f\v"; }
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) {
return 0;
}
args->own_argv_ = 1;
args->argv_ = (const char**)malloc(MAX_ARGC * sizeof(*args->argv_));
if (args->argv_ == NULL) return 0;
argc = 0; int ExUtilLoadWebP(const char* const in_file,
for (cur = strtok((char*)args->argv_data_.bytes, sep); const uint8_t** data, size_t* data_size,
cur != NULL; WebPBitstreamFeatures* bitstream) {
cur = strtok(NULL, sep)) { VP8StatusCode status;
if (argc == MAX_ARGC) { WebPBitstreamFeatures local_features;
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC); if (!ExUtilReadFile(in_file, data, data_size)) return 0;
return 0;
if (bitstream == NULL) {
bitstream = &local_features;
}
status = WebPGetFeatures(*data, *data_size, bitstream);
if (status != VP8_STATUS_OK) {
free((void*)*data);
*data = NULL;
*data_size = 0;
ExUtilPrintWebPError(in_file, status);
return 0;
}
return 1;
}
//------------------------------------------------------------------------------
VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
int verbose, WebPDecoderConfig* const config) {
Stopwatch stop_watch;
VP8StatusCode status = VP8_STATUS_OK;
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
PrintAnimationWarning(config);
StopwatchReset(&stop_watch);
// Decoding call.
status = WebPDecode(data, data_size, config);
if (verbose) {
const double decode_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
}
return status;
}
VP8StatusCode ExUtilDecodeWebPIncremental(
const uint8_t* const data, size_t data_size,
int verbose, WebPDecoderConfig* const config) {
Stopwatch stop_watch;
VP8StatusCode status = VP8_STATUS_OK;
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
PrintAnimationWarning(config);
StopwatchReset(&stop_watch);
// Decoding call.
{
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
if (idec == NULL) {
fprintf(stderr, "Failed during WebPINewDecoder().\n");
return VP8_STATUS_OUT_OF_MEMORY;
} else {
#ifdef WEBP_EXPERIMENTAL_FEATURES
size_t size = 0;
const size_t incr = 2 + (data_size / 20);
while (size < data_size) {
size_t next_size = size + (rand() % incr);
if (next_size > data_size) next_size = data_size;
status = WebPIUpdate(idec, data, next_size);
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) break;
size = next_size;
} }
assert(strlen(cur) != 0); #else
args->argv_[argc++] = cur; status = WebPIUpdate(idec, data, data_size);
#endif
WebPIDelete(idec);
} }
args->argc_ = argc;
} }
return 1;
if (verbose) {
const double decode_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
}
return status;
} }
//------------------------------------------------------------------------------ // -----------------------------------------------------------------------------
int ExUtilReadFileToWebPData(const char* const filename, void ExUtilCopyPlane(const uint8_t* src, int src_stride,
WebPData* const webp_data) { uint8_t* dst, int dst_stride, int width, int height) {
const uint8_t* data; while (height-- > 0) {
size_t size; memcpy(dst, src, width * sizeof(*dst));
if (webp_data == NULL) return 0; src += src_stride;
if (!ImgIoUtilReadFile(filename, &data, &size)) return 0; dst += dst_stride;
webp_data->bytes = data; }
webp_data->size = size;
return 1;
} }
// -----------------------------------------------------------------------------
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
return (total_size == (size_t)total_size);
}
// -----------------------------------------------------------------------------

View File

@ -13,8 +13,8 @@
#ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_ #ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_ #define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#include "webp/types.h" #include <stdio.h>
#include "webp/mux_types.h" #include "webp/decode.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -30,38 +30,68 @@ uint32_t ExUtilGetUInt(const char* const v, int base, int* const error);
int ExUtilGetInt(const char* const v, int base, int* const error); int ExUtilGetInt(const char* const v, int base, int* const error);
float ExUtilGetFloat(const char* const v, int* const error); float ExUtilGetFloat(const char* const v, int* const error);
// This variant of ExUtilGetInt() will parse multiple integers from a //------------------------------------------------------------------------------
// comma-separated list. Up to 'max_output' integers are parsed. // File I/O
// The result is placed in the output[] array, and the number of integers
// actually parsed is returned, or -1 if an error occurred.
int ExUtilGetInts(const char* v, int base, int max_output, int output[]);
// Reads a file named 'filename' into a WebPData structure. The content of // Reopen file in binary (O_BINARY) mode.
// webp_data is overwritten. Returns false in case of error. // Returns 'file' on success, NULL otherwise.
int ExUtilReadFileToWebPData(const char* const filename, FILE* ExUtilSetBinaryMode(FILE* file);
WebPData* const webp_data);
// Allocates storage for entire file 'file_name' and returns contents and size
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
// be deleted using free().
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
// the function ExUtilReadFromStdin().
int ExUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size);
// Same as ExUtilReadFile(), but reads until EOF from stdin instead.
int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size);
// Write a data segment into a file named 'file_name'. Returns true if ok.
// If 'file_name' is NULL or equal to "-", output is written to stdout.
int ExUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Command-line arguments
typedef struct { // Copy width x height pixels from 'src' to 'dst' honoring the strides.
int argc_; void ExUtilCopyPlane(const uint8_t* src, int src_stride,
const char** argv_; uint8_t* dst, int dst_stride, int width, int height);
WebPData argv_data_;
int own_argv_;
} CommandLineArguments;
// Initializes the structure from the command-line parameters. If there is //------------------------------------------------------------------------------
// only one parameter and it does not start with a '-', then it is assumed to
// be a file name. This file will be read and tokenized into command-line
// arguments. The content of 'args' is overwritten.
// Returns false in case of error (memory allocation failure, non
// existing file, too many arguments, ...).
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args);
// Deallocate all memory and reset 'args'. // Returns 0 in case of overflow of nmemb * size.
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args); int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
//------------------------------------------------------------------------------
// WebP decoding
// Prints an informative error message regarding decode failure of 'in_file'.
// 'status' is treated as a VP8StatusCode and if valid will be printed as a
// text string.
void ExUtilPrintWebPError(const char* const in_file, int status);
// Reads a WebP from 'in_file', returning the contents and size in 'data' and
// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures().
// Returns true on success.
int ExUtilLoadWebP(const char* const in_file,
const uint8_t** data, size_t* data_size,
WebPBitstreamFeatures* bitstream);
// Decodes the WebP contained in 'data'.
// 'config' is a structure previously initialized by WebPInitDecoderConfig().
// 'config->output' should have the desired colorspace selected. 'verbose' will
// cause decode timing to be reported.
// Returns the decoder status. On success 'config->output' will contain the
// decoded picture.
VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
int verbose, WebPDecoderConfig* const config);
// Same as ExUtilDecodeWebP(), but using the incremental decoder.
VP8StatusCode ExUtilDecodeWebPIncremental(
const uint8_t* const data, size_t data_size,
int verbose, WebPDecoderConfig* const config);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -23,21 +23,12 @@
#ifdef WEBP_HAVE_GIF #ifdef WEBP_HAVE_GIF
#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <gif_lib.h> #include <gif_lib.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "webp/mux.h" #include "webp/mux.h"
#include "../examples/example_util.h" #include "./example_util.h"
#include "../imageio/imageio_util.h"
#include "./gifdec.h" #include "./gifdec.h"
#if !defined(STDIN_FILENO)
#define STDIN_FILENO 0
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static int transparent_index = GIF_INDEX_INVALID; // Opaque by default. static int transparent_index = GIF_INDEX_INVALID; // Opaque by default.
@ -80,10 +71,8 @@ static void Help(void) {
printf(" -metadata <string> ..... comma separated list of metadata to\n"); printf(" -metadata <string> ..... comma separated list of metadata to\n");
printf(" "); printf(" ");
printf("copy from the input to the output if present\n"); printf("copy from the input to the output if present\n");
printf(" "); printf(" "
printf("Valid values: all, none, icc, xmp (default)\n"); "Valid values: all, none, icc, xmp (default)\n");
printf(" -loop_compatibility .... use compatibility mode for Chrome\n");
printf(" version prior to M62 (inclusive)\n");
printf(" -mt .................... use multi-threading if available\n"); printf(" -mt .................... use multi-threading if available\n");
printf("\n"); printf("\n");
printf(" -version ............... print version number and exit\n"); printf(" -version ............... print version number and exit\n");
@ -114,7 +103,7 @@ int main(int argc, const char *argv[]) {
WebPAnimEncoderOptions enc_options; WebPAnimEncoderOptions enc_options;
WebPConfig config; WebPConfig config;
int frame_number = 0; // Whether we are processing the first frame. int is_first_frame = 1; // Whether we are processing the first frame.
int done; int done;
int c; int c;
int quiet = 0; int quiet = 0;
@ -125,9 +114,8 @@ int main(int argc, const char *argv[]) {
int stored_icc = 0; // Whether we have already stored an ICC profile. int stored_icc = 0; // Whether we have already stored an ICC profile.
WebPData xmp_data; WebPData xmp_data;
int stored_xmp = 0; // Whether we have already stored an XMP profile. int stored_xmp = 0; // Whether we have already stored an XMP profile.
int loop_count = 0; // default: infinite int loop_count = 0;
int stored_loop_count = 0; // Whether we have found an explicit loop count. int stored_loop_count = 0; // Whether we have found an explicit loop count.
int loop_compatibility = 0;
WebPMux* mux = NULL; WebPMux* mux = NULL;
int default_kmin = 1; // Whether to use default kmin value. int default_kmin = 1; // Whether to use default kmin value.
@ -162,8 +150,6 @@ int main(int argc, const char *argv[]) {
} else if (!strcmp(argv[c], "-mixed")) { } else if (!strcmp(argv[c], "-mixed")) {
enc_options.allow_mixed = 1; enc_options.allow_mixed = 1;
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-loop_compatibility")) {
loop_compatibility = 1;
} else if (!strcmp(argv[c], "-q") && c < argc - 1) { } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
config.quality = ExUtilGetFloat(argv[++c], &parse_error); config.quality = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
@ -271,11 +257,9 @@ int main(int argc, const char *argv[]) {
// Start the decoder object // Start the decoder object
#if LOCAL_GIF_PREREQ(5,0) #if LOCAL_GIF_PREREQ(5,0)
gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO, &gif_error) gif = DGifOpenFileName(in_file, &gif_error);
: DGifOpenFileName(in_file, &gif_error);
#else #else
gif = !strcmp(in_file, "-") ? DGifOpenFileHandle(STDIN_FILENO) gif = DGifOpenFileName(in_file);
: DGifOpenFileName(in_file);
#endif #endif
if (gif == NULL) goto End; if (gif == NULL) goto End;
@ -292,7 +276,7 @@ int main(int argc, const char *argv[]) {
if (!DGifGetImageDesc(gif)) goto End; if (!DGifGetImageDesc(gif)) goto End;
if (frame_number == 0) { if (is_first_frame) {
if (verbose) { if (verbose) {
printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight); printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight);
} }
@ -334,6 +318,7 @@ int main(int argc, const char *argv[]) {
"a memory error.\n"); "a memory error.\n");
goto End; goto End;
} }
is_first_frame = 0;
} }
// Some even more broken GIF can have sub-rect with zero width/height. // Some even more broken GIF can have sub-rect with zero width/height.
@ -350,25 +335,13 @@ int main(int argc, const char *argv[]) {
GIFBlendFrames(&frame, &gif_rect, &curr_canvas); GIFBlendFrames(&frame, &gif_rect, &curr_canvas);
if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) { if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) {
fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number, fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
WebPAnimEncoderGetError(enc));
goto End;
} else {
++frame_number;
} }
// Update canvases. // Update canvases.
GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas); GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas);
GIFCopyPixels(&curr_canvas, &prev_canvas); GIFCopyPixels(&curr_canvas, &prev_canvas);
// Force frames with a small or no duration to 100ms to be consistent
// with web browsers and other transcoding tools. This also avoids
// incorrect durations between frames when padding frames are
// discarded.
if (frame_duration <= 10) {
frame_duration = 100;
}
// Update timestamp (for next frame). // Update timestamp (for next frame).
frame_timestamp += frame_duration; frame_timestamp += frame_duration;
@ -412,7 +385,7 @@ int main(int argc, const char *argv[]) {
if (verbose) { if (verbose) {
fprintf(stderr, "Loop count: %d\n", loop_count); fprintf(stderr, "Loop count: %d\n", loop_count);
} }
stored_loop_count = loop_compatibility ? (loop_count != 0) : 1; stored_loop_count = (loop_count != 0);
} else { // An extension containing metadata. } else { // An extension containing metadata.
// We only store the first encountered chunk of each type, and // We only store the first encountered chunk of each type, and
// only if requested by the user. // only if requested by the user.
@ -469,23 +442,6 @@ int main(int argc, const char *argv[]) {
goto End; goto End;
} }
if (!loop_compatibility) {
if (!stored_loop_count) {
// if no loop-count element is seen, the default is '1' (loop-once)
// and we need to signal it explicitly in WebP. Note however that
// in case there's a single frame, we still don't need to store it.
if (frame_number > 1) {
stored_loop_count = 1;
loop_count = 1;
}
} else if (loop_count > 0 && loop_count < 65535) {
// adapt GIF's semantic to WebP's (except in the infinite-loop case)
loop_count += 1;
}
}
// loop_count of 0 is the default (infinite), so no need to signal it
if (loop_count == 0) stored_loop_count = 0;
if (stored_loop_count || stored_icc || stored_xmp) { if (stored_loop_count || stored_icc || stored_xmp) {
// Re-mux to add loop count and/or metadata as needed. // Re-mux to add loop count and/or metadata as needed.
mux = WebPMuxCreate(&webp_data, 1); mux = WebPMuxCreate(&webp_data, 1);
@ -545,18 +501,13 @@ 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 (!ExUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
fprintf(stderr, "Error writing output file: %s\n", out_file); fprintf(stderr, "Error writing output file: %s\n", out_file);
goto End; goto End;
} }
if (!quiet) { if (!quiet) {
if (!strcmp(out_file, "-")) { fprintf(stderr, "Saved output file (%d bytes): %s\n",
fprintf(stderr, "Saved %d bytes to STDIO\n", (int)webp_data.size, out_file);
(int)webp_data.size);
} else {
fprintf(stderr, "Saved output file (%d bytes): %s\n",
(int)webp_data.size, out_file);
}
} }
} else { } else {
if (!quiet) { if (!quiet) {

View File

@ -21,24 +21,18 @@
#include "webp/encode.h" #include "webp/encode.h"
#include "webp/mux_types.h" #include "webp/mux_types.h"
#define GIF_TRANSPARENT_COLOR 0x00000000u #define GIF_TRANSPARENT_COLOR 0x00000000
#define GIF_WHITE_COLOR 0xffffffffu #define GIF_WHITE_COLOR 0xffffffff
#define GIF_TRANSPARENT_MASK 0x01 #define GIF_TRANSPARENT_MASK 0x01
#define GIF_DISPOSE_MASK 0x07 #define GIF_DISPOSE_MASK 0x07
#define GIF_DISPOSE_SHIFT 2 #define GIF_DISPOSE_SHIFT 2
// from utils/utils.h // from utils/utils.h
#ifdef __cplusplus
extern "C" {
#endif
extern void WebPCopyPlane(const uint8_t* src, int src_stride, extern void WebPCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, uint8_t* dst, int dst_stride,
int width, int height); int width, int height);
extern void WebPCopyPixels(const WebPPicture* const src, extern void WebPCopyPixels(const WebPPicture* const src,
WebPPicture* const dst); WebPPicture* const dst);
#ifdef __cplusplus
}
#endif
void GIFGetBackgroundColor(const ColorMapObject* const color_map, void GIFGetBackgroundColor(const ColorMapObject* const color_map,
int bgcolor_index, int transparent_index, int bgcolor_index, int transparent_index,
@ -54,7 +48,7 @@ void GIFGetBackgroundColor(const ColorMapObject* const color_map,
"white background.\n"); "white background.\n");
} else { } else {
const GifColorType color = color_map->Colors[bgcolor_index]; const GifColorType color = color_map->Colors[bgcolor_index];
*bgcolor = (0xffu << 24) *bgcolor = (0xff << 24)
| (color.Red << 16) | (color.Red << 16)
| (color.Green << 8) | (color.Green << 8)
| (color.Blue << 0); | (color.Blue << 0);

View File

@ -29,38 +29,18 @@ WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
format = WEBP_TIFF_FORMAT; format = WEBP_TIFF_FORMAT;
} else if (magic1 == 0x52494646 && magic2 == 0x57454250) { } else if (magic1 == 0x52494646 && magic2 == 0x57454250) {
format = WEBP_WEBP_FORMAT; format = WEBP_WEBP_FORMAT;
} else if (((magic1 >> 24) & 0xff) == 'P') {
const int type = (magic1 >> 16) & 0xff;
// we only support 'P5 -> P7' for now.
if (type >= '5' && type <= '7') format = WEBP_PNM_FORMAT;
} }
} }
return format; return format;
} }
static int FailReader(const uint8_t* const data, size_t data_size, WebPImageReader WebPGuessImageReader(const uint8_t* const data,
struct WebPPicture* const pic, size_t data_size) {
int keep_alpha, struct Metadata* const metadata) { switch (WebPGuessImageType(data, data_size)) {
(void)data;
(void)data_size;
(void)pic;
(void)keep_alpha;
(void)metadata;
return 0;
}
WebPImageReader WebPGetImageReader(WebPInputFileFormat format) {
switch (format) {
case WEBP_PNG_FORMAT: return ReadPNG; case WEBP_PNG_FORMAT: return ReadPNG;
case WEBP_JPEG_FORMAT: return ReadJPEG; case WEBP_JPEG_FORMAT: return ReadJPEG;
case WEBP_TIFF_FORMAT: return ReadTIFF; case WEBP_TIFF_FORMAT: return ReadTIFF;
case WEBP_WEBP_FORMAT: return ReadWebP; case WEBP_WEBP_FORMAT: return ReadWebP;
case WEBP_PNM_FORMAT: return ReadPNM; default: return NULL;
default: return FailReader;
} }
} }
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
size_t data_size) {
return WebPGetImageReader(WebPGuessImageType(data, data_size));
}

View File

@ -11,8 +11,8 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_ #ifndef WEBP_EXAMPLES_IMAGE_DEC_H_
#define WEBP_IMAGEIO_IMAGE_DEC_H_ #define WEBP_EXAMPLES_IMAGE_DEC_H_
#include "webp/types.h" #include "webp/types.h"
@ -23,7 +23,6 @@
#include "./metadata.h" #include "./metadata.h"
#include "./jpegdec.h" #include "./jpegdec.h"
#include "./pngdec.h" #include "./pngdec.h"
#include "./pnmdec.h"
#include "./tiffdec.h" #include "./tiffdec.h"
#include "./webpdec.h" #include "./webpdec.h"
#include "./wicdec.h" #include "./wicdec.h"
@ -37,7 +36,6 @@ typedef enum {
WEBP_JPEG_FORMAT, WEBP_JPEG_FORMAT,
WEBP_TIFF_FORMAT, WEBP_TIFF_FORMAT,
WEBP_WEBP_FORMAT, WEBP_WEBP_FORMAT,
WEBP_PNM_FORMAT,
WEBP_UNSUPPORTED_FORMAT WEBP_UNSUPPORTED_FORMAT
} WebPInputFileFormat; } WebPInputFileFormat;
@ -51,12 +49,8 @@ typedef int (*WebPImageReader)(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic, struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata); int keep_alpha, struct Metadata* const metadata);
// Return the reader associated to a given file format.
WebPImageReader WebPGetImageReader(WebPInputFileFormat format);
// This function is similar to WebPGuessImageType(), but returns a // This function is similar to WebPGuessImageType(), but returns a
// suitable reader function. The returned reader is never NULL, but // suitable reader function. Or NULL if the image can't be guessed.
// unknown formats will return an always-failing valid reader.
WebPImageReader WebPGuessImageReader(const uint8_t* const data, WebPImageReader WebPGuessImageReader(const uint8_t* const data,
size_t data_size); size_t data_size);
@ -64,4 +58,4 @@ WebPImageReader WebPGuessImageReader(const uint8_t* const data,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_IMAGE_DEC_H_ #endif // WEBP_EXAMPLES_IMAGE_DEC_H_

View File

@ -1,314 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// generate an animated WebP out of a sequence of images
// (PNG, JPEG, ...)
//
// Example usage:
// img2webp -o out.webp -q 40 -mixed -duration 40 input??.png
//
// Author: skal@google.com (Pascal Massimino)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "../examples/example_util.h"
#include "../imageio/image_dec.h"
#include "../imageio/imageio_util.h"
#include "./stopwatch.h"
#include "webp/encode.h"
#include "webp/mux.h"
//------------------------------------------------------------------------------
static void Help(void) {
printf("Usage:\n\n");
printf(" img2webp [file-level options] [image files...] "
"[per-frame options...]\n");
printf("\n");
printf("File-level options (only used at the start of compression):\n");
printf(" -min_size ............ minimize size\n");
printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
" (0=only keyframes)\n");
printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
" (0=disable key-frames altogether)\n");
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
printf(" -v ................... verbose mode\n");
printf(" -h ................... this help\n");
printf(" -version ............. print version number and exit\n");
printf("\n");
printf("Per-frame options (only used for subsequent images input):\n");
printf(" -d <int> ............. frame duration in ms (default: 100)\n");
printf(" -lossless ........... use lossless mode (default)\n");
printf(" -lossy ... ........... use lossy mode\n");
printf(" -q <float> ........... quality\n");
printf(" -m <int> ............. method to use\n");
printf("\n");
printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n"
" -d 80 in2.tiff -o out.webp\n");
}
//------------------------------------------------------------------------------
static int ReadImage(const char filename[], WebPPicture* const pic) {
const uint8_t* data = NULL;
size_t data_size = 0;
WebPImageReader reader;
int ok;
#ifdef HAVE_WINCODEC_H
// Try to decode the file using WIC falling back to the other readers for
// e.g., WebP.
ok = ReadPictureWithWIC(filename, pic, 1, NULL);
if (ok) return 1;
#endif
if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0;
reader = WebPGuessImageReader(data, data_size);
ok = reader(data, data_size, pic, 1, NULL);
free((void*)data);
return ok;
}
static int SetLoopCount(int loop_count, WebPData* const webp_data) {
int ok = 1;
WebPMuxError err;
uint32_t features;
WebPMuxAnimParams new_params;
WebPMux* const mux = WebPMuxCreate(webp_data, 1);
if (mux == NULL) return 0;
err = WebPMuxGetFeatures(mux, &features);
ok = (err == WEBP_MUX_OK);
if (!ok || !(features & ANIMATION_FLAG)) goto End;
err = WebPMuxGetAnimationParams(mux, &new_params);
ok = (err == WEBP_MUX_OK);
if (ok) {
new_params.loop_count = loop_count;
err = WebPMuxSetAnimationParams(mux, &new_params);
ok = (err == WEBP_MUX_OK);
}
if (ok) {
WebPDataClear(webp_data);
err = WebPMuxAssemble(mux, webp_data);
ok = (err == WEBP_MUX_OK);
}
End:
WebPMuxDelete(mux);
if (!ok) {
fprintf(stderr, "Error during loop-count setting\n");
}
return ok;
}
//------------------------------------------------------------------------------
int main(int argc, const char* argv[]) {
const char* output = NULL;
WebPAnimEncoder* enc = NULL;
int verbose = 0;
int pic_num = 0;
int duration = 100;
int timestamp_ms = 0;
int loop_count = 0;
int width = 0, height = 0;
WebPAnimEncoderOptions anim_config;
WebPConfig config;
WebPPicture pic;
WebPData webp_data;
int c;
int have_input = 0;
CommandLineArguments cmd_args;
int ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
if (!ok) return 1;
argc = cmd_args.argc_;
argv = cmd_args.argv_;
WebPDataInit(&webp_data);
if (!WebPAnimEncoderOptionsInit(&anim_config) ||
!WebPConfigInit(&config) ||
!WebPPictureInit(&pic)) {
fprintf(stderr, "Library version mismatch!\n");
ok = 0;
goto End;
}
// 1st pass of option parsing
for (c = 0; ok && c < argc; ++c) {
if (argv[c][0] == '-') {
int parse_error = 0;
if (!strcmp(argv[c], "-o") && c + 1 < argc) {
argv[c] = NULL;
output = argv[++c];
} else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) {
argv[c] = NULL;
anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-kmax") && c + 1 < argc) {
argv[c] = NULL;
anim_config.kmax = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-loop") && c + 1 < argc) {
argv[c] = NULL;
loop_count = ExUtilGetInt(argv[++c], 0, &parse_error);
if (loop_count < 0) {
fprintf(stderr, "Invalid non-positive loop-count (%d)\n", loop_count);
parse_error = 1;
}
} else if (!strcmp(argv[c], "-min_size")) {
anim_config.minimize_size = 1;
} else if (!strcmp(argv[c], "-mixed")) {
anim_config.allow_mixed = 1;
config.lossless = 0;
} else if (!strcmp(argv[c], "-v")) {
verbose = 1;
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
goto End;
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
goto End;
} else {
continue;
}
ok = !parse_error;
if (!ok) goto End;
argv[c] = NULL; // mark option as 'parsed' during 1st pass
} else {
have_input |= 1;
}
}
if (!have_input) {
fprintf(stderr, "No input file(s) for generating animation!\n");
goto End;
}
// image-reading pass
pic_num = 0;
config.lossless = 1;
for (c = 0; ok && c < argc; ++c) {
if (argv[c] == NULL) continue;
if (argv[c][0] == '-') { // parse local options
int parse_error = 0;
if (!strcmp(argv[c], "-lossy")) {
if (!anim_config.allow_mixed) config.lossless = 0;
} else if (!strcmp(argv[c], "-lossless")) {
if (!anim_config.allow_mixed) config.lossless = 1;
} else if (!strcmp(argv[c], "-q") && c + 1 < argc) {
config.quality = ExUtilGetFloat(argv[++c], &parse_error);
} else if (!strcmp(argv[c], "-m") && c + 1 < argc) {
config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-d") && c + 1 < argc) {
duration = ExUtilGetInt(argv[++c], 0, &parse_error);
if (duration <= 0) {
fprintf(stderr, "Invalid negative duration (%d)\n", duration);
parse_error = 1;
}
} else {
parse_error = 1; // shouldn't be here.
fprintf(stderr, "Unknown option [%s]\n", argv[c]);
}
ok = !parse_error;
if (!ok) goto End;
continue;
}
if (ok) {
ok = WebPValidateConfig(&config);
if (!ok) {
fprintf(stderr, "Invalid configuration.\n");
goto End;
}
}
// read next input image
pic.use_argb = 1;
ok = ReadImage(argv[c], &pic);
if (!ok) goto End;
if (enc == NULL) {
width = pic.width;
height = pic.height;
enc = WebPAnimEncoderNew(width, height, &anim_config);
ok = (enc != NULL);
if (!ok) {
fprintf(stderr, "Could not create WebPAnimEncoder object.\n");
}
}
if (ok) {
ok = (width == pic.width && height == pic.height);
if (!ok) {
fprintf(stderr, "Frame #%d dimension mismatched! "
"Got %d x %d. Was expecting %d x %d.\n",
pic_num, pic.width, pic.height, width, height);
}
}
if (ok) {
ok = WebPAnimEncoderAdd(enc, &pic, timestamp_ms, &config);
if (!ok) {
fprintf(stderr, "Error while adding frame #%d\n", pic_num);
}
}
WebPPictureFree(&pic);
if (!ok) goto End;
if (verbose) {
fprintf(stderr, "Added frame #%3d at time %4d (file: %s)\n",
pic_num, timestamp_ms, argv[c]);
}
timestamp_ms += duration;
++pic_num;
}
// add a last fake frame to signal the last duration
ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
ok = ok && WebPAnimEncoderAssemble(enc, &webp_data);
if (!ok) {
fprintf(stderr, "Error during final animation assembly.\n");
}
End:
// free resources
WebPAnimEncoderDelete(enc);
if (ok && loop_count > 0) { // Re-mux to add loop count.
ok = SetLoopCount(loop_count, &webp_data);
}
if (ok) {
if (output != NULL) {
ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size);
if (ok) fprintf(stderr, "output file: %s ", output);
} else {
fprintf(stderr, "[no output file specified] ");
}
}
if (ok) {
fprintf(stderr, "[%d frames, %u bytes].\n",
pic_num, (unsigned int)webp_data.size);
}
WebPDataClear(&webp_data);
ExUtilDeleteCommandLineArguments(&cmd_args);
return ok ? 0 : 1;
}

View File

@ -25,7 +25,7 @@
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h" #include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -266,8 +266,6 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
JSAMPROW buffer[1]; JSAMPROW buffer[1];
JPEGReadContext ctx; JPEGReadContext ctx;
if (data == NULL || data_size == 0 || pic == NULL) return 0;
(void)keep_alpha; (void)keep_alpha;
memset(&ctx, 0, sizeof(ctx)); memset(&ctx, 0, sizeof(ctx));
ctx.data = data; ctx.data = data;
@ -304,18 +302,18 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
if (stride != (int)stride || if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error; goto End;
} }
rgb = (uint8_t*)malloc((size_t)stride * height); rgb = (uint8_t*)malloc((size_t)stride * height);
if (rgb == NULL) { if (rgb == NULL) {
goto Error; goto End;
} }
buffer[0] = (JSAMPLE*)rgb; buffer[0] = (JSAMPLE*)rgb;
while (dinfo.output_scanline < dinfo.output_height) { while (dinfo.output_scanline < dinfo.output_height) {
if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) { if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) {
goto Error; goto End;
} }
buffer[0] += stride; buffer[0] += stride;
} }

View File

@ -9,9 +9,10 @@
// //
// JPEG decode. // JPEG decode.
#ifndef WEBP_IMAGEIO_JPEGDEC_H_ #ifndef WEBP_EXAMPLES_JPEGDEC_H_
#define WEBP_IMAGEIO_JPEGDEC_H_ #define WEBP_EXAMPLES_JPEGDEC_H_
#include <stdio.h>
#include "webp/types.h" #include "webp/types.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -34,4 +35,4 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_JPEGDEC_H_ #endif // WEBP_EXAMPLES_JPEGDEC_H_

View File

@ -10,8 +10,8 @@
// Metadata types and functions. // Metadata types and functions.
// //
#ifndef WEBP_IMAGEIO_METADATA_H_ #ifndef WEBP_EXAMPLES_METADATA_H_
#define WEBP_IMAGEIO_METADATA_H_ #define WEBP_EXAMPLES_METADATA_H_
#include "webp/types.h" #include "webp/types.h"
@ -44,4 +44,4 @@ int MetadataCopy(const char* metadata, size_t metadata_len,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_METADATA_H_ #endif // WEBP_EXAMPLES_METADATA_H_

View File

@ -24,7 +24,7 @@
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h" #include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
static void PNGAPI error_function(png_structp png, png_const_charp error) { static void PNGAPI error_function(png_structp png, png_const_charp error) {
@ -185,6 +185,7 @@ static int ExtractMetadataFromPNG(png_structp png,
} }
} }
} }
return 1; return 1;
} }
@ -219,8 +220,6 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
int64_t stride; int64_t stride;
uint8_t* volatile rgb = NULL; uint8_t* volatile rgb = NULL;
if (data == NULL || data_size == 0 || pic == NULL) return 0;
context.data = data; context.data = data;
context.data_size = data_size; context.data_size = data_size;
@ -264,16 +263,6 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
} }
// Apply gamma correction if needed.
{
double image_gamma = 1 / 2.2, screen_gamma = 2.2;
int srgb_intent;
if (png_get_sRGB(png, info, &srgb_intent) ||
png_get_gAMA(png, info, &image_gamma)) {
png_set_gamma(png, screen_gamma, image_gamma);
}
}
if (!keep_alpha) { if (!keep_alpha) {
png_set_strip_alpha(png); png_set_strip_alpha(png);
has_alpha = 0; has_alpha = 0;
@ -291,10 +280,9 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
rgb = (uint8_t*)malloc((size_t)stride * height); rgb = (uint8_t*)malloc((size_t)stride * height);
if (rgb == NULL) goto Error; if (rgb == NULL) goto Error;
for (p = 0; p < num_passes; ++p) { for (p = 0; p < num_passes; ++p) {
png_bytep row = rgb;
for (y = 0; y < height; ++y) { for (y = 0; y < height; ++y) {
png_bytep row = (png_bytep)(rgb + y * stride);
png_read_rows(png, &row, NULL, 1); png_read_rows(png, &row, NULL, 1);
row += stride;
} }
} }
png_read_end(png, end_info); png_read_end(png, end_info);

View File

@ -9,8 +9,8 @@
// //
// PNG decode. // PNG decode.
#ifndef WEBP_IMAGEIO_PNGDEC_H_ #ifndef WEBP_EXAMPLES_PNGDEC_H_
#define WEBP_IMAGEIO_PNGDEC_H_ #define WEBP_EXAMPLES_PNGDEC_H_
#include "webp/types.h" #include "webp/types.h"
@ -34,4 +34,4 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_PNGDEC_H_ #endif // WEBP_EXAMPLES_PNGDEC_H_

View File

@ -15,7 +15,6 @@
#include "webp/config.h" #include "webp/config.h"
#endif #endif
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -23,7 +22,7 @@
#include <tiffio.h> #include <tiffio.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h" #include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
static const struct { static const struct {
@ -108,7 +107,7 @@ static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) {
static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) { static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
MyData* const my_data = (MyData*)opaque; MyData* const my_data = (MyData*)opaque;
if (my_data->pos + size > my_data->size) { if (my_data->pos + size > my_data->size) {
size = (tsize_t)(my_data->size - my_data->pos); size = my_data->size - my_data->pos;
} }
if (size > 0) { if (size > 0) {
memcpy(dst, my_data->data + my_data->pos, size); memcpy(dst, my_data->data + my_data->pos, size);
@ -117,59 +116,19 @@ static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
return size; return size;
} }
// Unmultiply Argb data. Taken from dsp/alpha_processing
// (we don't want to force a dependency to a libdspdec library).
#define MFIX 24 // 24bit fixed-point arithmetic
#define HALF ((1u << MFIX) >> 1)
#define KINV_255 ((1u << MFIX) / 255u)
static uint32_t Unmult(uint8_t x, uint32_t mult) {
const uint32_t v = (x * mult + HALF) >> MFIX;
return (v > 255u) ? 255u : v;
}
static WEBP_INLINE uint32_t GetScale(uint32_t a) {
return (255u << MFIX) / a;
}
static void MultARGBRow(uint8_t* ptr, int width) {
int x;
for (x = 0; x < width; ++x, ptr += 4) {
const uint32_t alpha = ptr[3];
if (alpha < 255) {
if (alpha == 0) { // alpha == 0
ptr[0] = ptr[1] = ptr[2] = 0;
} else {
const uint32_t scale = GetScale(alpha);
ptr[0] = Unmult(ptr[0], scale);
ptr[1] = Unmult(ptr[1], scale);
ptr[2] = Unmult(ptr[2], scale);
}
}
}
}
int ReadTIFF(const uint8_t* const data, size_t data_size, int ReadTIFF(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha, WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) { Metadata* const metadata) {
MyData my_data = { data, (toff_t)data_size, 0 }; MyData my_data = { data, (toff_t)data_size, 0 };
TIFF* tif; TIFF* const tif = TIFFClientOpen("Memory", "r", &my_data,
uint32_t width, height; MyRead, MyRead, MySeek, MyClose,
uint16_t samples_per_px = 0; MySize, MyMapFile, MyUnmapFile);
uint16_t extra_samples = 0; uint32 width, height;
uint16_t* extra_samples_ptr = NULL; uint32* raster;
uint32_t* raster;
int64_t alloc_size; int64_t alloc_size;
int ok = 0; int ok = 0;
tdir_t dircount; tdir_t dircount;
if (data == NULL || data_size == 0 || data_size > INT_MAX || pic == NULL) {
return 0;
}
tif = TIFFClientOpen("Memory", "r", &my_data,
MyRead, MyRead, MySeek, MyClose,
MySize, MyMapFile, MyUnmapFile);
if (tif == NULL) { if (tif == NULL) {
fprintf(stderr, "Error! Cannot parse TIFF file\n"); fprintf(stderr, "Error! Cannot parse TIFF file\n");
return 0; return 0;
@ -181,27 +140,17 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
"Only the first will be used, %d will be ignored.\n", "Only the first will be used, %d will be ignored.\n",
dircount - 1); dircount - 1);
} }
if (!TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_px)) {
fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n");
goto End;
}
if (samples_per_px < 3 || samples_per_px > 4) goto End; // not supported
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) && if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) { TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
goto End; goto End;
} }
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height, if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
sizeof(*raster))) { sizeof(*raster))) {
goto End; goto End;
} }
if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extra_samples, &extra_samples_ptr)) {
fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n");
goto End;
}
// _Tiffmalloc uses a signed type for size. // _Tiffmalloc uses a signed type for size.
alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster)); alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster));
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End; if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
@ -217,16 +166,6 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
TIFFSwabArrayOfLong(raster, width * height); TIFFSwabArrayOfLong(raster, width * height);
#endif #endif
// if we have an alpha channel, we must un-multiply from rgbA to RGBA
if (extra_samples == 1 && extra_samples_ptr != NULL &&
extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) {
uint32_t y;
uint8_t* tmp = (uint8_t*)raster;
for (y = 0; y < height; ++y) {
MultARGBRow(tmp, width);
tmp += stride;
}
}
ok = keep_alpha ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride) ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride); : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);

View File

@ -9,8 +9,8 @@
// //
// TIFF decode. // TIFF decode.
#ifndef WEBP_IMAGEIO_TIFFDEC_H_ #ifndef WEBP_EXAMPLES_TIFFDEC_H_
#define WEBP_IMAGEIO_TIFFDEC_H_ #define WEBP_EXAMPLES_TIFFDEC_H_
#include "webp/types.h" #include "webp/types.h"
@ -34,4 +34,4 @@ int ReadTIFF(const uint8_t* const data, size_t data_size,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_TIFFDEC_H_ #endif // WEBP_EXAMPLES_TIFFDEC_H_

View File

@ -40,8 +40,7 @@
#include "webp/decode.h" #include "webp/decode.h"
#include "webp/demux.h" #include "webp/demux.h"
#include "../examples/example_util.h" #include "./example_util.h"
#include "../imageio/imageio_util.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf #define snprintf _snprintf
@ -54,7 +53,6 @@ static struct {
int done; int done;
int decoding_error; int decoding_error;
int print_info; int print_info;
int only_deltas;
int use_color_profile; int use_color_profile;
int canvas_width, canvas_height; int canvas_width, canvas_height;
@ -205,11 +203,6 @@ static void decode_callback(int what) {
} }
} }
duration = curr->duration; duration = curr->duration;
// Behavior copied from Chrome, cf:
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/
// platform/graphics/DeferredImageDecoder.cpp?
// rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246
if (duration <= 10) duration = 100;
} }
if (!Decode()) { if (!Decode()) {
kParams.decoding_error = 1; kParams.decoding_error = 1;
@ -253,20 +246,17 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
} }
} }
} else if (key == 'i') { } else if (key == 'i') {
// Note: doesn't handle refresh of animation's last-frame (it's quite
// more involved to do, since you need to save the previous frame).
kParams.print_info = 1 - kParams.print_info; kParams.print_info = 1 - kParams.print_info;
// TODO(skal): handle refresh of animation's last-frame too. It's quite
// more involved though (need to save the previous frame).
if (!kParams.has_animation) ClearPreviousFrame(); if (!kParams.has_animation) ClearPreviousFrame();
glutPostRedisplay(); glutPostRedisplay();
} else if (key == 'd') {
kParams.only_deltas = 1 - kParams.only_deltas;
glutPostRedisplay();
} }
} }
static void HandleReshape(int width, int height) { static void HandleReshape(int width, int height) {
// Note: reshape doesn't preserve aspect ratio, and might // TODO(skal): should we preserve aspect ratio?
// be handling larger-than-screen pictures incorrectly. // Also: handle larger-than-screen pictures correctly.
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
@ -324,9 +314,7 @@ static void HandleDisplay(void) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
if (kParams.only_deltas) { if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
DrawCheckerBoard();
} else if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
curr->blend_method == WEBP_MUX_NO_BLEND) { curr->blend_method == WEBP_MUX_NO_BLEND) {
// glScissor() takes window coordinates (0,0 at bottom left). // glScissor() takes window coordinates (0,0 at bottom left).
int window_x, window_y; int window_x, window_y;
@ -383,23 +371,13 @@ static void HandleDisplay(void) {
} }
} }
glPopMatrix(); glPopMatrix();
#if defined(__APPLE__) || defined(_WIN32)
glFlush(); glFlush();
#else
glutSwapBuffers();
#endif
} }
static void StartDisplay(void) { static void StartDisplay(void) {
const int width = kParams.canvas_width; const int width = kParams.canvas_width;
const int height = kParams.canvas_height; const int height = kParams.canvas_height;
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
// partially displayed with animated webp + alpha.
#if defined(__APPLE__) || defined(_WIN32)
glutInitDisplayMode(GLUT_RGBA); glutInitDisplayMode(GLUT_RGBA);
#else
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
#endif
glutInitWindowSize(width, height); glutInitWindowSize(width, height);
glutCreateWindow("WebP viewer"); glutCreateWindow("WebP viewer");
glutDisplayFunc(HandleDisplay); glutDisplayFunc(HandleDisplay);
@ -436,7 +414,6 @@ static void Help(void) {
"Keyboard shortcuts:\n" "Keyboard shortcuts:\n"
" 'c' ................ toggle use of color profile\n" " 'c' ................ toggle use of color profile\n"
" 'i' ................ overlay file information\n" " 'i' ................ overlay file information\n"
" 'd' ................ disable blending & disposal (debug)\n"
" 'q' / 'Q' / ESC .... quit\n" " 'q' / 'Q' / ESC .... quit\n"
); );
} }
@ -505,8 +482,8 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
if (!ImgIoUtilReadFile(kParams.file_name, if (!ExUtilReadFile(kParams.file_name,
&kParams.data.bytes, &kParams.data.size)) { &kParams.data.bytes, &kParams.data.size)) {
goto Error; goto Error;
} }
@ -521,6 +498,10 @@ int main(int argc, char *argv[]) {
goto Error; goto Error;
} }
if (WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & FRAGMENTS_FLAG) {
fprintf(stderr, "Image fragments are not supported for now!\n");
goto Error;
}
kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH); kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH);
kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT); kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT);
if (kParams.print_info) { if (kParams.print_info) {

95
examples/webpdec.c Normal file
View File

@ -0,0 +1,95 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP decode.
#include "./webpdec.h"
#include <stdio.h>
#include <stdlib.h>
#include "webp/decode.h"
#include "webp/encode.h"
#include "./example_util.h"
#include "./metadata.h"
int ReadWebP(const uint8_t* const data, size_t data_size,
WebPPicture* const pic,
int keep_alpha, Metadata* const metadata) {
int ok = 0;
VP8StatusCode status = VP8_STATUS_OK;
WebPDecoderConfig config;
WebPDecBuffer* const output_buffer = &config.output;
WebPBitstreamFeatures* const bitstream = &config.input;
// TODO(jzern): add Exif/XMP/ICC extraction.
if (metadata != NULL) {
fprintf(stderr, "Warning: metadata extraction from WebP is unsupported.\n");
}
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
return 0;
}
status = WebPGetFeatures(data, data_size, bitstream);
if (status != VP8_STATUS_OK) {
ExUtilPrintWebPError("input data", status);
return 0;
}
{
const int has_alpha = keep_alpha && bitstream->has_alpha;
if (pic->use_argb) {
output_buffer->colorspace = has_alpha ? MODE_RGBA : MODE_RGB;
} else {
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
}
status = ExUtilDecodeWebP(data, data_size, 0, &config);
if (status == VP8_STATUS_OK) {
pic->width = output_buffer->width;
pic->height = output_buffer->height;
if (pic->use_argb) {
const uint8_t* const rgba = output_buffer->u.RGBA.rgba;
const int stride = output_buffer->u.RGBA.stride;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgba, stride)
: WebPPictureImportRGB(pic, rgba, stride);
} else {
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
ok = WebPPictureAlloc(pic);
if (!ok) {
status = VP8_STATUS_OUT_OF_MEMORY;
} else {
const WebPYUVABuffer* const yuva = &output_buffer->u.YUVA;
const int uv_width = (pic->width + 1) >> 1;
const int uv_height = (pic->height + 1) >> 1;
ExUtilCopyPlane(yuva->y, yuva->y_stride,
pic->y, pic->y_stride, pic->width, pic->height);
ExUtilCopyPlane(yuva->u, yuva->u_stride,
pic->u, pic->uv_stride, uv_width, uv_height);
ExUtilCopyPlane(yuva->v, yuva->v_stride,
pic->v, pic->uv_stride, uv_width, uv_height);
if (has_alpha) {
ExUtilCopyPlane(yuva->a, yuva->a_stride,
pic->a, pic->a_stride, pic->width, pic->height);
}
}
}
}
}
if (status != VP8_STATUS_OK) {
ExUtilPrintWebPError("input data", status);
}
WebPFreeDecBuffer(output_buffer);
return ok;
}
// -----------------------------------------------------------------------------

37
examples/webpdec.h Normal file
View File

@ -0,0 +1,37 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP decode.
#ifndef WEBP_EXAMPLES_WEBPDEC_H_
#define WEBP_EXAMPLES_WEBPDEC_H_
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
// Reads a WebP from 'in_file', returning the decoded output in 'pic'.
// Output is RGBA or YUVA, depending on pic->use_argb value.
// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
// Returns true on success.
int ReadWebP(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_WEBPDEC_H_

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
Extract relevant data from WebP container file: Extract relevant data from WebP container file:
webpmux -get frgm n in.webp -o out_fragment.webp
webpmux -get frame n in.webp -o out_frame.webp webpmux -get frame n in.webp -o out_frame.webp
webpmux -get icc in.webp -o image_profile.icc webpmux -get icc in.webp -o image_profile.icc
webpmux -get exif in.webp -o image_metadata.exif webpmux -get exif in.webp -o image_metadata.exif
@ -38,16 +39,10 @@
webpmux -strip exif in.webp -o out.webp webpmux -strip exif in.webp -o out.webp
webpmux -strip xmp in.webp -o out.webp webpmux -strip xmp in.webp -o out.webp
Change duration of frame intervals:
webpmux -duration 150 in.webp -o out.webp
webpmux -duration 33,2 in.webp -o out.webp
webpmux -duration 200,10,0 -duration 150,6,50 in.webp -o out.webp
Misc: Misc:
webpmux -info in.webp webpmux -info in.webp
webpmux [ -h | -help ] webpmux [ -h | -help ]
webpmux -version webpmux -version
webpmux argument_file_name
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -60,8 +55,7 @@
#include <string.h> #include <string.h>
#include "webp/decode.h" #include "webp/decode.h"
#include "webp/mux.h" #include "webp/mux.h"
#include "../examples/example_util.h" #include "./example_util.h"
#include "../imageio/imageio_util.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Config object to parse command-line arguments. // Config object to parse command-line arguments.
@ -72,8 +66,7 @@ typedef enum {
ACTION_SET, ACTION_SET,
ACTION_STRIP, ACTION_STRIP,
ACTION_INFO, ACTION_INFO,
ACTION_HELP, ACTION_HELP
ACTION_DURATION
} ActionType; } ActionType;
typedef enum { typedef enum {
@ -95,40 +88,42 @@ typedef enum {
FEATURE_XMP, FEATURE_XMP,
FEATURE_ICCP, FEATURE_ICCP,
FEATURE_ANMF, FEATURE_ANMF,
FEATURE_DURATION, FEATURE_FRGM,
LAST_FEATURE LAST_FEATURE
} FeatureType; } FeatureType;
static const char* const kFourccList[LAST_FEATURE] = { static const char* const kFourccList[LAST_FEATURE] = {
NULL, "EXIF", "XMP ", "ICCP", "ANMF" NULL, "EXIF", "XMP ", "ICCP", "ANMF", "FRGM"
}; };
static const char* const kDescriptions[LAST_FEATURE] = { static const char* const kDescriptions[LAST_FEATURE] = {
NULL, "EXIF metadata", "XMP metadata", "ICC profile", NULL, "EXIF metadata", "XMP metadata", "ICC profile",
"Animation frame" "Animation frame", "Image fragment"
}; };
typedef struct { typedef struct {
CommandLineArguments cmd_args_;
ActionType action_type_;
const char* input_;
const char* output_;
FeatureType type_; FeatureType type_;
FeatureArg* args_; FeatureArg* args_;
int arg_count_; int arg_count_;
} Config; } Feature;
typedef struct {
ActionType action_type_;
const char* input_;
const char* output_;
Feature feature_;
} WebPMuxConfig;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helper functions. // Helper functions.
static int CountOccurrences(const CommandLineArguments* const args, static int CountOccurrences(const char* arglist[], int list_length,
const char* const arg) { const char* arg) {
int i; int i;
int num_occurences = 0; int num_occurences = 0;
for (i = 0; i < args->argc_; ++i) { for (i = 0; i < list_length; ++i) {
if (!strcmp(args->argv_[i], arg)) { if (!strcmp(arglist[i], arg)) {
++num_occurences; ++num_occurences;
} }
} }
@ -187,6 +182,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
printf("Canvas size: %d x %d\n", width, height); printf("Canvas size: %d x %d\n", width, height);
err = WebPMuxGetFeatures(mux, &flag); err = WebPMuxGetFeatures(mux, &flag);
if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
RETURN_IF_ERROR("Failed to retrieve features\n"); RETURN_IF_ERROR("Failed to retrieve features\n");
if (flag == 0) { if (flag == 0) {
@ -197,22 +193,26 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
// Print the features present. // Print the features present.
printf("Features present:"); printf("Features present:");
if (flag & ANIMATION_FLAG) printf(" animation"); if (flag & ANIMATION_FLAG) printf(" animation");
if (flag & FRAGMENTS_FLAG) printf(" image fragments");
if (flag & ICCP_FLAG) printf(" ICC profile"); if (flag & ICCP_FLAG) printf(" ICC profile");
if (flag & EXIF_FLAG) printf(" EXIF metadata"); if (flag & EXIF_FLAG) printf(" EXIF metadata");
if (flag & XMP_FLAG) printf(" XMP metadata"); if (flag & XMP_FLAG) printf(" XMP metadata");
if (flag & ALPHA_FLAG) printf(" transparency"); if (flag & ALPHA_FLAG) printf(" transparency");
printf("\n"); printf("\n");
if (flag & ANIMATION_FLAG) { if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) {
const WebPChunkId id = WEBP_CHUNK_ANMF; const int is_anim = !!(flag & ANIMATION_FLAG);
const char* const type_str = "frame"; const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
const char* const type_str = is_anim ? "frame" : "fragment";
int nFrames; int nFrames;
WebPMuxAnimParams params; if (is_anim) {
err = WebPMuxGetAnimationParams(mux, &params); WebPMuxAnimParams params;
assert(err == WEBP_MUX_OK); err = WebPMuxGetAnimationParams(mux, &params);
printf("Background color : 0x%.8X Loop Count : %d\n", assert(err == WEBP_MUX_OK);
params.bgcolor, params.loop_count); printf("Background color : 0x%.8X Loop Count : %d\n",
params.bgcolor, params.loop_count);
}
err = WebPMuxNumChunks(mux, id, &nFrames); err = WebPMuxNumChunks(mux, id, &nFrames);
assert(err == WEBP_MUX_OK); assert(err == WEBP_MUX_OK);
@ -221,8 +221,8 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
if (nFrames > 0) { if (nFrames > 0) {
int i; int i;
printf("No.: width height alpha x_offset y_offset "); printf("No.: width height alpha x_offset y_offset ");
printf("duration dispose blend "); if (is_anim) printf("duration dispose blend ");
printf("image_size compression\n"); printf("image_size\n");
for (i = 1; i <= nFrames; i++) { for (i = 1; i <= nFrames; i++) {
WebPMuxFrameInfo frame; WebPMuxFrameInfo frame;
err = WebPMuxGetFrame(mux, i, &frame); err = WebPMuxGetFrame(mux, i, &frame);
@ -235,7 +235,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
printf("%3d: %5d %5d %5s %8d %8d ", i, features.width, printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
features.height, features.has_alpha ? "yes" : "no", features.height, features.has_alpha ? "yes" : "no",
frame.x_offset, frame.y_offset); frame.x_offset, frame.y_offset);
{ if (is_anim) {
const char* const dispose = const char* const dispose =
(frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none" (frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
: "background"; : "background";
@ -243,10 +243,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
(frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no"; (frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no";
printf("%8d %10s %5s ", frame.duration, dispose, blend); printf("%8d %10s %5s ", frame.duration, dispose, blend);
} }
printf("%10d %11s\n", (int)frame.bitstream.size, printf("%10d\n", (int)frame.bitstream.size);
(features.format == 1) ? "lossy" :
(features.format == 2) ? "lossless" :
"undefined");
} }
WebPDataClear(&frame.bitstream); WebPDataClear(&frame.bitstream);
RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i); RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
@ -275,7 +272,7 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
printf("Size of the XMP metadata: %d\n", (int)xmp.size); printf("Size of the XMP metadata: %d\n", (int)xmp.size);
} }
if ((flag & ALPHA_FLAG) && !(flag & ANIMATION_FLAG)) { if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) {
WebPMuxFrameInfo image; WebPMuxFrameInfo image;
err = WebPMuxGetFrame(mux, 1, &image); err = WebPMuxGetFrame(mux, 1, &image);
if (err == WEBP_MUX_OK) { if (err == WEBP_MUX_OK) {
@ -291,8 +288,6 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
static void PrintHelp(void) { static void PrintHelp(void) {
printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n"); printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n"); printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
printf(" webpmux -duration DURATION_OPTIONS [-duration ...]\n");
printf(" INPUT -o OUTPUT\n");
printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n"); printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]" printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]"
"\n"); "\n");
@ -300,7 +295,6 @@ static void PrintHelp(void) {
printf(" webpmux -info INPUT\n"); printf(" webpmux -info INPUT\n");
printf(" webpmux [-h|-help]\n"); printf(" webpmux [-h|-help]\n");
printf(" webpmux -version\n"); printf(" webpmux -version\n");
printf(" webpmux argument_file_name\n");
printf("\n"); printf("\n");
printf("GET_OPTIONS:\n"); printf("GET_OPTIONS:\n");
@ -320,18 +314,6 @@ static void PrintHelp(void) {
printf(" 'file.exif' contains the EXIF metadata to be set\n"); printf(" 'file.exif' contains the EXIF metadata to be set\n");
printf(" 'file.xmp' contains the XMP metadata to be set\n"); printf(" 'file.xmp' contains the XMP metadata to be set\n");
printf("\n");
printf("DURATION_OPTIONS:\n");
printf(" Set duration of selected frames:\n");
printf(" duration set duration for each frames\n");
printf(" duration,frame set duration of a particular frame\n");
printf(" duration,start,end set duration of frames in the\n");
printf(" interval [start,end])\n");
printf(" where: 'duration' is the duration in milliseconds\n");
printf(" 'start' is the start frame index\n");
printf(" 'end' is the inclusive end frame index\n");
printf(" The special 'end' value '0' means: last frame.\n");
printf("\n"); printf("\n");
printf("STRIP_OPTIONS:\n"); printf("STRIP_OPTIONS:\n");
printf(" Strip color profile/metadata:\n"); printf(" Strip color profile/metadata:\n");
@ -369,10 +351,6 @@ static void PrintHelp(void) {
printf("\nNote: The nature of EXIF, XMP and ICC data is not checked"); printf("\nNote: The nature of EXIF, XMP and ICC data is not checked");
printf(" and is assumed to be\nvalid.\n"); printf(" and is assumed to be\nvalid.\n");
printf("\nNote: if a single file name is passed as the argument, the "
"arguments will be\n");
printf("tokenized from this file. The file name must not start with "
"the character '-'.\n");
} }
static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) { static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
@ -383,12 +361,22 @@ static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) {
} }
} }
static int ReadFileToWebPData(const char* const filename,
WebPData* const webp_data) {
const uint8_t* data;
size_t size;
if (!ExUtilReadFile(filename, &data, &size)) return 0;
webp_data->bytes = data;
webp_data->size = size;
return 1;
}
static int CreateMux(const char* const filename, WebPMux** mux) { static int CreateMux(const char* const filename, WebPMux** mux) {
WebPData bitstream; WebPData bitstream;
assert(mux != NULL); assert(mux != NULL);
if (!ExUtilReadFileToWebPData(filename, &bitstream)) return 0; if (!ReadFileToWebPData(filename, &bitstream)) return 0;
*mux = WebPMuxCreate(&bitstream, 1); *mux = WebPMuxCreate(&bitstream, 1);
WebPDataClear(&bitstream); free((void*)bitstream.bytes);
if (*mux != NULL) return 1; if (*mux != NULL) return 1;
fprintf(stderr, "Failed to create mux object from file %s.\n", filename); fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
return 0; return 0;
@ -397,7 +385,7 @@ static int CreateMux(const char* const filename, WebPMux** mux) {
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 = strcmp(filename, "-") ? fopen(filename, "wb")
: ImgIoUtilSetBinaryMode(stdout); : ExUtilSetBinaryMode(stdout);
if (fout == NULL) { if (fout == NULL) {
fprintf(stderr, "Error opening output WebP file %s!\n", filename); fprintf(stderr, "Error opening output WebP file %s!\n", filename);
return 0; return 0;
@ -426,45 +414,6 @@ static int WriteWebP(WebPMux* const mux, const char* filename) {
return ok; return ok;
} }
static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
WebPMux* new_mux = WebPMuxNew();
WebPMuxAnimParams p;
WebPMuxError err;
int i;
int ok = 1;
if (new_mux == NULL) return NULL;
err = WebPMuxGetAnimationParams(mux, &p);
if (err == WEBP_MUX_OK) {
err = WebPMuxSetAnimationParams(new_mux, &p);
if (err != WEBP_MUX_OK) {
ERROR_GOTO2("Error (%s) handling animation params.\n",
ErrorString(err), End);
}
} else {
/* it might not be an animation. Just keep moving. */
}
for (i = 1; i <= 3; ++i) {
WebPData metadata;
err = WebPMuxGetChunk(mux, kFourccList[i], &metadata);
if (err == WEBP_MUX_OK && metadata.size > 0) {
err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
if (err != WEBP_MUX_OK) {
ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
}
}
}
End:
if (!ok) {
WebPMuxDelete(new_mux);
new_mux = NULL;
}
return new_mux;
}
static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) { static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
int dispose_method, dummy; int dispose_method, dummy;
char plus_minus, blend_method; char plus_minus, blend_method;
@ -500,6 +449,13 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
return 1; return 1;
} }
static int ParseFragmentArgs(const char* args, WebPMuxFrameInfo* const info) {
const int ok =
(sscanf(args, "+%d+%d", &info->x_offset, &info->y_offset) == 2);
if (ok) WarnAboutOddOffset(info);
return ok;
}
static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) { static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
uint32_t a, r, g, b; uint32_t a, r, g, b;
if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0; if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0;
@ -511,10 +467,9 @@ static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Clean-up. // Clean-up.
static void DeleteConfig(Config* const config) { static void DeleteConfig(WebPMuxConfig* config) {
if (config != NULL) { if (config != NULL) {
free(config->args_); free(config->feature_.args_);
ExUtilDeleteCommandLineArguments(&config->cmd_args_);
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
} }
} }
@ -526,39 +481,39 @@ static void DeleteConfig(Config* const config) {
// Returns 1 on valid, 0 otherwise. // Returns 1 on valid, 0 otherwise.
// Also fills up num_feature_args to be number of feature arguments given. // Also fills up num_feature_args to be number of feature arguments given.
// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5). // (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
static int ValidateCommandLine(const CommandLineArguments* const cmd_args, static int ValidateCommandLine(int argc, const char* argv[],
int* num_feature_args) { int* num_feature_args) {
int num_frame_args; int num_frame_args;
int num_frgm_args;
int num_loop_args; int num_loop_args;
int num_bgcolor_args; int num_bgcolor_args;
int num_durations_args;
int ok = 1; int ok = 1;
assert(num_feature_args != NULL); assert(num_feature_args != NULL);
*num_feature_args = 0; *num_feature_args = 0;
// Simple checks. // Simple checks.
if (CountOccurrences(cmd_args, "-get") > 1) { if (CountOccurrences(argv, argc, "-get") > 1) {
ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-set") > 1) { if (CountOccurrences(argv, argc, "-set") > 1) {
ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-strip") > 1) { if (CountOccurrences(argv, argc, "-strip") > 1) {
ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-info") > 1) { if (CountOccurrences(argv, argc, "-info") > 1) {
ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
} }
if (CountOccurrences(cmd_args, "-o") > 1) { if (CountOccurrences(argv, argc, "-o") > 1) {
ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
} }
// Compound checks. // Compound checks.
num_frame_args = CountOccurrences(cmd_args, "-frame"); num_frame_args = CountOccurrences(argv, argc, "-frame");
num_loop_args = CountOccurrences(cmd_args, "-loop"); num_frgm_args = CountOccurrences(argv, argc, "-frgm");
num_bgcolor_args = CountOccurrences(cmd_args, "-bgcolor"); num_loop_args = CountOccurrences(argv, argc, "-loop");
num_durations_args = CountOccurrences(cmd_args, "-duration"); num_bgcolor_args = CountOccurrences(argv, argc, "-bgcolor");
if (num_loop_args > 1) { if (num_loop_args > 1) {
ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate); ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
@ -571,20 +526,22 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
ERROR_GOTO1("ERROR: Loop count and background color are relevant only in " ERROR_GOTO1("ERROR: Loop count and background color are relevant only in "
"case of animation.\n", ErrValidate); "case of animation.\n", ErrValidate);
} }
if (num_durations_args > 0 && num_frame_args != 0) { if (num_frame_args > 0 && num_frgm_args > 0) {
ERROR_GOTO1("ERROR: Can not combine -duration and -frame commands.\n", ERROR_GOTO1("ERROR: Only one of frames & fragments can be specified at a "
ErrValidate); "time.\n", ErrValidate);
} }
assert(ok == 1); assert(ok == 1);
if (num_durations_args > 0) { if (num_frame_args == 0 && num_frgm_args == 0) {
*num_feature_args = num_durations_args;
} else if (num_frame_args == 0) {
// Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action). // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
*num_feature_args = 1; *num_feature_args = 1;
} else { } else {
// Multiple arguments ('set' action for animation) // Multiple arguments ('set' action for animation or fragmented image).
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args; if (num_frame_args > 0) {
*num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args;
} else {
*num_feature_args = num_frgm_args;
}
} }
ErrValidate: ErrValidate:
@ -593,7 +550,7 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION) #define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE) #define FEATURETYPE_IS_NIL (feature->type_ == NIL_FEATURE)
#define CHECK_NUM_ARGS_LESS(NUM, LABEL) \ #define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
if (argc < i + (NUM)) { \ if (argc < i + (NUM)) { \
@ -609,15 +566,15 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
// 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.
static int ParseCommandLine(Config* config) { static int ParseCommandLine(int argc, const char* argv[],
WebPMuxConfig* config) {
int i = 0; int i = 0;
int feature_arg_index = 0; int feature_arg_index = 0;
int ok = 1; int ok = 1;
int argc = config->cmd_args_.argc_;
const char* const* argv = config->cmd_args_.argv_;
while (i < argc) { while (i < argc) {
FeatureArg* const arg = &config->args_[feature_arg_index]; Feature* const feature = &config->feature_;
FeatureArg* const arg = &feature->args_[feature_arg_index];
if (argv[i][0] == '-') { // One of the action types or output. if (argv[i][0] == '-') { // One of the action types or output.
if (!strcmp(argv[i], "-set")) { if (!strcmp(argv[i], "-set")) {
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
@ -626,21 +583,6 @@ static int ParseCommandLine(Config* config) {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
++i; ++i;
} else if (!strcmp(argv[i], "-duration")) {
CHECK_NUM_ARGS_LESS(2, ErrParse);
if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) {
config->action_type_ = ACTION_DURATION;
} else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
}
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) {
config->type_ = FEATURE_DURATION;
} else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
}
arg->params_ = argv[i + 1];
++feature_arg_index;
i += 2;
} else if (!strcmp(argv[i], "-get")) { } else if (!strcmp(argv[i], "-get")) {
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
config->action_type_ = ACTION_GET; config->action_type_ = ACTION_GET;
@ -651,7 +593,7 @@ static int ParseCommandLine(Config* config) {
} else if (!strcmp(argv[i], "-strip")) { } else if (!strcmp(argv[i], "-strip")) {
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
config->action_type_ = ACTION_STRIP; config->action_type_ = ACTION_STRIP;
config->arg_count_ = 0; feature->arg_count_ = 0;
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
@ -663,8 +605,8 @@ static int ParseCommandLine(Config* config) {
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF; feature->type_ = FEATURE_ANMF;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -680,8 +622,8 @@ static int ParseCommandLine(Config* config) {
} else { } else {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} }
if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_ANMF) {
config->type_ = FEATURE_ANMF; feature->type_ = FEATURE_ANMF;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -700,7 +642,7 @@ static int ParseCommandLine(Config* config) {
ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
} else { } else {
config->action_type_ = ACTION_INFO; config->action_type_ = ACTION_INFO;
config->arg_count_ = 0; feature->arg_count_ = 0;
config->input_ = argv[i + 1]; config->input_ = argv[i + 1];
} }
i += 2; i += 2;
@ -736,7 +678,7 @@ static int ParseCommandLine(Config* config) {
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") || if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
!strcmp(argv[i], "xmp")) { !strcmp(argv[i], "xmp")) {
if (FEATURETYPE_IS_NIL) { if (FEATURETYPE_IS_NIL) {
config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP : feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
(!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP; (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
@ -752,7 +694,8 @@ static int ParseCommandLine(Config* config) {
} else if (!strcmp(argv[i], "frame") && } else if (!strcmp(argv[i], "frame") &&
(config->action_type_ == ACTION_GET)) { (config->action_type_ == ACTION_GET)) {
CHECK_NUM_ARGS_LESS(2, ErrParse); CHECK_NUM_ARGS_LESS(2, ErrParse);
config->type_ = FEATURE_ANMF; feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_ANMF :
FEATURE_FRGM;
arg->params_ = argv[i + 1]; arg->params_ = argv[i + 1];
++feature_arg_index; ++feature_arg_index;
i += 2; i += 2;
@ -772,8 +715,9 @@ static int ParseCommandLine(Config* config) {
} }
// Additional checks after config is filled. // Additional checks after config is filled.
static int ValidateConfig(Config* const config) { static int ValidateConfig(WebPMuxConfig* config) {
int ok = 1; int ok = 1;
Feature* const feature = &config->feature_;
// Action. // Action.
if (ACTION_IS_NIL) { if (ACTION_IS_NIL) {
@ -789,7 +733,8 @@ static int ValidateConfig(Config* const config) {
if (config->input_ == NULL) { if (config->input_ == NULL) {
if (config->action_type_ != ACTION_SET) { if (config->action_type_ != ACTION_SET) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} else if (config->type_ != FEATURE_ANMF) { } else if (feature->type_ != FEATURE_ANMF &&
feature->type_ != FEATURE_FRGM) {
ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
} }
} }
@ -805,28 +750,27 @@ 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) { WebPMuxConfig* config) {
int num_feature_args = 0; int num_feature_args = 0;
int ok; int ok = 1;
assert(config != NULL);
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args_);
if (!ok) return 0;
// Validate command-line arguments. // Validate command-line arguments.
if (!ValidateCommandLine(&config->cmd_args_, &num_feature_args)) { if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
} }
config->arg_count_ = num_feature_args; config->feature_.arg_count_ = num_feature_args;
config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_)); config->feature_.args_ =
if (config->args_ == NULL) { (FeatureArg*)calloc(num_feature_args, sizeof(*config->feature_.args_));
if (config->feature_.args_ == NULL) {
ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1); ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
} }
// Parse command-line. // Parse command-line.
if (!ParseCommandLine(config) || !ValidateConfig(config)) { if (!ParseCommandLine(argc, argv, config) || !ValidateConfig(config)) {
ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
} }
@ -842,17 +786,18 @@ static int InitializeConfig(int argc, const char* argv[],
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Processing. // Processing.
static int GetFrame(const WebPMux* mux, const Config* config) { static int GetFrameFragment(const WebPMux* mux,
const WebPMuxConfig* config, int is_frame) {
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
WebPMux* mux_single = NULL; WebPMux* mux_single = NULL;
int num = 0; int num = 0;
int ok = 1; int ok = 1;
int parse_error = 0; int parse_error = 0;
const WebPChunkId id = WEBP_CHUNK_ANMF; const WebPChunkId id = is_frame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
WebPMuxFrameInfo info; WebPMuxFrameInfo info;
WebPDataInit(&info.bitstream); WebPDataInit(&info.bitstream);
num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error); num = ExUtilGetInt(config->feature_.args_[0].params_, 10, &parse_error);
if (num < 0) { if (num < 0) {
ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet);
} }
@ -886,28 +831,31 @@ static int GetFrame(const WebPMux* mux, const Config* config) {
} }
// Read and process config. // Read and process config.
static int Process(const Config* config) { static int Process(const WebPMuxConfig* config) {
WebPMux* mux = NULL; WebPMux* mux = NULL;
WebPData chunk; WebPData chunk;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int ok = 1; int ok = 1;
const Feature* const feature = &config->feature_;
switch (config->action_type_) { switch (config->action_type_) {
case ACTION_GET: { case ACTION_GET: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
switch (config->type_) { switch (feature->type_) {
case FEATURE_ANMF: case FEATURE_ANMF:
ok = GetFrame(mux, config); case FEATURE_FRGM:
ok = GetFrameFragment(mux, config,
(feature->type_ == FEATURE_ANMF) ? 1 : 0);
break; break;
case FEATURE_ICCP: case FEATURE_ICCP:
case FEATURE_EXIF: case FEATURE_EXIF:
case FEATURE_XMP: case FEATURE_XMP:
err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk); err = WebPMuxGetChunk(mux, kFourccList[feature->type_], &chunk);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not get the %s.\n", ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
ok = WriteData(config->output_, &chunk); ok = WriteData(config->output_, &chunk);
break; break;
@ -919,7 +867,7 @@ static int Process(const Config* config) {
break; break;
} }
case ACTION_SET: { case ACTION_SET: {
switch (config->type_) { switch (feature->type_) {
case FEATURE_ANMF: { case FEATURE_ANMF: {
int i; int i;
WebPMuxAnimParams params = { 0xFFFFFFFF, 0 }; WebPMuxAnimParams params = { 0xFFFFFFFF, 0 };
@ -928,11 +876,11 @@ static int Process(const Config* config) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
} }
for (i = 0; i < config->arg_count_; ++i) { for (i = 0; i < feature->arg_count_; ++i) {
switch (config->args_[i].subtype_) { switch (feature->args_[i].subtype_) {
case SUBTYPE_BGCOLOR: { case SUBTYPE_BGCOLOR: {
uint32_t bgcolor; uint32_t bgcolor;
ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor); ok = ParseBgcolorArgs(feature->args_[i].params_, &bgcolor);
if (!ok) { if (!ok) {
ERROR_GOTO1("ERROR: Could not parse the background color \n", ERROR_GOTO1("ERROR: Could not parse the background color \n",
Err2); Err2);
@ -943,7 +891,7 @@ static int Process(const Config* config) {
case SUBTYPE_LOOP: { case SUBTYPE_LOOP: {
int parse_error = 0; int parse_error = 0;
const int loop_count = const int loop_count =
ExUtilGetInt(config->args_[i].params_, 10, &parse_error); ExUtilGetInt(feature->args_[i].params_, 10, &parse_error);
if (loop_count < 0 || loop_count > 65535) { if (loop_count < 0 || loop_count > 65535) {
// Note: This is only a 'necessary' condition for loop_count // Note: This is only a 'necessary' condition for loop_count
// to be valid. The 'sufficient' conditioned in checked in // to be valid. The 'sufficient' conditioned in checked in
@ -959,10 +907,10 @@ static int Process(const Config* config) {
case SUBTYPE_ANMF: { case SUBTYPE_ANMF: {
WebPMuxFrameInfo frame; WebPMuxFrameInfo frame;
frame.id = WEBP_CHUNK_ANMF; frame.id = WEBP_CHUNK_ANMF;
ok = ExUtilReadFileToWebPData(config->args_[i].filename_, ok = ReadFileToWebPData(feature->args_[i].filename_,
&frame.bitstream); &frame.bitstream);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ParseFrameArgs(config->args_[i].params_, &frame); ok = ParseFrameArgs(feature->args_[i].params_, &frame);
if (!ok) { if (!ok) {
WebPDataClear(&frame.bitstream); WebPDataClear(&frame.bitstream);
ERROR_GOTO1("ERROR: Could not parse frame properties.\n", ERROR_GOTO1("ERROR: Could not parse frame properties.\n",
@ -990,18 +938,47 @@ static int Process(const Config* config) {
break; break;
} }
case FEATURE_FRGM: {
int i;
mux = WebPMuxNew();
if (mux == NULL) {
ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
}
for (i = 0; i < feature->arg_count_; ++i) {
WebPMuxFrameInfo frgm;
frgm.id = WEBP_CHUNK_FRGM;
ok = ReadFileToWebPData(feature->args_[i].filename_,
&frgm.bitstream);
if (!ok) goto Err2;
ok = ParseFragmentArgs(feature->args_[i].params_, &frgm);
if (!ok) {
WebPDataClear(&frgm.bitstream);
ERROR_GOTO1("ERROR: Could not parse fragment properties.\n",
Err2);
}
err = WebPMuxPushFrame(mux, &frgm, 1);
WebPDataClear(&frgm.bitstream);
if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not add a fragment at index %d.\n",
ErrorString(err), i, Err2);
}
}
break;
}
case FEATURE_ICCP: case FEATURE_ICCP:
case FEATURE_EXIF: case FEATURE_EXIF:
case FEATURE_XMP: { case FEATURE_XMP: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ExUtilReadFileToWebPData(config->args_[0].filename_, &chunk); ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk);
if (!ok) goto Err2; if (!ok) goto Err2;
err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1); err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1);
free((void*)chunk.bytes); free((void*)chunk.bytes);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not set the %s.\n", ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
break; break;
} }
@ -1013,98 +990,15 @@ static int Process(const Config* config) {
ok = WriteWebP(mux, config->output_); ok = WriteWebP(mux, config->output_);
break; break;
} }
case ACTION_DURATION: {
int num_frames;
ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2;
err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames);
ok = (err == WEBP_MUX_OK);
if (!ok) {
ERROR_GOTO1("ERROR: can not parse the number of frames.\n", Err2);
}
if (num_frames == 0) {
fprintf(stderr, "Doesn't look like the source is animated. "
"Skipping duration setting.\n");
ok = WriteWebP(mux, config->output_);
if (!ok) goto Err2;
} else {
int i;
int* durations = NULL;
WebPMux* new_mux = DuplicateMuxHeader(mux);
if (new_mux == NULL) goto Err2;
durations = (int*)malloc((size_t)num_frames * sizeof(*durations));
if (durations == NULL) goto Err2;
for (i = 0; i < num_frames; ++i) durations[i] = -1;
// Parse intervals to process.
for (i = 0; i < config->arg_count_; ++i) {
int k;
int args[3];
int duration, start, end;
const int nb_args = ExUtilGetInts(config->args_[i].params_,
10, 3, args);
ok = (nb_args >= 1);
if (!ok) goto Err3;
duration = args[0];
if (duration < 0) {
ERROR_GOTO1("ERROR: duration must be strictly positive.\n", Err3);
}
if (nb_args == 1) { // only duration is present -> use full interval
start = 1;
end = num_frames;
} else {
start = args[1];
if (start <= 0) {
start = 1;
} else if (start > num_frames) {
start = num_frames;
}
end = (nb_args >= 3) ? args[2] : start;
if (end == 0 || end > num_frames) end = num_frames;
}
for (k = start; k <= end; ++k) {
assert(k >= 1 && k <= num_frames);
durations[k - 1] = duration;
}
}
// Apply non-negative durations to their destination frames.
for (i = 1; i <= num_frames; ++i) {
WebPMuxFrameInfo frame;
err = WebPMuxGetFrame(mux, i, &frame);
if (err != WEBP_MUX_OK || frame.id != WEBP_CHUNK_ANMF) {
ERROR_GOTO2("ERROR: can not retrieve frame #%d.\n", i, Err3);
}
if (durations[i - 1] >= 0) frame.duration = durations[i - 1];
err = WebPMuxPushFrame(new_mux, &frame, 1);
if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR: error push frame data #%d\n", i, Err3);
}
WebPDataClear(&frame.bitstream);
}
WebPMuxDelete(mux);
ok = WriteWebP(new_mux, config->output_);
mux = new_mux; // transfer for the WebPMuxDelete() call
new_mux = NULL;
Err3:
free(durations);
WebPMuxDelete(new_mux);
if (!ok) goto Err2;
}
break;
}
case ACTION_STRIP: { case ACTION_STRIP: {
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF || if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF ||
config->type_ == FEATURE_XMP) { feature->type_ == FEATURE_XMP) {
err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]); err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n", ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
ErrorString(err), kDescriptions[config->type_], Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
} else { } else {
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2); ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
@ -1134,7 +1028,7 @@ static int Process(const Config* config) {
// Main. // Main.
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
Config config; WebPMuxConfig config;
int ok = InitializeConfig(argc - 1, argv + 1, &config); int ok = InitializeConfig(argc - 1, argv + 1, &config);
if (ok) { if (ok) {
ok = Process(&config); ok = Process(&config);

View File

@ -33,7 +33,7 @@
#include <wincodec.h> #include <wincodec.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h" #include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
#define IFS(fn) \ #define IFS(fn) \
@ -88,7 +88,7 @@ static HRESULT OpenInputStream(const char* filename, IStream** stream) {
if (!strcmp(filename, "-")) { if (!strcmp(filename, "-")) {
const uint8_t* data = NULL; const uint8_t* data = NULL;
size_t data_size = 0; size_t data_size = 0;
const int ok = ImgIoUtilReadFile(filename, &data, &data_size); const int ok = ExUtilReadFile(filename, &data, &data_size);
if (ok) { if (ok) {
HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size); HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
if (image != NULL) { if (image != NULL) {
@ -276,8 +276,6 @@ int ReadPictureWithWIC(const char* const filename,
int has_alpha = 0; int has_alpha = 0;
int64_t stride; int64_t stride;
if (filename == NULL || pic == NULL) return 0;
IFS(CoInitialize(NULL)); IFS(CoInitialize(NULL));
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,

View File

@ -9,8 +9,8 @@
// //
// Windows Imaging Component (WIC) decode. // Windows Imaging Component (WIC) decode.
#ifndef WEBP_IMAGEIO_WICDEC_H_ #ifndef WEBP_EXAMPLES_WICDEC_H_
#define WEBP_IMAGEIO_WICDEC_H_ #define WEBP_EXAMPLES_WICDEC_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -31,4 +31,4 @@ int ReadPictureWithWIC(const char* const filename,
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_WICDEC_H_ #endif // WEBP_EXAMPLES_WICDEC_H_

View File

@ -1,44 +0,0 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src
noinst_LTLIBRARIES = libwebpextras.la
noinst_HEADERS =
noinst_HEADERS += ../src/webp/types.h
libwebpextras_la_SOURCES =
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
libwebpextras_la_LDFLAGS = -lm
libwebpextras_la_LIBADD = ../src/libwebp.la
noinst_PROGRAMS =
noinst_PROGRAMS += webp_quality
if WANT_DEMUX
noinst_PROGRAMS += get_disto
endif
if BUILD_VWEBP_SDL
noinst_PROGRAMS += vwebp_sdl
endif
get_disto_SOURCES = get_disto.c
get_disto_CPPFLAGS = $(AM_CPPFLAGS)
get_disto_LDADD =
get_disto_LDADD += ../imageio/libimageio_util.la
get_disto_LDADD += ../imageio/libimagedec.la
get_disto_LDADD += ../src/libwebp.la
get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS)
webp_quality_SOURCES = webp_quality.c
webp_quality_CPPFLAGS = $(AM_CPPFLAGS)
webp_quality_LDADD =
webp_quality_LDADD += ../imageio/libimageio_util.la
webp_quality_LDADD += libwebpextras.la
webp_quality_LDADD += ../src/libwebp.la
vwebp_sdl_SOURCES = vwebp_sdl.c webp_to_sdl.c webp_to_sdl.h
vwebp_sdl_CPPFLAGS = $(AM_CPPFLAGS) $(SDL_INCLUDES)
vwebp_sdl_LDADD =
vwebp_sdl_LDADD += ../imageio/libimageio_util.la
vwebp_sdl_LDADD += ../src/libwebp.la
vwebp_sdl_LDADD += $(SDL_LIBS)

View File

@ -1,70 +0,0 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
#ifndef WEBP_EXTRAS_EXTRAS_H_
#define WEBP_EXTRAS_EXTRAS_H_
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "webp/encode.h"
#define WEBP_EXTRAS_ABI_VERSION 0x0001 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------
// Returns the version number of the extras library, packed in hexadecimal using
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
WEBP_EXTERN int WebPGetExtrasVersion(void);
//------------------------------------------------------------------------------
// Ad-hoc colorspace importers.
// Import luma sample (gray scale image) into 'picture'. The 'picture'
// width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportGray(const uint8_t* gray, WebPPicture* picture);
// Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
// width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
// width and height must be set prior to calling this function.
WEBP_EXTERN int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
// Import a color mapped image. The number of colors is less or equal to
// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any,
// will be discarded. Returns 'false' in case of error, or if indexed[] contains
// invalid indices.
WEBP_EXTERN int
WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
const uint32_t palette[], int palette_size,
WebPPicture* pic);
//------------------------------------------------------------------------------
// Parse a bitstream, search for VP8 (lossy) header and report a
// rough estimation of the quality factor used for compressing the bitstream.
// If the bitstream is in lossless format, the special value '101' is returned.
// Otherwise (lossy bitstream), the returned value is in the range [0..100].
// Any error (invalid bitstream, animated WebP, incomplete header, etc.)
// will return a value of -1.
WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* WEBP_EXTRAS_EXTRAS_H_ */

View File

@ -1,351 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Simple tool to load two webp/png/jpg/tiff files and compute PSNR/SSIM.
// This is mostly a wrapper around WebPPictureDistortion().
//
/*
gcc -o get_disto get_disto.c -O3 -I../ -L../examples -L../imageio \
-lexample_util -limageio_util -limagedec -lwebp -L/opt/local/lib \
-lpng -lz -ljpeg -ltiff -lm -lpthread
*/
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h"
#include "imageio/image_dec.h"
#include "imageio/imageio_util.h"
static size_t ReadPicture(const char* const filename, WebPPicture* const pic,
int keep_alpha) {
const uint8_t* data = NULL;
size_t data_size = 0;
WebPImageReader reader = NULL;
int ok = ImgIoUtilReadFile(filename, &data, &data_size);
if (!ok) goto End;
pic->use_argb = 1; // force ARGB
#ifdef HAVE_WINCODEC_H
// Try to decode the file using WIC falling back to the other readers for
// e.g., WebP.
ok = ReadPictureWithWIC(filename, pic, keep_alpha, NULL);
if (ok) goto End;
#endif
reader = WebPGuessImageReader(data, data_size);
ok = reader(data, data_size, pic, keep_alpha, NULL);
End:
if (!ok) {
fprintf(stderr, "Error! Could not process file %s\n", filename);
}
free((void*)data);
return ok ? data_size : 0;
}
static void RescalePlane(uint8_t* plane, int width, int height,
int x_stride, int y_stride, int max) {
const uint32_t factor = (max > 0) ? (255u << 16) / max : 0;
int x, y;
for (y = 0; y < height; ++y) {
uint8_t* const ptr = plane + y * y_stride;
for (x = 0; x < width * x_stride; x += x_stride) {
const uint32_t diff = (ptr[x] * factor + (1 << 15)) >> 16;
ptr[x] = diff;
}
}
}
// Return the max absolute difference.
static int DiffScaleChannel(uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int x_stride, int w, int h, int do_scaling) {
int x, y;
int max = 0;
for (y = 0; y < h; ++y) {
uint8_t* const ptr1 = src1 + y * stride1;
const uint8_t* const ptr2 = src2 + y * stride2;
for (x = 0; x < w * x_stride; x += x_stride) {
const int diff = abs(ptr1[x] - ptr2[x]);
if (diff > max) max = diff;
ptr1[x] = diff;
}
}
if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
return max;
}
//------------------------------------------------------------------------------
// SSIM calculation. We re-implement these functions here, out of dsp/, to avoid
// breaking the library's hidden visibility. This code duplication avoids the
// bigger annoyance of having to open up internal details of libdsp...
#define SSIM_KERNEL 3 // total size of the kernel: 2 * SSIM_KERNEL + 1
// struct for accumulating statistical moments
typedef struct {
uint32_t w; // sum(w_i) : sum of weights
uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i)
uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc.
} DistoStats;
// hat-shaped filter. Sum of coefficients is equal to 16.
static const uint32_t kWeight[2 * SSIM_KERNEL + 1] = { 1, 2, 3, 4, 3, 2, 1 };
static WEBP_INLINE double SSIMCalculation(const DistoStats* const stats) {
const uint32_t N = stats->w;
const uint32_t w2 = N * N;
const uint32_t C1 = 20 * w2;
const uint32_t C2 = 60 * w2;
const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6
const uint64_t xmxm = (uint64_t)stats->xm * stats->xm;
const uint64_t ymym = (uint64_t)stats->ym * stats->ym;
if (xmxm + ymym >= C3) {
const int64_t xmym = (int64_t)stats->xm * stats->ym;
const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative
const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm;
const uint64_t syy = (uint64_t)stats->yym * N - ymym;
// we descale by 8 to prevent overflow during the fnum/fden multiply.
const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8;
const uint64_t den_S = (sxx + syy + C2) >> 8;
const uint64_t fnum = (2 * xmym + C1) * num_S;
const uint64_t fden = (xmxm + ymym + C1) * den_S;
const double r = (double)fnum / fden;
assert(r >= 0. && r <= 1.0);
return r;
}
return 1.; // area is too dark to contribute meaningfully
}
static double SSIMGetClipped(const uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int xo, int yo, int W, int H) {
DistoStats stats = { 0, 0, 0, 0, 0, 0 };
const int ymin = (yo - SSIM_KERNEL < 0) ? 0 : yo - SSIM_KERNEL;
const int ymax = (yo + SSIM_KERNEL > H - 1) ? H - 1 : yo + SSIM_KERNEL;
const int xmin = (xo - SSIM_KERNEL < 0) ? 0 : xo - SSIM_KERNEL;
const int xmax = (xo + SSIM_KERNEL > W - 1) ? W - 1 : xo + SSIM_KERNEL;
int x, y;
src1 += ymin * stride1;
src2 += ymin * stride2;
for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) {
for (x = xmin; x <= xmax; ++x) {
const uint32_t w = kWeight[SSIM_KERNEL + x - xo]
* kWeight[SSIM_KERNEL + y - yo];
const uint32_t s1 = src1[x];
const uint32_t s2 = src2[x];
stats.w += w;
stats.xm += w * s1;
stats.ym += w * s2;
stats.xxm += w * s1 * s1;
stats.xym += w * s1 * s2;
stats.yym += w * s2 * s2;
}
}
return SSIMCalculation(&stats);
}
// Compute SSIM-score map. Return -1 in case of error, max diff otherwise.
static int SSIMScaleChannel(uint8_t* src1, int stride1,
const uint8_t* src2, int stride2,
int x_stride, int w, int h, int do_scaling) {
int x, y;
int max = 0;
uint8_t* const plane1 = (uint8_t*)malloc(2 * w * h * sizeof(*plane1));
uint8_t* const plane2 = plane1 + w * h;
if (plane1 == NULL) return -1;
// extract plane
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
plane1[x + y * w] = src1[x * x_stride + y * stride1];
plane2[x + y * w] = src2[x * x_stride + y * stride2];
}
}
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
const double ssim = SSIMGetClipped(plane1, w, plane2, w, x, y, w, h);
int diff = (int)(255 * (1. - ssim));
if (diff < 0) {
diff = 0;
} else if (diff > max) {
max = diff;
}
src1[x * x_stride + y * stride1] = (diff > 255) ? 255u : (uint8_t)diff;
}
}
free(plane1);
if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max);
return max;
}
// Convert an argb picture to luminance.
static void ConvertToGray(WebPPicture* const pic) {
int x, y;
assert(pic != NULL);
assert(pic->use_argb);
for (y = 0; y < pic->height; ++y) {
uint32_t* const row = &pic->argb[y * pic->argb_stride];
for (x = 0; x < pic->width; ++x) {
const uint32_t argb = row[x];
const uint32_t r = (argb >> 16) & 0xff;
const uint32_t g = (argb >> 8) & 0xff;
const uint32_t b = (argb >> 0) & 0xff;
// We use BT.709 for converting to luminance.
const uint32_t Y = (uint32_t)(0.2126 * r + 0.7152 * g + 0.0722 * b + .5);
row[x] = (argb & 0xff000000u) | (Y * 0x010101u);
}
}
}
static void Help(void) {
fprintf(stderr,
"Usage: get_disto [-ssim][-psnr][-alpha] compressed.webp orig.webp\n"
" -ssim ..... print SSIM distortion\n"
" -psnr ..... print PSNR distortion (default)\n"
" -alpha .... preserve alpha plane\n"
" -h ........ this message\n"
" -o <file> . save the diff map as a WebP lossless file\n"
" -scale .... scale the difference map to fit [0..255] range\n"
" -gray ..... use grayscale for difference map (-scale)\n"
" Also handles PNG, JPG and TIFF files, in addition to WebP.\n");
}
int main(int argc, const char *argv[]) {
WebPPicture pic1, pic2;
size_t size1 = 0, size2 = 0;
int ret = 1;
float disto[5];
int type = 0;
int c;
int help = 0;
int keep_alpha = 0;
int scale = 0;
int use_gray = 0;
const char* name1 = NULL;
const char* name2 = NULL;
const char* output = NULL;
if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) {
fprintf(stderr, "Can't init pictures\n");
return 1;
}
for (c = 1; c < argc; ++c) {
if (!strcmp(argv[c], "-ssim")) {
type = 1;
} else if (!strcmp(argv[c], "-psnr")) {
type = 0;
} else if (!strcmp(argv[c], "-alpha")) {
keep_alpha = 1;
} else if (!strcmp(argv[c], "-scale")) {
scale = 1;
} else if (!strcmp(argv[c], "-gray")) {
use_gray = 1;
} else if (!strcmp(argv[c], "-h")) {
help = 1;
ret = 0;
} else if (!strcmp(argv[c], "-o")) {
if (++c == argc) {
fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]);
goto End;
}
output = argv[c];
} else if (name1 == NULL) {
name1 = argv[c];
} else {
name2 = argv[c];
}
}
if (help || name1 == NULL || name2 == NULL) {
if (!help) {
fprintf(stderr, "Error: missing arguments.\n");
}
Help();
goto End;
}
size1 = ReadPicture(name1, &pic1, 1);
size2 = ReadPicture(name2, &pic2, 1);
if (size1 == 0 || size2 == 0) goto End;
if (!keep_alpha) {
WebPBlendAlpha(&pic1, 0x00000000);
WebPBlendAlpha(&pic2, 0x00000000);
}
if (!WebPPictureDistortion(&pic1, &pic2, type, disto)) {
fprintf(stderr, "Error while computing the distortion.\n");
goto End;
}
printf("%u %.2f %.2f %.2f %.2f %.2f [ %.2f bpp ]\n",
(unsigned int)size1,
disto[4], disto[0], disto[1], disto[2], disto[3],
8.f * size1 / pic1.width / pic1.height);
if (output != NULL) {
uint8_t* data = NULL;
size_t data_size = 0;
if (pic1.use_argb != pic2.use_argb) {
fprintf(stderr, "Pictures are not in the same argb format. "
"Can't save the difference map.\n");
goto End;
}
if (pic1.use_argb) {
int n;
fprintf(stderr, "max differences per channel: ");
for (n = 0; n < 3; ++n) { // skip the alpha channel
const int range = (type == 1) ?
SSIMScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
(const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
4, pic1.width, pic1.height, scale) :
DiffScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4,
(const uint8_t*)pic2.argb + n, pic2.argb_stride * 4,
4, pic1.width, pic1.height, scale);
if (range < 0) fprintf(stderr, "\nError computing diff map\n");
fprintf(stderr, "[%d]", range);
}
fprintf(stderr, "\n");
if (use_gray) ConvertToGray(&pic1);
} else {
fprintf(stderr, "Can only compute the difference map in ARGB format.\n");
goto End;
}
#if !defined(WEBP_REDUCE_CSP)
data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb,
pic1.width, pic1.height,
pic1.argb_stride * 4,
&data);
if (data_size == 0) {
fprintf(stderr, "Error during lossless encoding.\n");
goto End;
}
ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1;
WebPFree(data);
if (ret) goto End;
#else
(void)data;
(void)data_size;
fprintf(stderr, "Cannot save the difference map. Please recompile "
"without the WEBP_REDUCE_CSP flag.\n");
#endif // WEBP_REDUCE_CSP
}
ret = 0;
End:
WebPPictureFree(&pic1);
WebPPictureFree(&pic2);
return ret;
}

View File

@ -1,129 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// VP8EstimateQuality(): rough encoding quality estimate
//
// Author: Skal (pascal.massimino@gmail.com)
#include "extras/extras.h"
#include "webp/decode.h"
#include <math.h>
//------------------------------------------------------------------------------
#define INVALID_BIT_POS (1ull << 63)
// In most cases, we don't need to use a full arithmetic decoder, since
// all the header's bits are written using a uniform probability of 128.
// We can just parse the header as if it was bits (works in 99.999% cases).
static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb,
uint64_t max_size, uint64_t* const bit_pos) {
uint32_t val = 0;
if (*bit_pos + nb <= 8 * max_size) {
while (nb-- > 0) {
const uint64_t p = (*bit_pos)++;
const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
val = (val << 1) | bit;
}
} else {
*bit_pos = INVALID_BIT_POS;
}
return val;
}
#define GET_BIT(n) GetBit(data, (n), size, &bit_pos)
#define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0)
int VP8EstimateQuality(const uint8_t* const data, size_t size) {
size_t pos = 0;
uint64_t bit_pos;
uint64_t sig = 0x00;
int ok = 0;
int Q = -1;
WebPBitstreamFeatures features;
if (data == NULL) return -1;
if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) {
return -1; // invalid file
}
if (features.format == 2) return 101; // lossless
if (features.format == 0 || features.has_animation) return -1; // mixed
while (pos < size) {
sig = (sig >> 8) | ((uint64_t)data[pos++] << 40);
if ((sig >> 24) == 0x2a019dull) {
ok = 1;
break;
}
}
if (!ok) return -1;
if (pos + 4 > size) return -1;
// Skip main Header
// width = (data[pos + 0] | (data[pos + 1] << 8)) & 0x3fff;
// height = (data[pos + 2] | (data[pos + 3] << 8)) & 0x3fff;
pos += 4;
bit_pos = pos * 8;
GET_BIT(2); // colorspace + clamp type
// Segment header
if (GET_BIT(1)) { // use_segment_
int s;
const int update_map = GET_BIT(1);
if (GET_BIT(1)) { // update data
const int absolute_delta = GET_BIT(1);
int q[4] = { 0, 0, 0, 0 };
for (s = 0; s < 4; ++s) {
if (GET_BIT(1)) {
q[s] = GET_BIT(7);
if (GET_BIT(1)) q[s] = -q[s]; // sign
}
}
if (absolute_delta) Q = q[0]; // just use the first segment's quantizer
for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7); // filter strength
}
if (update_map) {
for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8);
}
}
// Filter header
GET_BIT(1 + 6 + 3); // simple + level + sharpness
if (GET_BIT(1)) { // use_lf_delta
if (GET_BIT(1)) { // update lf_delta?
int n;
for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6);
}
}
// num partitions
GET_BIT(2);
// ParseQuant
{
const int base_q = GET_BIT(7);
/* dqy1_dc = */ CONDITIONAL_SKIP(5);
/* dqy2_dc = */ CONDITIONAL_SKIP(5);
/* dqy2_ac = */ CONDITIONAL_SKIP(5);
/* dquv_dc = */ CONDITIONAL_SKIP(5);
/* dquv_ac = */ CONDITIONAL_SKIP(5);
if (Q < 0) Q = base_q;
}
if (bit_pos == INVALID_BIT_POS) return -1;
// base mapping
Q = (127 - Q) * 100 / 127;
// correction for power-law behavior in low range
if (Q < 80) {
Q = (int)(pow(Q / 80., 1. / 0.38) * 80);
}
return Q;
}

View File

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

View File

@ -1,50 +0,0 @@
// Simple tool to roughly evaluate the quality encoding of a webp bitstream
//
// Result is a *rough* estimation of the quality. You should just consider
// the bucket it's in (q > 80? > 50? > 20?) and not take it for face value.
/*
gcc -o webp_quality webp_quality.c -O3 -I../ -L. -L../imageio \
-limageio_util -lwebpextras -lwebp -lm -lpthread
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extras/extras.h"
#include "imageio/imageio_util.h"
int main(int argc, const char *argv[]) {
int c;
int quiet = 0;
int ok = 1;
for (c = 1; ok && c < argc; ++c) {
if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
printf("webp_quality [-h][-quiet] webp_files...\n");
return 0;
} else {
const char* const filename = argv[c];
const uint8_t* data = NULL;
size_t data_size = 0;
int q;
ok = ImgIoUtilReadFile(filename, &data, &data_size);
if (!ok) break;
q = VP8EstimateQuality(data, data_size);
if (!quiet) printf("[%s] ", filename);
if (q < 0) {
fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n");
ok = 0;
} else {
if (!quiet) {
printf("Estimated quality factor: %d\n", q);
} else {
printf("%d\n", q); // just print the number
}
}
free((void*)data);
}
}
return ok ? 0 : 1;
}

View File

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

View File

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

View File

@ -1,54 +0,0 @@
LOCAL_PATH := $(call my-dir)
################################################################################
# libimageio_util
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
imageio_util.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_MODULE := imageio_util
include $(BUILD_STATIC_LIBRARY)
################################################################################
# libimagedec
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
image_dec.c \
jpegdec.c \
metadata.c \
pngdec.c \
pnmdec.c \
tiffdec.c \
webpdec.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := imageio_util
LOCAL_MODULE := imagedec
include $(BUILD_STATIC_LIBRARY)
################################################################################
# libimageenc
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
image_enc.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_STATIC_LIBRARIES := imageio_util
LOCAL_MODULE := imageenc
include $(BUILD_STATIC_LIBRARY)

View File

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

View File

@ -1,599 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Save image
#include "./image_enc.h"
#include <assert.h>
#include <string.h>
#ifdef WEBP_HAVE_PNG
#include <png.h>
#include <setjmp.h> // note: this must be included *after* png.h
#endif
#ifdef HAVE_WINCODEC_H
#ifdef __MINGW32__
#define INITGUID // Without this GUIDs are declared extern and fail to link
#endif
#define CINTERFACE
#define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h>
#include <windows.h>
#include <wincodec.h>
#endif
#include "./imageio_util.h"
//------------------------------------------------------------------------------
// PNG
#ifdef HAVE_WINCODEC_H
#define IFS(fn) \
do { \
if (SUCCEEDED(hr)) { \
hr = (fn); \
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
} \
} while (0)
#ifdef __cplusplus
#define MAKE_REFGUID(x) (x)
#else
#define MAKE_REFGUID(x) &(x)
#endif
static HRESULT CreateOutputStream(const char* out_file_name,
int write_to_mem, IStream** stream) {
HRESULT hr = S_OK;
if (write_to_mem) {
// Output to a memory buffer. This is freed when 'stream' is released.
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
} else {
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
}
if (FAILED(hr)) {
fprintf(stderr, "Error opening output file %s (%08lx)\n",
out_file_name, hr);
}
return hr;
}
static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
REFGUID container_guid,
uint8_t* rgb, int stride,
uint32_t width, uint32_t height, int has_alpha) {
HRESULT hr = S_OK;
IWICImagingFactory* factory = NULL;
IWICBitmapFrameEncode* frame = NULL;
IWICBitmapEncoder* encoder = NULL;
IStream* stream = NULL;
WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
: GUID_WICPixelFormat24bppBGR;
if (out_file_name == NULL || rgb == NULL) return E_INVALIDARG;
IFS(CoInitialize(NULL));
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
CLSCTX_INPROC_SERVER,
MAKE_REFGUID(IID_IWICImagingFactory),
(LPVOID*)&factory));
if (hr == REGDB_E_CLASSNOTREG) {
fprintf(stderr,
"Couldn't access Windows Imaging Component (are you running "
"Windows XP SP3 or newer?). PNG support not available. "
"Use -ppm or -pgm for available PPM and PGM formats.\n");
}
IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
&encoder));
IFS(IWICBitmapEncoder_Initialize(encoder, stream,
WICBitmapEncoderNoCache));
IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
height * stride, rgb));
IFS(IWICBitmapFrameEncode_Commit(frame));
IFS(IWICBitmapEncoder_Commit(encoder));
if (SUCCEEDED(hr) && use_stdout) {
HGLOBAL image;
IFS(GetHGlobalFromStream(stream, &image));
if (SUCCEEDED(hr)) {
HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
const BOOL update_mode = GetConsoleMode(std_output, &mode);
const void* const image_mem = GlobalLock(image);
DWORD bytes_written = 0;
// Clear output processing if necessary, then output the image.
if (update_mode) SetConsoleMode(std_output, 0);
if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image),
&bytes_written, NULL) ||
bytes_written != GlobalSize(image)) {
hr = E_FAIL;
}
if (update_mode) SetConsoleMode(std_output, mode);
GlobalUnlock(image);
}
}
if (frame != NULL) IUnknown_Release(frame);
if (encoder != NULL) IUnknown_Release(encoder);
if (factory != NULL) IUnknown_Release(factory);
if (stream != NULL) IUnknown_Release(stream);
return hr;
}
int WebPWritePNG(const char* out_file_name, int use_stdout,
const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
uint8_t* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
MAKE_REFGUID(GUID_ContainerFormatPng),
rgb, stride, width, height, has_alpha));
}
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp dummy) {
(void)dummy; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1);
}
int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
volatile png_structp png;
volatile png_infop info;
if (out_file == NULL || buffer == NULL) return 0;
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, PNGErrorFunction, NULL);
if (png == NULL) {
return 0;
}
info = png_create_info_struct(png);
if (info == NULL) {
png_destroy_write_struct((png_structpp)&png, NULL);
return 0;
}
if (setjmp(png_jmpbuf(png))) {
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
return 0;
}
png_init_io(png, out_file);
{
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
png_bytep row = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
uint32_t y;
png_set_IHDR(png, info, width, height, 8,
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png, info);
for (y = 0; y < height; ++y) {
png_write_rows(png, &row, 1);
row += stride;
}
}
png_write_end(png, info);
png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
return 1;
}
#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
int WebPWritePNG(FILE* fout, const WebPDecBuffer* const buffer) {
if (fout == NULL || buffer == NULL) return 0;
fprintf(stderr, "PNG support not compiled. Please install the libpng "
"development package before building.\n");
fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n");
return 0;
}
#endif
//------------------------------------------------------------------------------
// PPM / PAM
static int WritePPMPAM(FILE* fout, const WebPDecBuffer* const buffer,
int alpha) {
if (fout == NULL || buffer == NULL) {
return 0;
} else {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* row = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const size_t bytes_per_px = alpha ? 4 : 3;
uint32_t y;
if (row == NULL) return 0;
if (alpha) {
fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n"
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
} else {
fprintf(fout, "P6\n%u %u\n255\n", width, height);
}
for (y = 0; y < height; ++y) {
if (fwrite(row, width, bytes_per_px, fout) != bytes_per_px) {
return 0;
}
row += stride;
}
}
return 1;
}
int WebPWritePPM(FILE* fout, const WebPDecBuffer* const buffer) {
return WritePPMPAM(fout, buffer, 0);
}
int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
return WritePPMPAM(fout, buffer, 1);
}
//------------------------------------------------------------------------------
// Raw PGM
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = 2;
uint32_t y;
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
for (y = 0; y < height; ++y) {
if (fwrite(rgba, width, bytes_per_px, fout) != bytes_per_px) {
return 0;
}
rgba += stride;
}
return 1;
}
//------------------------------------------------------------------------------
// BMP
static void PutLE16(uint8_t* const dst, uint32_t value) {
dst[0] = (value >> 0) & 0xff;
dst[1] = (value >> 8) & 0xff;
}
static void PutLE32(uint8_t* const dst, uint32_t value) {
PutLE16(dst + 0, (value >> 0) & 0xffff);
PutLE16(dst + 2, (value >> 16) & 0xffff);
}
#define BMP_HEADER_SIZE 54
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint32_t bytes_per_px = has_alpha ? 4 : 3;
uint32_t y;
const uint32_t line_size = bytes_per_px * width;
const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
const uint32_t total_size = bmp_stride * height + BMP_HEADER_SIZE;
uint8_t bmp_header[BMP_HEADER_SIZE] = { 0 };
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
// bitmap file header
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
PutLE32(bmp_header + 2, total_size); // size including header
PutLE32(bmp_header + 6, 0); // reserved
PutLE32(bmp_header + 10, BMP_HEADER_SIZE); // offset to pixel array
// bitmap info header
PutLE32(bmp_header + 14, 40); // DIB header size
PutLE32(bmp_header + 18, width); // dimensions
PutLE32(bmp_header + 22, -(int)height); // vertical flip!
PutLE16(bmp_header + 26, 1); // number of planes
PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel
PutLE32(bmp_header + 30, 0); // no compression (BI_RGB)
PutLE32(bmp_header + 34, 0); // image size (dummy)
PutLE32(bmp_header + 38, 2400); // x pixels/meter
PutLE32(bmp_header + 42, 2400); // y pixels/meter
PutLE32(bmp_header + 46, 0); // number of palette colors
PutLE32(bmp_header + 50, 0); // important color count
// TODO(skal): color profile
// write header
if (fwrite(bmp_header, sizeof(bmp_header), 1, fout) != 1) {
return 0;
}
// write pixel array
for (y = 0; y < height; ++y) {
if (fwrite(rgba, line_size, 1, fout) != 1) {
return 0;
}
// write padding zeroes
if (bmp_stride != line_size) {
const uint8_t zeroes[3] = { 0 };
if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) {
return 0;
}
}
rgba += stride;
}
return 1;
}
#undef BMP_HEADER_SIZE
//------------------------------------------------------------------------------
// TIFF
#define NUM_IFD_ENTRIES 15
#define EXTRA_DATA_SIZE 16
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4)
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* rgba = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const uint8_t bytes_per_px = has_alpha ? 4 : 3;
const uint8_t assoc_alpha =
WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
: NUM_IFD_ENTRIES - 1;
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
0x49, 0x49, 0x2a, 0x00, // little endian signature
8, 0, 0, 0, // offset to the unique IFD that follows
// IFD (offset = 8). Entries must be written in increasing tag order.
num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
EXTRA_DATA_OFFSET + 0, 0, 0, 0,
0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
TIFF_HEADER_SIZE, 0, 0, 0, // data follows header
0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
bytes_per_px, 0, 0, 0,
0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
EXTRA_DATA_OFFSET + 8, 0, 0, 0,
0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
0x52, 0x01, 3, 0, 1, 0, 0, 0,
assoc_alpha, 0, 0, 0, // 178: ExtraSamples: rgbA/RGBA
0, 0, 0, 0, // 190: IFD terminator
// EXTRA_DATA_OFFSET:
8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
};
uint32_t y;
if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
// Fill placeholders in IFD:
PutLE32(tiff_header + 10 + 8, width);
PutLE32(tiff_header + 22 + 8, height);
PutLE32(tiff_header + 106 + 8, height);
PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator
// write header
if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) {
return 0;
}
// write pixel values
for (y = 0; y < height; ++y) {
if (fwrite(rgba, bytes_per_px, width, fout) != width) {
return 0;
}
rgba += stride;
}
return 1;
}
#undef TIFF_HEADER_SIZE
#undef EXTRA_DATA_OFFSET
#undef EXTRA_DATA_SIZE
#undef NUM_IFD_ENTRIES
//------------------------------------------------------------------------------
// Raw Alpha
int WebPWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
if (fout == NULL || buffer == NULL) {
return 0;
} else {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const uint8_t* a = buffer->u.YUVA.a;
const int a_stride = buffer->u.YUVA.a_stride;
uint32_t y;
if (a == NULL) return 0;
fprintf(fout, "P5\n%u %u\n255\n", width, height);
for (y = 0; y < height; ++y) {
if (fwrite(a, width, 1, fout) != 1) return 0;
a += a_stride;
}
return 1;
}
}
//------------------------------------------------------------------------------
// PGM with IMC4 layout
int WebPWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {
if (fout == NULL || buffer == NULL) {
return 0;
} else {
const int width = buffer->width;
const int height = buffer->height;
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
const uint8_t* src_y = yuv->y;
const uint8_t* src_u = yuv->u;
const uint8_t* src_v = yuv->v;
const uint8_t* src_a = yuv->a;
const int uv_width = (width + 1) / 2;
const int uv_height = (height + 1) / 2;
const int a_height = (src_a != NULL) ? height : 0;
int ok = 1;
int y;
if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
fprintf(fout, "P5\n%d %d\n255\n",
(width + 1) & ~1, height + uv_height + a_height);
for (y = 0; ok && y < height; ++y) {
ok &= (fwrite(src_y, width, 1, fout) == 1);
if (width & 1) fputc(0, fout); // padding byte
src_y += yuv->y_stride;
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
src_u += yuv->u_stride;
src_v += yuv->v_stride;
}
for (y = 0; ok && y < a_height; ++y) {
ok &= (fwrite(src_a, width, 1, fout) == 1);
if (width & 1) fputc(0, fout); // padding byte
src_a += yuv->a_stride;
}
return ok;
}
}
//------------------------------------------------------------------------------
// Raw YUV(A) planes
int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {
if (fout == NULL || buffer == NULL) {
return 0;
} else {
const int width = buffer->width;
const int height = buffer->height;
const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
const uint8_t* src_y = yuv->y;
const uint8_t* src_u = yuv->u;
const uint8_t* src_v = yuv->v;
const uint8_t* src_a = yuv->a;
const int uv_width = (width + 1) / 2;
const int uv_height = (height + 1) / 2;
const int a_height = (src_a != NULL) ? height : 0;
int ok = 1;
int y;
if (src_y == NULL || src_u == NULL || src_v == NULL) return 0;
for (y = 0; ok && y < height; ++y) {
ok &= (fwrite(src_y, width, 1, fout) == 1);
src_y += yuv->y_stride;
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(src_u, uv_width, 1, fout) == 1);
src_u += yuv->u_stride;
}
for (y = 0; ok && y < uv_height; ++y) {
ok &= (fwrite(src_v, uv_width, 1, fout) == 1);
src_v += yuv->v_stride;
}
for (y = 0; ok && y < a_height; ++y) {
ok &= (fwrite(src_a, width, 1, fout) == 1);
src_a += yuv->a_stride;
}
return ok;
}
}
//------------------------------------------------------------------------------
// Generic top-level call
int WebPSaveImage(const WebPDecBuffer* const buffer,
WebPOutputFileFormat format,
const char* const out_file_name) {
FILE* fout = NULL;
int needs_open_file = 1;
const int use_stdout = (out_file_name != NULL) && !strcmp(out_file_name, "-");
int ok = 1;
if (buffer == NULL || out_file_name == NULL) return 0;
#ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG);
#endif
if (needs_open_file) {
fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout)
: fopen(out_file_name, "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file %s\n", out_file_name);
return 0;
}
}
if (format == PNG ||
format == RGBA || format == BGRA || format == ARGB ||
format == rgbA || format == bgrA || format == Argb) {
#ifdef HAVE_WINCODEC_H
ok &= WebPWritePNG(out_file_name, use_stdout, buffer);
#else
ok &= WebPWritePNG(fout, buffer);
#endif
} else if (format == PAM) {
ok &= WebPWritePAM(fout, buffer);
} else if (format == PPM || format == RGB || format == BGR) {
ok &= WebPWritePPM(fout, buffer);
} else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) {
ok &= WebPWrite16bAsPGM(fout, buffer);
} else if (format == BMP) {
ok &= WebPWriteBMP(fout, buffer);
} else if (format == TIFF) {
ok &= WebPWriteTIFF(fout, buffer);
} else if (format == RAW_YUV) {
ok &= WebPWriteYUV(fout, buffer);
} else if (format == PGM || format == YUV || format == YUVA) {
ok &= WebPWritePGM(fout, buffer);
} else if (format == ALPHA_PLANE_ONLY) {
ok &= WebPWriteAlphaPlane(fout, buffer);
}
if (fout != NULL && fout != stdout) {
fclose(fout);
}
return ok;
}

View File

@ -1,96 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// All-in-one library to save PNG/JPEG/WebP/TIFF/WIC images.
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_IMAGEIO_IMAGE_ENC_H_
#define WEBP_IMAGEIO_IMAGE_ENC_H_
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "webp/types.h"
#include "webp/decode.h"
#ifdef __cplusplus
extern "C" {
#endif
// Output types
typedef enum {
PNG = 0,
PAM,
PPM,
PGM,
BMP,
TIFF,
RAW_YUV,
ALPHA_PLANE_ONLY, // this is for experimenting only
// forced colorspace output (for testing, mostly)
RGB, RGBA, BGR, BGRA, ARGB,
RGBA_4444, RGB_565,
rgbA, bgrA, Argb, rgbA_4444,
YUV, YUVA
} WebPOutputFileFormat;
// General all-purpose call.
// Most formats expect a 'buffer' containing RGBA-like samples, except
// RAW_YUV, YUV and YUVA formats.
// If 'out_file_name' is "-", data is saved to stdout.
// Returns false if an error occurred, true otherwise.
int WebPSaveImage(const WebPDecBuffer* const buffer,
WebPOutputFileFormat format, const char* const out_file_name);
// Save to PNG.
#ifdef HAVE_WINCODEC_H
int WebPWritePNG(const char* out_file_name, int use_stdout,
const struct WebPDecBuffer* const buffer);
#else
int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer);
#endif
// Save to PPM format (RGB, no alpha)
int WebPWritePPM(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save to PAM format (= PPM + alpha)
int WebPWritePAM(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purposes.
int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save as BMP
int WebPWriteBMP(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save as TIFF
int WebPWriteTIFF(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save the ALPHA plane (only) as a PGM
int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save as YUV samples as PGM format (using IMC4 layout).
// See: http://www.fourcc.org/yuv.php#IMC4.
// (very convenient format for viewing the samples, esp. for odd dimensions).
int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save YUV(A) planes sequentially (raw dump)
int WebPWriteYUV(FILE* fout, const struct WebPDecBuffer* const buffer);
// Save 16b mode (RGBA4444, RGB565, ...) as PGM format, for debugging purposes.
int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_IMAGEIO_IMAGE_ENC_H_

View File

@ -1,158 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Utility functions used by the image decoders.
//
#include "./imageio_util.h"
#if defined(_WIN32)
#include <fcntl.h> // for _O_BINARY
#include <io.h> // for _setmode()
#endif
#include <stdlib.h>
#include <string.h>
// -----------------------------------------------------------------------------
// File I/O
FILE* ImgIoUtilSetBinaryMode(FILE* file) {
#if defined(_WIN32)
if (_setmode(_fileno(file), _O_BINARY) == -1) {
fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
return NULL;
}
#endif
return file;
}
int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
static const size_t kBlockSize = 16384; // default initial size
size_t max_size = 0;
size_t size = 0;
uint8_t* input = NULL;
if (data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
if (!ImgIoUtilSetBinaryMode(stdin)) return 0;
while (!feof(stdin)) {
// We double the buffer size each time and read as much as possible.
const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
// we allocate one extra byte for the \0 terminator
void* const new_data = realloc(input, max_size + extra_size + 1);
if (new_data == NULL) goto Error;
input = (uint8_t*)new_data;
max_size += extra_size;
size += fread(input + size, 1, extra_size, stdin);
if (size < max_size) break;
}
if (ferror(stdin)) goto Error;
if (input != NULL) input[size] = '\0'; // convenient 0-terminator
*data = input;
*data_size = size;
return 1;
Error:
free(input);
fprintf(stderr, "Could not read from stdin\n");
return 0;
}
int ImgIoUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size) {
int ok;
uint8_t* file_data;
size_t file_size;
FILE* in;
const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
if (data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
in = fopen(file_name, "rb");
if (in == NULL) {
fprintf(stderr, "cannot open input file '%s'\n", file_name);
return 0;
}
fseek(in, 0, SEEK_END);
file_size = ftell(in);
fseek(in, 0, SEEK_SET);
// we allocate one extra byte for the \0 terminator
file_data = (uint8_t*)malloc(file_size + 1);
if (file_data == NULL) {
fclose(in);
fprintf(stderr, "memory allocation failure when reading file %s\n",
file_name);
return 0;
}
ok = (fread(file_data, file_size, 1, in) == 1);
fclose(in);
if (!ok) {
fprintf(stderr, "Could not read %d bytes of data from file %s\n",
(int)file_size, file_name);
free(file_data);
return 0;
}
file_data[file_size] = '\0'; // convenient 0-terminator
*data = file_data;
*data_size = file_size;
return 1;
}
// -----------------------------------------------------------------------------
int ImgIoUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size) {
int ok;
FILE* out;
const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
if (data == NULL) {
return 0;
}
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : fopen(file_name, "wb");
if (out == NULL) {
fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
return 0;
}
ok = (fwrite(data, data_size, 1, out) == 1);
if (out != stdout) fclose(out);
return ok;
}
// -----------------------------------------------------------------------------
void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height) {
while (height-- > 0) {
memcpy(dst, src, width * sizeof(*dst));
src += src_stride;
dst += dst_stride;
}
}
// -----------------------------------------------------------------------------
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
int ok = (total_size == (size_t)total_size);
#if defined(WEBP_MAX_IMAGE_SIZE)
ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE);
#endif
return ok;
}
// -----------------------------------------------------------------------------

View File

@ -1,64 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Utility functions used by the image decoders.
//
#ifndef WEBP_IMAGEIO_IMAGEIO_UTIL_H_
#define WEBP_IMAGEIO_IMAGEIO_UTIL_H_
#include <stdio.h>
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
// File I/O
// Reopen file in binary (O_BINARY) mode.
// Returns 'file' on success, NULL otherwise.
FILE* ImgIoUtilSetBinaryMode(FILE* file);
// Allocates storage for entire file 'file_name' and returns contents and size
// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
// be deleted using free().
// Note: for convenience, the data will be null-terminated with an extra byte
// (not accounted for in *data_size), in case the file is text and intended
// to be used as a C-string.
// If 'file_name' is NULL or equal to "-", input is read from stdin by calling
// the function ImgIoUtilReadFromStdin().
int ImgIoUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size);
// Same as ImgIoUtilReadFile(), but reads until EOF from stdin instead.
int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size);
// Write a data segment into a file named 'file_name'. Returns true if ok.
// If 'file_name' is NULL or equal to "-", output is written to stdout.
int ImgIoUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size);
//------------------------------------------------------------------------------
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height);
//------------------------------------------------------------------------------
// Returns 0 in case of overflow of nmemb * size.
int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_IMAGEIO_IMAGEIO_UTIL_H_

View File

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

View File

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

View File

@ -1,243 +0,0 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP decode.
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "./webpdec.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "webp/decode.h"
#include "webp/demux.h"
#include "webp/encode.h"
#include "./imageio_util.h"
#include "./metadata.h"
//------------------------------------------------------------------------------
// WebP decoding
static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
"OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
};
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
if (config->input.has_animation) {
fprintf(stderr,
"Error! Decoding of an animated WebP file is not supported.\n"
" Use webpmux to extract the individual frames or\n"
" vwebp to view this image.\n");
}
}
void PrintWebPError(const char* const in_file, int status) {
fprintf(stderr, "Decoding of %s failed.\n", in_file);
fprintf(stderr, "Status: %d", status);
if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
fprintf(stderr, "(%s)", kStatusMessages[status]);
}
fprintf(stderr, "\n");
}
int LoadWebP(const char* const in_file,
const uint8_t** data, size_t* data_size,
WebPBitstreamFeatures* bitstream) {
VP8StatusCode status;
WebPBitstreamFeatures local_features;
if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
if (bitstream == NULL) {
bitstream = &local_features;
}
status = WebPGetFeatures(*data, *data_size, bitstream);
if (status != VP8_STATUS_OK) {
free((void*)*data);
*data = NULL;
*data_size = 0;
PrintWebPError(in_file, status);
return 0;
}
return 1;
}
//------------------------------------------------------------------------------
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
WebPDecoderConfig* const config) {
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
PrintAnimationWarning(config);
return WebPDecode(data, data_size, config);
}
VP8StatusCode DecodeWebPIncremental(
const uint8_t* const data, size_t data_size,
WebPDecoderConfig* const config) {
VP8StatusCode status = VP8_STATUS_OK;
if (config == NULL) return VP8_STATUS_INVALID_PARAM;
PrintAnimationWarning(config);
// Decoding call.
{
WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
if (idec == NULL) {
fprintf(stderr, "Failed during WebPINewDecoder().\n");
return VP8_STATUS_OUT_OF_MEMORY;
} else {
status = WebPIUpdate(idec, data, data_size);
WebPIDelete(idec);
}
}
return status;
}
// -----------------------------------------------------------------------------
// Metadata
static int ExtractMetadata(const uint8_t* const data, size_t data_size,
Metadata* const metadata) {
WebPData webp_data = { data, data_size };
WebPDemuxer* const demux = WebPDemux(&webp_data);
WebPChunkIterator chunk_iter;
uint32_t flags;
if (demux == NULL) return 0;
assert(metadata != NULL);
flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->iccp);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->exif);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
&metadata->xmp);
WebPDemuxReleaseChunkIterator(&chunk_iter);
}
WebPDemuxDelete(demux);
return 1;
}
// -----------------------------------------------------------------------------
int ReadWebP(const uint8_t* const data, size_t data_size,
WebPPicture* const pic,
int keep_alpha, Metadata* const metadata) {
int ok = 0;
VP8StatusCode status = VP8_STATUS_OK;
WebPDecoderConfig config;
WebPDecBuffer* const output_buffer = &config.output;
WebPBitstreamFeatures* const bitstream = &config.input;
if (data == NULL || data_size == 0 || pic == NULL) return 0;
if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n");
return 0;
}
status = WebPGetFeatures(data, data_size, bitstream);
if (status != VP8_STATUS_OK) {
PrintWebPError("input data", status);
return 0;
}
do {
const int has_alpha = keep_alpha && bitstream->has_alpha;
uint64_t stride;
pic->width = bitstream->width;
pic->height = bitstream->height;
if (pic->use_argb) {
stride = (uint64_t)bitstream->width * 4;
} else {
stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
}
if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
status = VP8_STATUS_OUT_OF_MEMORY;
break;
}
ok = WebPPictureAlloc(pic);
if (!ok) {
status = VP8_STATUS_OUT_OF_MEMORY;
break;
}
if (pic->use_argb) {
#ifdef WORDS_BIGENDIAN
output_buffer->colorspace = MODE_ARGB;
#else
output_buffer->colorspace = MODE_BGRA;
#endif
output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
} else {
output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
output_buffer->u.YUVA.y = pic->y;
output_buffer->u.YUVA.u = pic->u;
output_buffer->u.YUVA.v = pic->v;
output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL;
output_buffer->u.YUVA.y_stride = pic->y_stride;
output_buffer->u.YUVA.u_stride = pic->uv_stride;
output_buffer->u.YUVA.v_stride = pic->uv_stride;
output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0;
output_buffer->u.YUVA.y_size = pic->height * pic->y_stride;
output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride;
output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride;
output_buffer->u.YUVA.a_size = pic->height * pic->a_stride;
}
output_buffer->is_external_memory = 1;
status = DecodeWebP(data, data_size, &config);
ok = (status == VP8_STATUS_OK);
if (ok && !keep_alpha && pic->use_argb) {
// Need to wipe out the alpha value, as requested.
int x, y;
uint32_t* argb = pic->argb;
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
argb += pic->argb_stride;
}
}
} while (0); // <- so we can 'break' out of the loop
if (status != VP8_STATUS_OK) {
PrintWebPError("input data", status);
ok = 0;
}
WebPFreeDecBuffer(output_buffer);
if (ok && metadata != NULL) {
ok = ExtractMetadata(data, data_size, metadata);
if (!ok) {
PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
}
}
if (!ok) WebPPictureFree(pic);
return ok;
}
// -----------------------------------------------------------------------------

View File

@ -1,67 +0,0 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP decode.
#ifndef WEBP_IMAGEIO_WEBPDEC_H_
#define WEBP_IMAGEIO_WEBPDEC_H_
#include "webp/decode.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Metadata;
struct WebPPicture;
//------------------------------------------------------------------------------
// WebP decoding
// Prints an informative error message regarding decode failure of 'in_file'.
// 'status' is treated as a VP8StatusCode and if valid will be printed as a
// text string.
void PrintWebPError(const char* const in_file, int status);
// Reads a WebP from 'in_file', returning the contents and size in 'data' and
// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures().
// Returns true on success.
int LoadWebP(const char* const in_file,
const uint8_t** data, size_t* data_size,
WebPBitstreamFeatures* bitstream);
// Decodes the WebP contained in 'data'.
// 'config' is a structure previously initialized by WebPInitDecoderConfig().
// 'config->output' should have the desired colorspace selected.
// Returns the decoder status. On success 'config->output' will contain the
// decoded picture.
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
WebPDecoderConfig* const config);
// Same as DecodeWebP(), but using the incremental decoder.
VP8StatusCode DecodeWebPIncremental(
const uint8_t* const data, size_t data_size,
WebPDecoderConfig* const config);
//------------------------------------------------------------------------------
// Decodes a WebP contained in 'data', returning the decoded output in 'pic'.
// Output is RGBA or YUVA, depending on pic->use_argb value.
// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
// Returns true on success.
int ReadWebP(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_IMAGEIO_WEBPDEC_H_

View File

@ -122,8 +122,8 @@ for PLATFORM in ${PLATFORMS}; do
export PATH=${OLDPATH} export PATH=${OLDPATH}
done done
cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/ cp -a ${SRCDIR}/src/webp/*.h ${TARGETDIR}/Headers/
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP ${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/ cp -a ${SRCDIR}/src/webp/*.h ${DECTARGETDIR}/Headers/
${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder ${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder

View File

@ -3,7 +3,7 @@
# It will not install the libraries system-wide, but just create the 'cwebp' # It will not install the libraries system-wide, but just create the 'cwebp'
# and 'dwebp' tools in the examples/ directory, along with the static # and 'dwebp' tools in the examples/ directory, along with the static
# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a', # libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a',
# 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'. # 'src/demux/libwebpdemux.a' and 'src/libwebpextras.a'.
# #
# To build the library and examples, use: # To build the library and examples, use:
# make -f makefile.unix # make -f makefile.unix
@ -25,26 +25,13 @@ ifeq ($(strip $(shell uname)), Darwin)
# Failure observed with: gcc 4.2.1 and 4.0.1. # Failure observed with: gcc 4.2.1 and 4.0.1.
EXTRA_FLAGS += -fno-common EXTRA_FLAGS += -fno-common
EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H
EXTRA_FLAGS += -Wno-deprecated-declarations
EXTRA_FLAGS += -I/opt/local/include EXTRA_FLAGS += -I/opt/local/include
EXTRA_LIBS += -L/opt/local/lib EXTRA_LIBS += -L/opt/local/lib
GL_LIBS = -framework GLUT -framework OpenGL GL_LIBS = -framework GLUT -framework OpenGL
else else
EXTRA_FLAGS += -I/usr/local/include
EXTRA_LIBS += -L/usr/local/lib
GL_LIBS = -lglut -lGL GL_LIBS = -lglut -lGL
endif endif
# SDL flags: use sdl-config if it exists
SDL_CONFIG = $(shell sdl-config --version 2> /dev/null)
ifneq ($(SDL_CONFIG),)
SDL_LIBS = $(shell sdl-config --libs)
SDL_FLAGS = $(shell sdl-config --cflags)
else
# use best-guess
SDL_LIBS = -lSDL
SDL_FLAGS =
endif
# To install libraries on Mac OS X: # To install libraries on Mac OS X:
# 1. Install MacPorts (http://www.macports.org/install.php) # 1. Install MacPorts (http://www.macports.org/install.php)
@ -64,8 +51,11 @@ endif
# 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect. # 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect.
# EXTRA_FLAGS += -m32 # EXTRA_FLAGS += -m32
# Extra flags to enable experimental features and code
# EXTRA_FLAGS += -DWEBP_EXPERIMENTAL_FEATURES
# Extra flags to enable byte swap for 16 bit colorspaces. # Extra flags to enable byte swap for 16 bit colorspaces.
# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP=1 # EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP
# Extra flags to enable multi-threading # Extra flags to enable multi-threading
EXTRA_FLAGS += -DWEBP_USE_THREAD EXTRA_FLAGS += -DWEBP_USE_THREAD
@ -111,13 +101,8 @@ endif
AR = ar AR = ar
ARFLAGS = r ARFLAGS = r
CPPFLAGS = -I. -Isrc/ -Wall CPPFLAGS = -Isrc/ -Wall
ifeq ($(DEBUG), 1) CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
CFLAGS = -g
else
CFLAGS = -O3 -DNDEBUG
endif
CFLAGS += $(EXTRA_FLAGS)
CC = gcc CC = gcc
INSTALL = install INSTALL = install
GROFF = /usr/bin/groff GROFF = /usr/bin/groff
@ -128,16 +113,16 @@ ANIM_UTIL_OBJS = \
examples/anim_util.o \ examples/anim_util.o \
DEC_OBJS = \ DEC_OBJS = \
src/dec/alpha_dec.o \ src/dec/alpha.o \
src/dec/buffer_dec.o \ src/dec/buffer.o \
src/dec/frame_dec.o \ src/dec/frame.o \
src/dec/idec_dec.o \ src/dec/idec.o \
src/dec/io_dec.o \ src/dec/io.o \
src/dec/quant_dec.o \ src/dec/quant.o \
src/dec/tree_dec.o \ src/dec/tree.o \
src/dec/vp8_dec.o \ src/dec/vp8.o \
src/dec/vp8l_dec.o \ src/dec/vp8l.o \
src/dec/webp_dec.o \ src/dec/webp.o \
DEMUX_OBJS = \ DEMUX_OBJS = \
src/demux/anim_decode.o \ src/demux/anim_decode.o \
@ -146,7 +131,6 @@ DEMUX_OBJS = \
DSP_DEC_OBJS = \ DSP_DEC_OBJS = \
src/dsp/alpha_processing.o \ src/dsp/alpha_processing.o \
src/dsp/alpha_processing_mips_dsp_r2.o \ src/dsp/alpha_processing_mips_dsp_r2.o \
src/dsp/alpha_processing_neon.o \
src/dsp/alpha_processing_sse2.o \ src/dsp/alpha_processing_sse2.o \
src/dsp/alpha_processing_sse41.o \ src/dsp/alpha_processing_sse41.o \
src/dsp/cpu.o \ src/dsp/cpu.o \
@ -160,34 +144,29 @@ DSP_DEC_OBJS = \
src/dsp/dec_sse41.o \ src/dsp/dec_sse41.o \
src/dsp/filters.o \ src/dsp/filters.o \
src/dsp/filters_mips_dsp_r2.o \ src/dsp/filters_mips_dsp_r2.o \
src/dsp/filters_msa.o \
src/dsp/filters_neon.o \
src/dsp/filters_sse2.o \ src/dsp/filters_sse2.o \
src/dsp/lossless.o \ src/dsp/lossless.o \
src/dsp/lossless_mips_dsp_r2.o \ src/dsp/lossless_mips_dsp_r2.o \
src/dsp/lossless_msa.o \
src/dsp/lossless_neon.o \ src/dsp/lossless_neon.o \
src/dsp/lossless_sse2.o \ src/dsp/lossless_sse2.o \
src/dsp/rescaler.o \ src/dsp/rescaler.o \
src/dsp/rescaler_mips32.o \ src/dsp/rescaler_mips32.o \
src/dsp/rescaler_mips_dsp_r2.o \ src/dsp/rescaler_mips_dsp_r2.o \
src/dsp/rescaler_msa.o \
src/dsp/rescaler_neon.o \ src/dsp/rescaler_neon.o \
src/dsp/rescaler_sse2.o \ src/dsp/rescaler_sse2.o \
src/dsp/upsampling.o \ src/dsp/upsampling.o \
src/dsp/upsampling_mips_dsp_r2.o \ src/dsp/upsampling_mips_dsp_r2.o \
src/dsp/upsampling_msa.o \
src/dsp/upsampling_neon.o \ src/dsp/upsampling_neon.o \
src/dsp/upsampling_sse2.o \ src/dsp/upsampling_sse2.o \
src/dsp/upsampling_sse41.o \
src/dsp/yuv.o \ src/dsp/yuv.o \
src/dsp/yuv_mips32.o \ src/dsp/yuv_mips32.o \
src/dsp/yuv_mips_dsp_r2.o \ src/dsp/yuv_mips_dsp_r2.o \
src/dsp/yuv_neon.o \
src/dsp/yuv_sse2.o \ src/dsp/yuv_sse2.o \
src/dsp/yuv_sse41.o \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
src/dsp/argb.o \
src/dsp/argb_mips_dsp_r2.o \
src/dsp/argb_sse2.o \
src/dsp/cost.o \ src/dsp/cost.o \
src/dsp/cost_mips32.o \ src/dsp/cost_mips32.o \
src/dsp/cost_mips_dsp_r2.o \ src/dsp/cost_mips_dsp_r2.o \
@ -196,56 +175,47 @@ DSP_ENC_OBJS = \
src/dsp/enc_avx2.o \ src/dsp/enc_avx2.o \
src/dsp/enc_mips32.o \ src/dsp/enc_mips32.o \
src/dsp/enc_mips_dsp_r2.o \ src/dsp/enc_mips_dsp_r2.o \
src/dsp/enc_msa.o \
src/dsp/enc_neon.o \ src/dsp/enc_neon.o \
src/dsp/enc_sse2.o \ src/dsp/enc_sse2.o \
src/dsp/enc_sse41.o \ src/dsp/enc_sse41.o \
src/dsp/lossless_enc.o \ src/dsp/lossless_enc.o \
src/dsp/lossless_enc_mips32.o \ src/dsp/lossless_enc_mips32.o \
src/dsp/lossless_enc_mips_dsp_r2.o \ src/dsp/lossless_enc_mips_dsp_r2.o \
src/dsp/lossless_enc_msa.o \
src/dsp/lossless_enc_neon.o \ src/dsp/lossless_enc_neon.o \
src/dsp/lossless_enc_sse2.o \ src/dsp/lossless_enc_sse2.o \
src/dsp/lossless_enc_sse41.o \ src/dsp/lossless_enc_sse41.o \
src/dsp/ssim.o \
src/dsp/ssim_sse2.o \
ENC_OBJS = \ ENC_OBJS = \
src/enc/alpha_enc.o \ src/enc/alpha.o \
src/enc/analysis_enc.o \ src/enc/analysis.o \
src/enc/backward_references_cost_enc.o \ src/enc/backward_references.o \
src/enc/backward_references_enc.o \ src/enc/config.o \
src/enc/config_enc.o \ src/enc/cost.o \
src/enc/cost_enc.o \ src/enc/delta_palettization.o \
src/enc/filter_enc.o \ src/enc/filter.o \
src/enc/frame_enc.o \ src/enc/frame.o \
src/enc/histogram_enc.o \ src/enc/histogram.o \
src/enc/iterator_enc.o \ src/enc/iterator.o \
src/enc/near_lossless_enc.o \ src/enc/near_lossless.o \
src/enc/picture_enc.o \ src/enc/picture.o \
src/enc/picture_csp_enc.o \ src/enc/picture_csp.o \
src/enc/picture_psnr_enc.o \ src/enc/picture_psnr.o \
src/enc/picture_rescale_enc.o \ src/enc/picture_rescale.o \
src/enc/picture_tools_enc.o \ src/enc/picture_tools.o \
src/enc/predictor_enc.o \ src/enc/quant.o \
src/enc/quant_enc.o \ src/enc/syntax.o \
src/enc/syntax_enc.o \ src/enc/token.o \
src/enc/token_enc.o \ src/enc/tree.o \
src/enc/tree_enc.o \ src/enc/vp8l.o \
src/enc/vp8l_enc.o \ src/enc/webpenc.o \
src/enc/webp_enc.o \
EX_FORMAT_DEC_OBJS = \ EX_FORMAT_DEC_OBJS = \
imageio/image_dec.o \ examples/image_dec.o \
imageio/jpegdec.o \ examples/jpegdec.o \
imageio/metadata.o \ examples/metadata.o \
imageio/pngdec.o \ examples/pngdec.o \
imageio/pnmdec.o \ examples/tiffdec.o \
imageio/tiffdec.o \ examples/webpdec.o \
imageio/webpdec.o \
EX_FORMAT_ENC_OBJS = \
imageio/image_enc.o \
EX_UTIL_OBJS = \ EX_UTIL_OBJS = \
examples/example_util.o \ examples/example_util.o \
@ -253,9 +223,6 @@ EX_UTIL_OBJS = \
GIFDEC_OBJS = \ GIFDEC_OBJS = \
examples/gifdec.o \ examples/gifdec.o \
IMAGE_UTIL_OBJS = \
imageio/imageio_util.o \
MUX_OBJS = \ MUX_OBJS = \
src/mux/anim_encode.o \ src/mux/anim_encode.o \
src/mux/muxedit.o \ src/mux/muxedit.o \
@ -263,24 +230,23 @@ MUX_OBJS = \
src/mux/muxread.o \ src/mux/muxread.o \
UTILS_DEC_OBJS = \ UTILS_DEC_OBJS = \
src/utils/bit_reader_utils.o \ src/utils/bit_reader.o \
src/utils/color_cache_utils.o \ src/utils/color_cache.o \
src/utils/filters_utils.o \ src/utils/filters.o \
src/utils/huffman_utils.o \ src/utils/huffman.o \
src/utils/quant_levels_dec_utils.o \ src/utils/quant_levels_dec.o \
src/utils/random_utils.o \ src/utils/random.o \
src/utils/rescaler_utils.o \ src/utils/rescaler.o \
src/utils/thread_utils.o \ src/utils/thread.o \
src/utils/utils.o \ src/utils/utils.o \
UTILS_ENC_OBJS = \ UTILS_ENC_OBJS = \
src/utils/bit_writer_utils.o \ src/utils/bit_writer.o \
src/utils/huffman_encode_utils.o \ src/utils/huffman_encode.o \
src/utils/quant_levels_utils.o \ src/utils/quant_levels.o \
EXTRA_OBJS = \ EXTRA_OBJS = \
extras/extras.o \ src/extras/extras.o \
extras/quality_estimate.o \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS) LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \ LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) $(DSP_ENC_OBJS) \
@ -298,171 +264,115 @@ HDRS_INSTALLED = \
src/webp/types.h \ src/webp/types.h \
HDRS = \ HDRS = \
src/dec/alphai_dec.h \ src/dec/alphai.h \
src/dec/common_dec.h \ src/dec/common.h \
src/dec/vp8_dec.h \ src/dec/decode_vp8.h \
src/dec/vp8i_dec.h \ src/dec/vp8i.h \
src/dec/vp8li_dec.h \ src/dec/vp8li.h \
src/dec/webpi_dec.h \ src/dec/webpi.h \
src/dsp/common_sse2.h \ src/dsp/common_sse2.h \
src/dsp/dsp.h \ src/dsp/dsp.h \
src/dsp/lossless.h \ src/dsp/lossless.h \
src/dsp/lossless_common.h \
src/dsp/mips_macro.h \ src/dsp/mips_macro.h \
src/dsp/msa_macro.h \ src/dsp/msa_macro.h \
src/dsp/neon.h \ src/dsp/neon.h \
src/dsp/yuv.h \ src/dsp/yuv.h \
src/enc/backward_references_enc.h \ src/enc/backward_references.h \
src/enc/cost_enc.h \ src/enc/cost.h \
src/enc/histogram_enc.h \ src/enc/delta_palettization.h \
src/enc/vp8i_enc.h \ src/enc/histogram.h \
src/enc/vp8li_enc.h \ src/enc/vp8enci.h \
src/mux/animi.h \ src/enc/vp8li.h \
src/mux/muxi.h \ src/mux/muxi.h \
src/utils/bit_reader_utils.h \ src/utils/bit_reader.h \
src/utils/bit_reader_inl_utils.h \ src/utils/bit_reader_inl.h \
src/utils/bit_writer_utils.h \ src/utils/bit_writer.h \
src/utils/color_cache_utils.h \ src/utils/color_cache.h \
src/utils/endian_inl_utils.h \ src/utils/endian_inl.h \
src/utils/filters_utils.h \ src/utils/filters.h \
src/utils/huffman_utils.h \ src/utils/huffman.h \
src/utils/huffman_encode_utils.h \ src/utils/huffman_encode.h \
src/utils/quant_levels_utils.h \ src/utils/quant_levels.h \
src/utils/quant_levels_dec_utils.h \ src/utils/quant_levels_dec.h \
src/utils/random_utils.h \ src/utils/random.h \
src/utils/rescaler_utils.h \ src/utils/rescaler.h \
src/utils/thread_utils.h \ src/utils/thread.h \
src/utils/utils.h \ src/utils/utils.h \
src/webp/format_constants.h \ src/webp/format_constants.h \
$(HDRS_INSTALLED) \ $(HDRS_INSTALLED) \
OUT_LIBS = examples/libexample_util.a OUT_LIBS = examples/libexample_util.a src/libwebpdecoder.a src/libwebp.a
OUT_LIBS += imageio/libimageio_util.a EXTRA_LIB = src/libwebpextras.a
OUT_LIBS += imageio/libimagedec.a
OUT_LIBS += imageio/libimageenc.a
OUT_LIBS += src/libwebpdecoder.a
OUT_LIBS += src/libwebp.a
EXTRA_LIB = extras/libwebpextras.a
OUT_EXAMPLES = examples/cwebp examples/dwebp OUT_EXAMPLES = examples/cwebp examples/dwebp
EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \ EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \
examples/anim_diff examples/anim_dump \ examples/anim_diff
examples/img2webp examples/webpinfo
OTHER_EXAMPLES = extras/get_disto extras/webp_quality extras/vwebp_sdl
OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES) OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES)
ifeq ($(MAKECMDGOALS),clean) ifeq ($(MAKECMDGOALS),clean)
OUTPUT += $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES) OUTPUT += $(EXTRA_EXAMPLES)
OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB) OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB)
OUTPUT += examples/libgifdec.a examples/libanim_util.a OUTPUT += examples/libgifdec.a examples/libanim_util.a
endif endif
ex: $(OUT_EXAMPLES) ex: $(OUT_EXAMPLES)
all: ex $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES) all: ex $(EXTRA_EXAMPLES)
extras: $(EXTRA_LIB) extras: $(EXTRA_LIB)
$(EX_FORMAT_DEC_OBJS): %.o: %.h $(EX_FORMAT_DEC_OBJS): %.o: %.h
# special dependencies: # special dependencies:
# tree_dec.c/vp8_dec.c/bit_reader_utils.c <-> # tree.c/vp8.c/bit_reader.c <-> bit_reader_inl.h, endian_inl.h
# bit_reader_inl_utils.h, endian_inl_utils.h # bit_writer.c <-> endian_inl.h
# bit_writer_utils.c <-> endian_inl_utils.h src/dec/tree.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
src/dec/tree_dec.o: src/utils/bit_reader_inl_utils.h src/dec/vp8.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
src/dec/tree_dec.o: src/utils/endian_inl_utils.h src/utils/bit_reader.o: src/utils/bit_reader_inl.h src/utils/endian_inl.h
src/dec/vp8_dec.o: src/utils/bit_reader_inl_utils.h src/utils/endian_inl_utils.h src/utils/bit_writer.o: src/utils/endian_inl.h
src/utils/bit_reader_utils.o: src/utils/bit_reader_inl_utils.h
src/utils/bit_reader_utils.o: src/utils/endian_inl_utils.h
src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h
%.o: %.c $(HDRS) %.o: %.c $(HDRS)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
examples/libanim_util.a: $(ANIM_UTIL_OBJS) examples/libanim_util.a: $(ANIM_UTIL_OBJS)
examples/libexample_dec.a: $(EX_FORMAT_DEC_OBJS)
examples/libexample_util.a: $(EX_UTIL_OBJS) examples/libexample_util.a: $(EX_UTIL_OBJS)
examples/libgifdec.a: $(GIFDEC_OBJS) examples/libgifdec.a: $(GIFDEC_OBJS)
extras/libwebpextras.a: $(LIBWEBPEXTRA_OBJS)
imageio/libimagedec.a: $(EX_FORMAT_DEC_OBJS)
imageio/libimageenc.a: $(EX_FORMAT_ENC_OBJS)
imageio/libimageio_util.a: $(IMAGE_UTIL_OBJS)
src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS) src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS)
src/libwebp.a: $(LIBWEBP_OBJS) src/libwebp.a: $(LIBWEBP_OBJS)
src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS) src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS)
src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS) src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
src/libwebpextras.a: $(LIBWEBPEXTRA_OBJS)
%.a: %.a:
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS) examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS)
examples/cwebp: examples/cwebp.o examples/cwebp: examples/cwebp.o
examples/dwebp: examples/dwebp.o examples/dwebp: examples/dwebp.o
examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS) examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS)
examples/vwebp: examples/vwebp.o examples/vwebp: examples/vwebp.o
examples/webpmux: examples/webpmux.o examples/webpmux: examples/webpmux.o
examples/img2webp: examples/img2webp.o
examples/webpinfo: examples/webpinfo.o
examples/anim_diff: examples/libanim_util.a examples/libgifdec.a examples/anim_diff: examples/libanim_util.a examples/libgifdec.a
examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a examples/anim_diff: src/libwebp.a
examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS) examples/anim_diff: EXTRA_LIBS += $(GIF_LIBS)
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/anim_dump: examples/libanim_util.a examples/cwebp: examples/libexample_util.a examples/libexample_dec.a
examples/anim_dump: src/demux/libwebpdemux.a
examples/anim_dump: examples/libexample_util.a
examples/anim_dump: imageio/libimageio_util.a
examples/anim_dump: imageio/libimageenc.a
examples/anim_dump: src/libwebp.a
examples/anim_dump: EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
examples/cwebp: examples/libexample_util.a
examples/cwebp: imageio/libimagedec.a
examples/cwebp: src/demux/libwebpdemux.a
examples/cwebp: imageio/libimageio_util.a
examples/cwebp: src/libwebp.a examples/cwebp: src/libwebp.a
examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS) examples/cwebp: EXTRA_LIBS += $(CWEBP_LIBS)
examples/dwebp: examples/libexample_util.a examples/dwebp: examples/libexample_util.a src/libwebpdecoder.a
examples/dwebp: imageio/libimagedec.a
examples/dwebp: src/demux/libwebpdemux.a
examples/dwebp: imageio/libimageenc.a
examples/dwebp: imageio/libimageio_util.a
examples/dwebp: src/libwebp.a
examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS) examples/dwebp: EXTRA_LIBS += $(DWEBP_LIBS)
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a examples/gif2webp: examples/libexample_util.a examples/libgifdec.a
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a examples/gif2webp: src/mux/libwebpmux.a src/libwebp.a
examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS) examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a
examples/vwebp: imageio/libimageio_util.a src/libwebp.a examples/vwebp: src/libwebp.a
examples/vwebp: EXTRA_LIBS += $(GL_LIBS) examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a
examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a examples/webpmux: src/libwebpdecoder.a
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/img2webp: imageio/libimagedec.a
examples/img2webp: src/demux/libwebpdemux.a
examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
examples/img2webp: EXTRA_LIBS += $(CWEBP_LIBS)
examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
examples/webpinfo: src/libwebpdecoder.a
extras/get_disto: extras/get_disto.o $(OUT_EXAMPLES) $(EXTRA_EXAMPLES):
extras/get_disto: imageio/libimagedec.a
extras/get_disto: src/demux/libwebpdemux.a
extras/get_disto: imageio/libimageio_util.a
extras/get_disto: src/libwebp.a
extras/get_disto: EXTRA_LIBS += $(CWEBP_LIBS)
extras/webp_quality: extras/webp_quality.o
extras/webp_quality: imageio/libimageio_util.a
extras/webp_quality: $(EXTRA_LIB) src/libwebp.a
extras/vwebp_sdl: extras/vwebp_sdl.o
extras/vwebp_sdl: extras/webp_to_sdl.o
extras/vwebp_sdl: imageio/libimageio_util.a
extras/vwebp_sdl: src/libwebp.a
extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS)
extras/vwebp_sdl: EXTRA_LIBS += $(SDL_LIBS)
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)
dist: DESTDIR := dist dist: DESTDIR := dist
@ -476,10 +386,9 @@ dist: all
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib $(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib $(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
umask 022; \ umask 022; \
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \ for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1; do \
man/img2webp.1 man/webpinfo.1; do \
basenam=$$(basename $$m .1); \ basenam=$$(basename $$m .1); \
$(GROFF) -t -e -man -T ascii $$m \ $(GROFF) -t -e -man -T utf8 $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \
$(GROFF) -t -e -man -T html $$m \ $(GROFF) -t -e -man -T html $$m \
| $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \ | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \
@ -488,12 +397,11 @@ dist: all
clean: clean:
$(RM) $(OUTPUT) *~ \ $(RM) $(OUTPUT) *~ \
examples/*.o examples/*~ \ examples/*.o examples/*~ \
extras/*.o extras/*~ \
imageio/*.o imageio/*~ \
src/dec/*.o src/dec/*~ \ src/dec/*.o src/dec/*~ \
src/demux/*.o src/demux/*~ \ src/demux/*.o src/demux/*~ \
src/dsp/*.o src/dsp/*~ \ src/dsp/*.o src/dsp/*~ \
src/enc/*.o src/enc/*~ \ src/enc/*.o src/enc/*~ \
src/extras/*.o src/extras/*~ \
src/mux/*.o src/mux/*~ \ src/mux/*.o src/mux/*~ \
src/utils/*.o src/utils/*~ \ src/utils/*.o src/utils/*~ \
src/webp/*~ man/*~ doc/*~ swig/*~ \ src/webp/*~ man/*~ doc/*~ swig/*~ \

View File

@ -8,7 +8,4 @@ endif
if BUILD_VWEBP if BUILD_VWEBP
man_MANS += vwebp.1 man_MANS += vwebp.1
endif endif
if BUILD_WEBPINFO
man_MANS += webpinfo.1
endif
EXTRA_DIST = $(man_MANS) EXTRA_DIST = $(man_MANS)

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH CWEBP 1 "January 20, 2017" .TH CWEBP 1 "September 02, 2016"
.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
@ -98,7 +98,8 @@ Crop the source to a rectangle with top\-left corner at coordinates
This cropping area must be fully contained within the source rectangle. This cropping area must be fully contained within the source rectangle.
.TP .TP
.B \-mt .B \-mt
Use multi\-threading for encoding, if possible. Use multi\-threading for encoding, if possible. This option is only effective
when using lossy compression on a source with a transparency channel.
.TP .TP
.B \-low_memory .B \-low_memory
Reduce memory usage of lossy encoding by saving four times the compressed Reduce memory usage of lossy encoding by saving four times the compressed
@ -165,10 +166,6 @@ Use strong filtering (if filtering is being used thanks to the
Disable strong filtering (if filtering is being used thanks to the Disable strong filtering (if filtering is being used thanks to the
\fB\-f\fP option) and use simple filtering instead. \fB\-f\fP option) and use simple filtering instead.
.TP .TP
.B \-sharp_yuv
Use more accurate and sharper RGB->YUV conversion if needed. Note that this
process is slower than the default 'fast' RGB->YUV conversion.
.TP
.BI \-sns " int .BI \-sns " int
Specify the amplitude of the spatial noise shaping. Spatial noise shaping Specify the amplitude of the spatial noise shaping. Spatial noise shaping
(or \fBsns\fP for short) refers to a general collection of built\-in algorithms (or \fBsns\fP for short) refers to a general collection of built\-in algorithms

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH GIF2WEBP 1 "January 25, 2018" .TH GIF2WEBP 1 "June 23, 2016"
.SH NAME .SH NAME
gif2webp \- Convert a GIF image to WebP gif2webp \- Convert a GIF image to WebP
.SH SYNOPSIS .SH SYNOPSIS
@ -20,12 +20,6 @@ Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will
perform conversion but only report statistics. perform conversion but only report statistics.
Using "\-" as output name will direct output to 'stdout'. Using "\-" as output name will direct output to 'stdout'.
.TP .TP
.BI \-\- " string
Explicitly specify the input file. This option is useful if the input
file starts with an '\-' for instance. This option must appear \fBlast\fP.
Any other options afterward will be ignored. If the input file is "\-",
the data will be read from \fIstdin\fP instead of a file.
.TP
.B \-h, \-help .B \-h, \-help
Usage information. Usage information.
.TP .TP
@ -74,9 +68,8 @@ Specify the minimum and maximum distance between consecutive key frames
some key frames into the output animation as needed so that this criteria is some key frames into the output animation as needed so that this criteria is
satisfied. satisfied.
.br .br
A 'kmax' value of 0 will turn off insertion of key frames. A 'kmax' value of 1 A 'kmin' value of 0 will turn off insertion of key frames. A 'kmax' value of 0
will result in all frames being key frames. 'kmin' value is not taken into will result in all frames being key frames.
account in both these special cases.
Typical values are in the range 3 to 30. Default values are kmin = 9, Typical values are in the range 3 to 30. Default values are kmin = 9,
kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression. kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression.
.br .br
@ -114,11 +107,8 @@ the value the smoother the picture will appear. Typical values are usually in
the range of 20 to 50. the range of 20 to 50.
.TP .TP
.B \-mt .B \-mt
Use multi-threading for encoding, if possible. Use multi-threading for encoding, if possible. This option is only effective
.TP when using lossy compression.
.B \-loop_compatibility
If enabled, handle the loop information in a compatible fashion for Chrome
version prior to M62 (inclusive) and Firefox.
.TP .TP
.B \-v .B \-v
Print extra information. Print extra information.
@ -143,8 +133,6 @@ gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp
gif2webp \-lossy \-f 50 picture.gif \-o picture.webp gif2webp \-lossy \-f 50 picture.gif \-o picture.webp
.br .br
gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif
.br
cat picture.gif | gif2webp \-o \- \-\- \- > output.webp
.SH AUTHORS .SH AUTHORS
\fBgif2webp\fP is a part of libwebp and was written by the WebP team. \fBgif2webp\fP is a part of libwebp and was written by the WebP team.

View File

@ -1,105 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.TH IMG2WEBP 1 "April 3, 2018"
.SH NAME
img2webp \- create animated WebP file from a sequence of input images.
.SH SYNOPSIS
.B img2webp
[file_level_options] [files] [per_frame_options...]
.br
.B img2webp argument_file_name
.br
.SH DESCRIPTION
This manual page documents the
.B img2webp
command.
.PP
\fBimg2webp\fP compresses a sequence of images using the animated WebP format.
Input images can either be PNG, JPEG, TIFF or WebP.
If a single file name (not starting with the character '\-') is supplied as
the argument, the command line argument are actually tokenized from this file.
This allows for easy scripting or using large number of arguments.
.SH FILE-LEVEL OPTIONS
The file-level options are applied at the beginning of the compression process,
before the input frames are read.
.TP
.BI \-o " string
Specify the name of the output WebP file.
.TP
.BI \-min_size
Encode images to achieve smallest size. This disables key frame insertion and
picks the parameters resulting in smallest output for each frame. It uses
lossless compression by default, but can be combined with \-q, \-m, \-lossy or
\-mixed options.
.TP
.BI \-kmin " int
.TP
.BI \-kmax " int
Specify the minimum and maximum distance between consecutive key frames
(independently decodable frames) in the output animation. The tool will insert
some key frames into the output animation as needed so that this criteria is
satisfied.
.br
.B \-mixed
Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically. This global
option disables the local option \fB-lossy\fP and \fB-lossless\fP .
.TP
.BI \-loop " int
Specifies the number of times the animation should loop. Using '0'
means 'loop indefinitely'.
.TP
.BI \-v
Be more verbose.
.TP
.B \-h, \-help
A short usage summary.
.TP
.B \-version
Print the version numbers of the relevant libraries used.
.SH PER-FRAME OPTIONS
The per-frame options are applied for the images following as arguments in the
command line. They can be modified any number of times preceding each particular
input image.
.TP
.BI \-d " int
Specify the image duration in milliseconds.
.TP
.B \-lossless, \-lossy
Compress the next image(s) using lossless or lossy compression mode. The
default mode is lossless.
.TP
.BI \-q " float
Specify the compression factor between 0 and 100. The default is 75.
.TP
.BI \-m " int
Specify the compression method to use. This parameter controls the
trade off between encoding speed and the compressed file size and quality.
Possible values range from 0 to 6. Default value is 4.
.SH EXAMPLE
img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp
.br
.SH BUGS
Please report all bugs to the issue tracker:
https://bugs.chromium.org/p/webp
.br
Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting\-patches/
.SH AUTHORS
\fBimg2webp\fP is a part of libwebp and was written by the WebP team.
.br
The latest source tree is available at
https://chromium.googlesource.com/webm/libwebp
.PP
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others).
.SH SEE ALSO
.BR webpmux (1),
.BR gif2webp (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH VWEBP 1 "November 25, 2016" .TH VWEBP 1 "June 23, 2016"
.SH NAME .SH NAME
vwebp \- decompress a WebP file and display it in a window vwebp \- decompress a WebP file and display it in a window
.SH SYNOPSIS .SH SYNOPSIS
@ -59,9 +59,6 @@ Toggle use of color profile.
.B 'i' .B 'i'
Overlay file information. Overlay file information.
.TP .TP
.B 'd'
Disable blending and disposal process, for debugging purposes.
.TP
.B 'q' / 'Q' / ESC .B 'q' / 'Q' / ESC
Quit. Quit.

View File

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

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "December 1, 2017" .TH WEBPMUX 1 "June 23, 2016"
.SH NAME .SH NAME
webpmux \- create animated WebP files from non\-animated WebP images, extract webpmux \- create animated WebP files from non\-animated WebP images, extract
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile. frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
@ -35,21 +35,12 @@ frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
.I OUTPUT .I OUTPUT
.RE .RE
.br .br
.B webpmux \-duration
.I DURATION OPTIONS
.B [ \-duration ... ]
.I INPUT
.B \-o
.I OUTPUT
.br
.B webpmux \-info .B webpmux \-info
.I INPUT .I INPUT
.br .br
.B webpmux [\-h|\-help] .B webpmux [\-h|\-help]
.br .br
.B webpmux \-version .B webpmux \-version
.br
.B webpmux argument_file_name
.SH DESCRIPTION .SH DESCRIPTION
This manual page documents the This manual page documents the
.B webpmux .B webpmux
@ -57,9 +48,6 @@ command.
.PP .PP
\fBwebpmux\fP can be used to create/extract from animated WebP files, as well as \fBwebpmux\fP can be used to create/extract from animated WebP files, as well as
to add/extract/strip XMP/EXIF metadata and ICC profile. to add/extract/strip XMP/EXIF metadata and ICC profile.
If a single file name (not starting with the character '\-') is supplied as
the argument, the command line argument are actually tokenized from this file.
This allows for easy scripting or using large number of arguments.
.SH OPTIONS .SH OPTIONS
.SS GET_OPTIONS (\-get): .SS GET_OPTIONS (\-get):
.TP .TP
@ -103,42 +91,6 @@ Strip EXIF metadata.
.B xmp .B xmp
Strip XMP metadata. Strip XMP metadata.
.SS DURATION_OPTIONS (\-duration)
Amend the duration of a specific interval of frames. This option is only
effective on animated WebP and has no effect on a single-frame file.
.TP
.I duration[,start[,end]]
Where:
.br
.B duration
is the duration for the interval in milliseconds (mandatory).
Must be non-negative.
.br
.B start
is the starting frame index of the interval (optional).
.br
.B end
is the ending frame index (inclusive) of the interval (optional).
.TP
The three typical usages of this option are:
.br
.B -duration d
set the duration to 'd' for the whole animation.
.br
.B -duration d,f
set the duration of frame 'f' to 'd'.
.br
.B -duration d,start,end
set the duration to 'd' for the whole [start,end] interval.
.TP
.P
Note that the frames outside of the [start, end] interval will remain untouched.
The 'end' value '0' has the special meaning 'last frame of the animation'.
.TP
.I Reminder:
frame indexing starts at '1'.
.br
.SS FRAME_OPTIONS (\-frame) .SS FRAME_OPTIONS (\-frame)
Create an animated WebP file from multiple (non\-animated) WebP images. Create an animated WebP file from multiple (non\-animated) WebP images.
.TP .TP

View File

@ -1,4 +1,4 @@
# The mux and demux libraries depend on libwebp, thus the '.' to force # The mux, demux and extras libraries depend on libwebp, thus the '.' to force
# the build order so it's available to them. # the build order so it's available to them.
SUBDIRS = dec enc dsp utils . SUBDIRS = dec enc dsp utils .
if WANT_MUX if WANT_MUX
@ -7,6 +7,9 @@ endif
if WANT_DEMUX if WANT_DEMUX
SUBDIRS += demux SUBDIRS += demux
endif endif
if WANT_EXTRAS
SUBDIRS += extras
endif
lib_LTLIBRARIES = libwebp.la lib_LTLIBRARIES = libwebp.la
@ -22,7 +25,6 @@ commondir = $(includedir)/webp
libwebp_la_SOURCES = libwebp_la_SOURCES =
libwebpinclude_HEADERS = libwebpinclude_HEADERS =
libwebpinclude_HEADERS += webp/encode.h libwebpinclude_HEADERS += webp/encode.h
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += webp/format_constants.h noinst_HEADERS += webp/format_constants.h
@ -36,7 +38,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:2:0 libwebp_la_LDFLAGS = -no-undefined -version-info 6:2:0
libwebpincludedir = $(includedir)/webp libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc pkgconfig_DATA = libwebp.pc
@ -48,7 +50,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:2:0 libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 2:2:0
pkgconfig_DATA += libwebpdecoder.pc pkgconfig_DATA += libwebpdecoder.pc
endif endif

View File

@ -1,23 +1,22 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
noinst_LTLIBRARIES = libwebpdecode.la noinst_LTLIBRARIES = libwebpdecode.la
libwebpdecode_la_SOURCES = libwebpdecode_la_SOURCES =
libwebpdecode_la_SOURCES += alpha_dec.c libwebpdecode_la_SOURCES += alpha.c
libwebpdecode_la_SOURCES += alphai_dec.h libwebpdecode_la_SOURCES += alphai.h
libwebpdecode_la_SOURCES += buffer_dec.c libwebpdecode_la_SOURCES += buffer.c
libwebpdecode_la_SOURCES += common_dec.h libwebpdecode_la_SOURCES += common.h
libwebpdecode_la_SOURCES += vp8_dec.h libwebpdecode_la_SOURCES += decode_vp8.h
libwebpdecode_la_SOURCES += frame_dec.c libwebpdecode_la_SOURCES += frame.c
libwebpdecode_la_SOURCES += idec_dec.c libwebpdecode_la_SOURCES += idec.c
libwebpdecode_la_SOURCES += io_dec.c libwebpdecode_la_SOURCES += io.c
libwebpdecode_la_SOURCES += quant_dec.c libwebpdecode_la_SOURCES += quant.c
libwebpdecode_la_SOURCES += tree_dec.c libwebpdecode_la_SOURCES += tree.c
libwebpdecode_la_SOURCES += vp8_dec.c libwebpdecode_la_SOURCES += vp8.c
libwebpdecode_la_SOURCES += vp8i_dec.h libwebpdecode_la_SOURCES += vp8i.h
libwebpdecode_la_SOURCES += vp8l_dec.c libwebpdecode_la_SOURCES += vp8l.c
libwebpdecode_la_SOURCES += vp8li_dec.h libwebpdecode_la_SOURCES += vp8li.h
libwebpdecode_la_SOURCES += webp_dec.c libwebpdecode_la_SOURCES += webp.c
libwebpdecode_la_SOURCES += webpi_dec.h libwebpdecode_la_SOURCES += webpi.h
libwebpdecodeinclude_HEADERS = libwebpdecodeinclude_HEADERS =
libwebpdecodeinclude_HEADERS += ../webp/decode.h libwebpdecodeinclude_HEADERS += ../webp/decode.h
@ -25,5 +24,5 @@ libwebpdecodeinclude_HEADERS += ../webp/types.h
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h noinst_HEADERS += ../webp/format_constants.h
libwebpdecode_la_CPPFLAGS = $(AM_CPPFLAGS) libwebpdecode_la_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
libwebpdecodeincludedir = $(includedir)/webp libwebpdecodeincludedir = $(includedir)/webp

View File

@ -12,13 +12,13 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "./alphai.h"
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/dec/vp8li_dec.h" #include "./vp8li.h"
#include "src/dsp/dsp.h" #include "../dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h" #include "../utils/quant_levels_dec.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
#include "src/webp/format_constants.h" #include "../webp/format_constants.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ALPHDecoder object. // ALPHDecoder object.

View File

@ -11,11 +11,11 @@
// //
// Author: Urvang (urvang@google.com) // Author: Urvang (urvang@google.com)
#ifndef WEBP_DEC_ALPHAI_DEC_H_ #ifndef WEBP_DEC_ALPHAI_H_
#define WEBP_DEC_ALPHAI_DEC_H_ #define WEBP_DEC_ALPHAI_H_
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/utils/filters_utils.h" #include "../utils/filters.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_ALPHAI_DEC_H_ */ #endif /* WEBP_DEC_ALPHAI_H_ */

View File

@ -13,15 +13,15 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// WebPDecBuffer // WebPDecBuffer
// Number of bytes per pixel for the different color-spaces. // Number of bytes per pixel for the different color-spaces.
static const uint8_t kModeBpp[MODE_LAST] = { static const int kModeBpp[MODE_LAST] = {
3, 4, 3, 4, 4, 2, 2, 3, 4, 3, 4, 4, 2, 2,
4, 4, 4, 2, // pre-multiplied modes 4, 4, 4, 2, // pre-multiplied modes
1, 1 }; 1, 1 };
@ -36,7 +36,7 @@ static int IsValidColorspace(int webp_csp_mode) {
// strictly speaking, the very last (or first, if flipped) row // strictly speaking, the very last (or first, if flipped) row
// doesn't require padding. // doesn't require padding.
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \ #define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
((uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)) (uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1; int ok = 1;
@ -74,8 +74,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks } else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA; const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride); const int stride = abs(buf->stride);
const uint64_t size = const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size); ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]); ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL); ok &= (buf->rgba != NULL);
@ -99,14 +98,9 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
uint64_t uv_size = 0, a_size = 0, total_size; uint64_t uv_size = 0, a_size = 0, total_size;
// We need memory and it hasn't been allocated yet. // We need memory and it hasn't been allocated yet.
// => initialize output buffer, now that dimensions are known. // => initialize output buffer, now that dimensions are known.
int stride; const int stride = w * kModeBpp[mode];
uint64_t size; const uint64_t size = (uint64_t)stride * h;
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
return VP8_STATUS_INVALID_PARAM;
}
stride = w * kModeBpp[mode];
size = (uint64_t)stride * h;
if (!WebPIsRGBMode(mode)) { if (!WebPIsRGBMode(mode)) {
uv_stride = (w + 1) / 2; uv_stride = (w + 1) / 2;
uv_size = (uint64_t)uv_stride * ((h + 1) / 2); uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
@ -175,11 +169,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
return VP8_STATUS_OK; return VP8_STATUS_OK;
} }
VP8StatusCode WebPAllocateDecBuffer(int width, int height, VP8StatusCode WebPAllocateDecBuffer(int w, int h,
const WebPDecoderOptions* const options, const WebPDecoderOptions* const options,
WebPDecBuffer* const buffer) { WebPDecBuffer* const out) {
VP8StatusCode status; VP8StatusCode status;
if (buffer == NULL || width <= 0 || height <= 0) { if (out == NULL || w <= 0 || h <= 0) {
return VP8_STATUS_INVALID_PARAM; return VP8_STATUS_INVALID_PARAM;
} }
if (options != NULL) { // First, apply options if there is any. if (options != NULL) { // First, apply options if there is any.
@ -188,39 +182,33 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const int ch = options->crop_height; const int ch = options->crop_height;
const int x = options->crop_left & ~1; const int x = options->crop_left & ~1;
const int y = options->crop_top & ~1; const int y = options->crop_top & ~1;
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
x + cw > width || y + ch > height) {
return VP8_STATUS_INVALID_PARAM; // out of frame boundary. return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
} }
width = cw; w = cw;
height = ch; h = ch;
} }
if (options->use_scaling) { if (options->use_scaling) {
#if !defined(WEBP_REDUCE_SIZE)
int scaled_width = options->scaled_width; int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height; int scaled_height = options->scaled_height;
if (!WebPRescalerGetScaledDimensions( if (!WebPRescalerGetScaledDimensions(
width, height, &scaled_width, &scaled_height)) { w, h, &scaled_width, &scaled_height)) {
return VP8_STATUS_INVALID_PARAM; return VP8_STATUS_INVALID_PARAM;
} }
width = scaled_width; w = scaled_width;
height = scaled_height; h = scaled_height;
#else
return VP8_STATUS_INVALID_PARAM; // rescaling not supported
#endif
} }
} }
buffer->width = width; out->width = w;
buffer->height = height; out->height = h;
// Then, allocate buffer for real. // Then, allocate buffer for real.
status = AllocateBuffer(buffer); status = AllocateBuffer(out);
if (status != VP8_STATUS_OK) return status; if (status != VP8_STATUS_OK) return status;
// Use the stride trick if vertical flip is needed. // Use the stride trick if vertical flip is needed.
if (options != NULL && options->flip) { if (options != NULL && options->flip) {
status = WebPFlipBuffer(buffer); status = WebPFlipBuffer(out);
} }
return status; return status;
} }

View File

@ -11,8 +11,8 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DEC_COMMON_DEC_H_ #ifndef WEBP_DEC_COMMON_H_
#define WEBP_DEC_COMMON_DEC_H_ #define WEBP_DEC_COMMON_H_
// intra prediction modes // intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes enum { B_DC_PRED = 0, // 4x4 modes
@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11 NUM_PROBAS = 11
}; };
#endif // WEBP_DEC_COMMON_DEC_H_ #endif // WEBP_DEC_COMMON_H_

View File

@ -11,10 +11,10 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DEC_VP8_DEC_H_ #ifndef WEBP_WEBP_DECODE_VP8_H_
#define WEBP_DEC_VP8_DEC_H_ #define WEBP_WEBP_DECODE_VP8_H_
#include "src/webp/decode.h" #include "../webp/decode.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -33,7 +33,7 @@ extern "C" {
// /* customize io's functions (setup()/put()/teardown()) if needed. */ // /* customize io's functions (setup()/put()/teardown()) if needed. */
// //
// VP8Decoder* dec = VP8New(); // VP8Decoder* dec = VP8New();
// int ok = VP8Decode(dec, &io); // bool ok = VP8Decode(dec);
// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec)); // if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
// VP8Delete(dec); // VP8Delete(dec);
// return ok; // return ok;
@ -157,24 +157,24 @@ void VP8Delete(VP8Decoder* const dec);
// Miscellaneous VP8/VP8L bitstream probing functions. // Miscellaneous VP8/VP8L bitstream probing functions.
// Returns true if the next 3 bytes in data contain the VP8 signature. // Returns true if the next 3 bytes in data contain the VP8 signature.
WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size); WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
// Validates the VP8 data-header and retrieves basic header information viz // Validates the VP8 data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. *width/*height // width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL. // can be passed NULL.
WEBP_EXTERN int VP8GetInfo( WEBP_EXTERN(int) VP8GetInfo(
const uint8_t* data, const uint8_t* data,
size_t data_size, // data available so far size_t data_size, // data available so far
size_t chunk_size, // total data size expected in the chunk size_t chunk_size, // total data size expected in the chunk
int* const width, int* const height); int* const width, int* const height);
// Returns true if the next byte(s) in data is a VP8L signature. // Returns true if the next byte(s) in data is a VP8L signature.
WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size); WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
// Validates the VP8L data-header and retrieves basic header information viz // Validates the VP8L data-header and retrieves basic header information viz
// width, height and alpha. Returns 0 in case of formatting error. // width, height and alpha. Returns 0 in case of formatting error.
// width/height/has_alpha can be passed NULL. // width/height/has_alpha can be passed NULL.
WEBP_EXTERN int VP8LGetInfo( WEBP_EXTERN(int) VP8LGetInfo(
const uint8_t* data, size_t data_size, // data available so far const uint8_t* data, size_t data_size, // data available so far
int* const width, int* const height, int* const has_alpha); int* const width, int* const height, int* const has_alpha);
@ -182,4 +182,4 @@ WEBP_EXTERN int VP8LGetInfo(
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8_DEC_H_ */ #endif /* WEBP_WEBP_DECODE_VP8_H_ */

View File

@ -12,13 +12,13 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main reconstruction function. // Main reconstruction function.
static const uint16_t kScan[16] = { static const int kScan[16] = {
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
@ -320,7 +320,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
#define MIN_DITHER_AMP 4 #define MIN_DITHER_AMP 4
#define DITHER_AMP_TAB_SIZE 12 #define DITHER_AMP_TAB_SIZE 12
static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = { static const int kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
// roughly, it's dqm->uv_mat_[1] // roughly, it's dqm->uv_mat_[1]
8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
}; };
@ -400,9 +400,7 @@ static void DitherRow(VP8Decoder* const dec) {
#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB #define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB
// Finalize and transmit a complete row. Return false in case of user-abort. // Finalize and transmit a complete row. Return false in case of user-abort.
static int FinishRow(void* arg1, void* arg2) { static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
VP8Decoder* const dec = (VP8Decoder*)arg1;
VP8Io* const io = (VP8Io*)arg2;
int ok = 1; int ok = 1;
const VP8ThreadContext* const ctx = &dec->thread_ctx_; const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const int cache_id = ctx->id_; const int cache_id = ctx->id_;
@ -450,9 +448,10 @@ static int FinishRow(void* arg1, void* arg2) {
if (y_end > io->crop_bottom) { if (y_end > io->crop_bottom) {
y_end = io->crop_bottom; // make sure we don't overflow on last row. y_end = io->crop_bottom; // make sure we don't overflow on last row.
} }
// If dec->alpha_data_ is not NULL, we have some alpha plane present.
io->a = NULL; io->a = NULL;
if (dec->alpha_data_ != NULL && y_start < y_end) { if (dec->alpha_data_ != NULL && y_start < y_end) {
// TODO(skal): testing presence of alpha with dec->alpha_data_ is not a
// good idea.
io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start); io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
if (io->a == NULL) { if (io->a == NULL) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
@ -559,6 +558,7 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
if (io->bypass_filtering) { if (io->bypass_filtering) {
dec->filter_type_ = 0; dec->filter_type_ = 0;
} }
// TODO(skal): filter type / strength / sharpness forcing
// Define the area where we can skip in-loop filtering, in case of cropping. // Define the area where we can skip in-loop filtering, in case of cropping.
// //
@ -569,6 +569,8 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// Means: there's a dependency chain that goes all the way up to the // Means: there's a dependency chain that goes all the way up to the
// top-left corner of the picture (MB #0). We must filter all the previous // top-left corner of the picture (MB #0). We must filter all the previous
// macroblocks. // macroblocks.
// TODO(skal): add an 'approximate_decoding' option, that won't produce
// a 1:1 bit-exactness for complex filtering?
{ {
const int extra_pixels = kFilterExtraRows[dec->filter_type_]; const int extra_pixels = kFilterExtraRows[dec->filter_type_];
if (dec->filter_type_ == 2) { if (dec->filter_type_ == 2) {
@ -649,7 +651,7 @@ static int InitThreadContext(VP8Decoder* const dec) {
} }
worker->data1 = dec; worker->data1 = dec;
worker->data2 = (void*)&dec->thread_ctx_.io_; worker->data2 = (void*)&dec->thread_ctx_.io_;
worker->hook = FinishRow; worker->hook = (WebPWorkerHook)FinishRow;
dec->num_caches_ = dec->num_caches_ =
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
} else { } else {
@ -721,12 +723,12 @@ static int AllocateMemory(VP8Decoder* const dec) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"no memory during frame initialization."); "no memory during frame initialization.");
} }
// down-cast is ok, thanks to WebPSafeMalloc() above. // down-cast is ok, thanks to WebPSafeAlloc() above.
dec->mem_size_ = (size_t)needed; dec->mem_size_ = (size_t)needed;
} }
mem = (uint8_t*)dec->mem_; mem = (uint8_t*)dec->mem_;
dec->intra_t_ = mem; dec->intra_t_ = (uint8_t*)mem;
mem += intra_pred_mode_size; mem += intra_pred_mode_size;
dec->yuv_t_ = (VP8TopSamples*)mem; dec->yuv_t_ = (VP8TopSamples*)mem;
@ -748,7 +750,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
mem = (uint8_t*)WEBP_ALIGN(mem); mem = (uint8_t*)WEBP_ALIGN(mem);
assert((yuv_size & WEBP_ALIGN_CST) == 0); assert((yuv_size & WEBP_ALIGN_CST) == 0);
dec->yuv_b_ = mem; dec->yuv_b_ = (uint8_t*)mem;
mem += yuv_size; mem += yuv_size;
dec->mb_data_ = (VP8MBData*)mem; dec->mb_data_ = (VP8MBData*)mem;
@ -764,7 +766,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
const int extra_rows = kFilterExtraRows[dec->filter_type_]; const int extra_rows = kFilterExtraRows[dec->filter_type_];
const int extra_y = extra_rows * dec->cache_y_stride_; const int extra_y = extra_rows * dec->cache_y_stride_;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_; const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
dec->cache_y_ = mem + extra_y; dec->cache_y_ = ((uint8_t*)mem) + extra_y;
dec->cache_u_ = dec->cache_y_ dec->cache_u_ = dec->cache_y_
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv; + 16 * num_caches * dec->cache_y_stride_ + extra_uv;
dec->cache_v_ = dec->cache_u_ dec->cache_v_ = dec->cache_u_
@ -774,7 +776,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
mem += cache_size; mem += cache_size;
// alpha plane // alpha plane
dec->alpha_plane_ = alpha_size ? mem : NULL; dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
mem += alpha_size; mem += alpha_size;
assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_); assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);

View File

@ -15,10 +15,10 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "./alphai.h"
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
// In append mode, buffer allocations increase as multiples of this value. // In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2. // Needs to be a power of 2.
@ -140,9 +140,10 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (NeedCompressedAlpha(idec)) { if (NeedCompressedAlpha(idec)) {
ALPHDecoder* const alph_dec = dec->alph_dec_; ALPHDecoder* const alph_dec = dec->alph_dec_;
dec->alpha_data_ += offset; dec->alpha_data_ += offset;
if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) { if (alph_dec != NULL) {
if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
assert(alph_vp8l_dec != NULL);
assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
dec->alpha_data_ + ALPHA_HEADER_LEN, dec->alpha_data_ + ALPHA_HEADER_LEN,
@ -282,8 +283,10 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) { if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors. VP8Io* const io = &idec->io_;
VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); if (io->teardown != NULL) {
io->teardown(io);
}
} }
idec->state_ = STATE_ERROR; idec->state_ = STATE_ERROR;
return error; return error;
@ -448,10 +451,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8Io* const io = &idec->io_; VP8Io* const io = &idec->io_;
// Make sure partition #0 has been read before, to set dec to ready_. assert(dec->ready_);
if (!dec->ready_) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
if (idec->last_mb_y_ != dec->mb_y_) { if (idec->last_mb_y_ != dec->mb_y_) {
if (!VP8ParseIntraModeRow(&dec->br_, dec)) { if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
@ -491,7 +491,6 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
} }
// Synchronize the thread and check for errors. // Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) { if (!VP8ExitCritical(dec, io)) {
idec->state_ = STATE_ERROR; // prevent re-entry in IDecError
return IDecError(idec, VP8_STATUS_USER_ABORT); return IDecError(idec, VP8_STATUS_USER_ABORT);
} }
dec->ready_ = 0; dec->ready_ = 0;
@ -572,10 +571,6 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
status = DecodePartition0(idec); status = DecodePartition0(idec);
} }
if (idec->state_ == STATE_VP8_DATA) { if (idec->state_ == STATE_VP8_DATA) {
const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
if (dec == NULL) {
return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
}
status = DecodeRemaining(idec); status = DecodeRemaining(idec);
} }
if (idec->state_ == STATE_VP8L_HEADER) { if (idec->state_ == STATE_VP8L_HEADER) {
@ -678,12 +673,12 @@ void WebPIDelete(WebPIDecoder* idec) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Wrapper toward WebPINewDecoder // Wrapper toward WebPINewDecoder
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer, WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
size_t output_buffer_size, int output_stride) { size_t output_buffer_size, int output_stride) {
const int is_external_memory = (output_buffer != NULL) ? 1 : 0; const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
WebPIDecoder* idec; WebPIDecoder* idec;
if (csp >= MODE_YUV) return NULL; if (mode >= MODE_YUV) return NULL;
if (is_external_memory == 0) { // Overwrite parameters to sane values. if (is_external_memory == 0) { // Overwrite parameters to sane values.
output_buffer_size = 0; output_buffer_size = 0;
output_stride = 0; output_stride = 0;
@ -694,7 +689,7 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
} }
idec = WebPINewDecoder(NULL); idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL; if (idec == NULL) return NULL;
idec->output_.colorspace = csp; idec->output_.colorspace = mode;
idec->output_.is_external_memory = is_external_memory; idec->output_.is_external_memory = is_external_memory;
idec->output_.u.RGBA.rgba = output_buffer; idec->output_.u.RGBA.rgba = output_buffer;
idec->output_.u.RGBA.stride = output_stride; idec->output_.u.RGBA.stride = output_stride;

View File

@ -13,11 +13,11 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8i_dec.h" #include "../dec/vp8i.h"
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/dsp/dsp.h" #include "../dsp/dsp.h"
#include "src/dsp/yuv.h" #include "../dsp/yuv.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main YUV<->RGB conversion functions // Main YUV<->RGB conversion functions
@ -212,7 +212,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
int num_rows; int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1) #ifdef WEBP_SWAP_16BIT_CSP
uint8_t* alpha_dst = base_rgba; uint8_t* alpha_dst = base_rgba;
#else #else
uint8_t* alpha_dst = base_rgba + 1; uint8_t* alpha_dst = base_rgba + 1;
@ -241,7 +241,6 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// YUV rescaling (no final RGB conversion needed) // YUV rescaling (no final RGB conversion needed)
#if !defined(WEBP_REDUCE_SIZE)
static int Rescale(const uint8_t* src, int src_stride, static int Rescale(const uint8_t* src, int src_stride,
int new_lines, WebPRescaler* const wrk) { int new_lines, WebPRescaler* const wrk) {
int num_lines_out = 0; int num_lines_out = 0;
@ -257,7 +256,7 @@ static int Rescale(const uint8_t* src, int src_stride,
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
const int mb_h = io->mb_h; const int mb_h = io->mb_h;
const int uv_mb_h = (mb_h + 1) >> 1; const int uv_mb_h = (mb_h + 1) >> 1;
WebPRescaler* const scaler = p->scaler_y; WebPRescaler* const scaler = &p->scaler_y;
int num_lines_out = 0; int num_lines_out = 0;
if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
// Before rescaling, we premultiply the luma directly into the io->y // Before rescaling, we premultiply the luma directly into the io->y
@ -268,28 +267,29 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
io->a, io->width, io->mb_w, mb_h, 0); io->a, io->width, io->mb_w, mb_h, 0);
} }
num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler); num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u); Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v); Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
return num_lines_out; return num_lines_out;
} }
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
int expected_num_lines_out) { int expected_num_lines_out) {
const WebPYUVABuffer* const buf = &p->output->u.YUVA; const WebPYUVABuffer* const buf = &p->output->u.YUVA;
uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride;
if (io->a != NULL) { if (io->a != NULL) {
uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride; uint8_t* dst_y = buf->y + p->last_y * buf->y_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); const uint8_t* src_a = buf->a + p->last_y * buf->a_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
(void)expected_num_lines_out;
assert(expected_num_lines_out == num_lines_out); assert(expected_num_lines_out == num_lines_out);
if (num_lines_out > 0) { // unmultiply the Y if (num_lines_out > 0) { // unmultiply the Y
WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride, WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride,
p->scaler_a->dst_width, num_lines_out, 1); p->scaler_a.dst_width, num_lines_out, 1);
} }
} else if (buf->a != NULL) { } else if (buf->a != NULL) {
// the user requested alpha, but there is none, set it to opaque. // the user requested alpha, but there is none, set it to opaque.
assert(p->last_y + expected_num_lines_out <= io->scaled_height); assert(p->last_y + expected_num_lines_out <= io->scaled_height);
FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out, FillAlphaPlane(buf->a + p->last_y * buf->a_stride,
buf->a_stride); io->scaled_width, expected_num_lines_out, buf->a_stride);
} }
return 0; return 0;
} }
@ -305,42 +305,31 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_in_height = (io->mb_h + 1) >> 1; const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
size_t tmp_size, rescaler_size; size_t tmp_size;
rescaler_t* work; rescaler_t* work;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work); tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) { if (has_alpha) {
tmp_size += work_size * sizeof(*work); tmp_size += work_size * sizeof(*work);
} }
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; p->memory = WebPSafeMalloc(1ULL, tmp_size);
p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; work = (rescaler_t*)p->memory;
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1, buf->y, out_width, out_height, buf->y_stride, 1,
work); work);
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
work + work_size); work + work_size);
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
work + work_size + uv_work_size); work + work_size + uv_work_size);
p->emit = EmitRescaledYUV; p->emit = EmitRescaledYUV;
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1, buf->a, out_width, out_height, buf->a_stride, 1,
work + work_size + 2 * uv_work_size); work + work_size + 2 * uv_work_size);
p->emit_alpha = EmitRescaledAlphaYUV; p->emit_alpha = EmitRescaledAlphaYUV;
@ -360,15 +349,15 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
int num_lines_out = 0; int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position // For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test. // U/V can be +1/-1 line from the Y one. Hence the double test.
while (WebPRescalerHasPendingOutput(p->scaler_y) && while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
WebPRescalerHasPendingOutput(p->scaler_u)) { WebPRescalerHasPendingOutput(&p->scaler_u)) {
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
assert(p->scaler_u->y_accum == p->scaler_v->y_accum); assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
WebPRescalerExportRow(p->scaler_y); WebPRescalerExportRow(&p->scaler_y);
WebPRescalerExportRow(p->scaler_u); WebPRescalerExportRow(&p->scaler_u);
WebPRescalerExportRow(p->scaler_v); WebPRescalerExportRow(&p->scaler_v);
convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst, convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
dst, p->scaler_y->dst_width); dst, p->scaler_y.dst_width);
dst += buf->stride; dst += buf->stride;
++num_lines_out; ++num_lines_out;
} }
@ -382,15 +371,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = 0; int num_lines_out = 0;
while (j < mb_h) { while (j < mb_h) {
const int y_lines_in = const int y_lines_in =
WebPRescalerImport(p->scaler_y, mb_h - j, WebPRescalerImport(&p->scaler_y, mb_h - j,
io->y + j * io->y_stride, io->y_stride); io->y + j * io->y_stride, io->y_stride);
j += y_lines_in; j += y_lines_in;
if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) {
const int u_lines_in = const int u_lines_in =
WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j, WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
io->u + uv_j * io->uv_stride, io->uv_stride); io->u + uv_j * io->uv_stride, io->uv_stride);
const int v_lines_in = const int v_lines_in =
WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j, WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
io->v + uv_j * io->uv_stride, io->uv_stride); io->v + uv_j * io->uv_stride, io->uv_stride);
(void)v_lines_in; // remove a gcc warning (void)v_lines_in; // remove a gcc warning
assert(u_lines_in == v_lines_in); assert(u_lines_in == v_lines_in);
@ -411,13 +400,13 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
int num_lines_out = 0; int num_lines_out = 0;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t non_opaque = 0; uint32_t non_opaque = 0;
const int width = p->scaler_a->dst_width; const int width = p->scaler_a.dst_width;
while (WebPRescalerHasPendingOutput(p->scaler_a) && while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
num_lines_out < max_lines_out) { num_lines_out < max_lines_out) {
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(p->scaler_a); WebPRescalerExportRow(&p->scaler_a);
non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0); non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0);
dst += buf->stride; dst += buf->stride;
++num_lines_out; ++num_lines_out;
} }
@ -432,25 +421,25 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
int max_lines_out) { int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride; uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1) #ifdef WEBP_SWAP_16BIT_CSP
uint8_t* alpha_dst = base_rgba; uint8_t* alpha_dst = base_rgba;
#else #else
uint8_t* alpha_dst = base_rgba + 1; uint8_t* alpha_dst = base_rgba + 1;
#endif #endif
int num_lines_out = 0; int num_lines_out = 0;
const WEBP_CSP_MODE colorspace = p->output->colorspace; const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int width = p->scaler_a->dst_width; const int width = p->scaler_a.dst_width;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t alpha_mask = 0x0f; uint32_t alpha_mask = 0x0f;
while (WebPRescalerHasPendingOutput(p->scaler_a) && while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
num_lines_out < max_lines_out) { num_lines_out < max_lines_out) {
int i; int i;
assert(y_pos + num_lines_out < p->output->height); assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(p->scaler_a); WebPRescalerExportRow(&p->scaler_a);
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
// Fill in the alpha value (converted to 4 bits). // Fill in the alpha value (converted to 4 bits).
const uint32_t alpha_value = p->scaler_a->dst[i] >> 4; const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
alpha_mask &= alpha_value; alpha_mask &= alpha_value;
} }
@ -466,7 +455,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
int expected_num_out_lines) { int expected_num_out_lines) {
if (io->a != NULL) { if (io->a != NULL) {
WebPRescaler* const scaler = p->scaler_a; WebPRescaler* const scaler = &p->scaler_a;
int lines_left = expected_num_out_lines; int lines_left = expected_num_out_lines;
const int y_end = p->last_y + lines_left; const int y_end = p->last_y + lines_left;
while (lines_left > 0) { while (lines_left > 0) {
@ -488,9 +477,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t work_size = 2 * out_width; // scratch memory for one rescaler const size_t work_size = 2 * out_width; // scratch memory for one rescaler
rescaler_t* work; // rescalers work area rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
size_t tmp_size1, tmp_size2, total_size, rescaler_size; size_t tmp_size1, tmp_size2, total_size;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
tmp_size1 = 3 * work_size; tmp_size1 = 3 * work_size;
tmp_size2 = 3 * out_width; tmp_size2 = 3 * out_width;
@ -499,35 +486,26 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size2 += out_width; tmp_size2 += out_width;
} }
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp); total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST; p->memory = WebPSafeMalloc(1ULL, total_size);
p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
work = (rescaler_t*)p->memory; work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1); tmp = (uint8_t*)(work + tmp_size1);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1, tmp + 0 * out_width, out_width, out_height, 0, 1,
work + 0 * work_size); work + 0 * work_size);
WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1, tmp + 1 * out_width, out_width, out_height, 0, 1,
work + 1 * work_size); work + 1 * work_size);
WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height, WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1, tmp + 2 * out_width, out_width, out_height, 0, 1,
work + 2 * work_size); work + 2 * work_size);
p->emit = EmitRescaledRGB; p->emit = EmitRescaledRGB;
WebPInitYUV444Converters(); WebPInitYUV444Converters();
if (has_alpha) { if (has_alpha) {
WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h, WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1, tmp + 3 * out_width, out_width, out_height, 0, 1,
work + 3 * work_size); work + 3 * work_size);
p->emit_alpha = EmitRescaledAlphaRGB; p->emit_alpha = EmitRescaledAlphaRGB;
@ -542,8 +520,6 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 1; return 1;
} }
#endif // WEBP_REDUCE_SIZE
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Default custom functions // Default custom functions
@ -564,14 +540,10 @@ static int CustomSetup(VP8Io* io) {
WebPInitUpsamplers(); WebPInitUpsamplers();
} }
if (io->use_scaling) { if (io->use_scaling) {
#if !defined(WEBP_REDUCE_SIZE)
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
if (!ok) { if (!ok) {
return 0; // memory error return 0; // memory error
} }
#else
return 0; // rescaling support not compiled
#endif
} else { } else {
if (is_rgb) { if (is_rgb) {
WebPInitSamplers(); WebPInitSamplers();
@ -605,6 +577,9 @@ static int CustomSetup(VP8Io* io) {
} }
} }
if (is_rgb) {
VP8YUVInit();
}
return 1; return 1;
} }

View File

@ -11,7 +11,7 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
static WEBP_INLINE int clip(int v, int M) { static WEBP_INLINE int clip(int v, int M) {
return v < 0 ? 0 : v > M ? M : v; return v < 0 ? 0 : v > M ? M : v;

View File

@ -11,19 +11,12 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/utils/bit_reader_inl_utils.h" #include "../utils/bit_reader_inl.h"
#if !defined(USE_GENERIC_TREE) #define USE_GENERIC_TREE
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
#define USE_GENERIC_TREE 1 // ALTERNATE_CODE
#else
#define USE_GENERIC_TREE 0
#endif
#endif // USE_GENERIC_TREE
#if (USE_GENERIC_TREE == 1) #ifdef USE_GENERIC_TREE
static const int8_t kYModesIntra4[18] = { static const int8_t kYModesIntra4[18] = {
-B_DC_PRED, 1, -B_DC_PRED, 1,
-B_TM_PRED, 2, -B_TM_PRED, 2,
@ -321,7 +314,7 @@ static void ParseIntraMode(VP8BitReader* const br,
int x; int x;
for (x = 0; x < 4; ++x) { for (x = 0; x < 4; ++x) {
const uint8_t* const prob = kBModesProba[top[x]][ymode]; const uint8_t* const prob = kBModesProba[top[x]][ymode];
#if (USE_GENERIC_TREE == 1) #ifdef USE_GENERIC_TREE
// Generic tree-parsing // Generic tree-parsing
int i = kYModesIntra4[VP8GetBit(br, prob[0])]; int i = kYModesIntra4[VP8GetBit(br, prob[0])];
while (i > 0) { while (i > 0) {
@ -339,7 +332,7 @@ static void ParseIntraMode(VP8BitReader* const br,
(!VP8GetBit(br, prob[6]) ? B_LD_PRED : (!VP8GetBit(br, prob[6]) ? B_LD_PRED :
(!VP8GetBit(br, prob[7]) ? B_VL_PRED : (!VP8GetBit(br, prob[7]) ? B_VL_PRED :
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED))); (!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
#endif // USE_GENERIC_TREE #endif // USE_GENERIC_TREE
top[x] = ymode; top[x] = ymode;
} }
memcpy(modes, top, 4 * sizeof(*top)); memcpy(modes, top, 4 * sizeof(*top));
@ -502,7 +495,7 @@ static const uint8_t
// Paragraph 9.9 // Paragraph 9.9
static const uint8_t kBands[16 + 1] = { static const int kBands[16 + 1] = {
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
0 // extra entry as sentinel 0 // extra entry as sentinel
}; };

View File

@ -13,12 +13,12 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "./alphai.h"
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/dec/vp8li_dec.h" #include "./vp8li.h"
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/utils/bit_reader_inl_utils.h" #include "../utils/bit_reader_inl.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -26,16 +26,6 @@ int WebPGetDecoderVersion(void) {
return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION; return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
} }
//------------------------------------------------------------------------------
// Signature and pointer-to-function for GetCoeffs() variants below.
typedef int (*GetCoeffsFunc)(VP8BitReader* const br,
const VP8BandProbas* const prob[],
int ctx, const quant_t dq, int n, int16_t* out);
static volatile GetCoeffsFunc GetCoeffs = NULL;
static void InitGetCoeffs(void);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// VP8Decoder // VP8Decoder
@ -61,7 +51,6 @@ VP8Decoder* VP8New(void) {
WebPGetWorkerInterface()->Init(&dec->worker_); WebPGetWorkerInterface()->Init(&dec->worker_);
dec->ready_ = 0; dec->ready_ = 0;
dec->num_parts_minus_one_ = 0; dec->num_parts_minus_one_ = 0;
InitGetCoeffs();
} }
return dec; return dec;
} }
@ -284,14 +273,12 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
frm_hdr->profile_ = (bits >> 1) & 7; frm_hdr->profile_ = (bits >> 1) & 7;
frm_hdr->show_ = (bits >> 4) & 1; frm_hdr->show_ = (bits >> 4) & 1;
frm_hdr->partition_length_ = (bits >> 5); frm_hdr->partition_length_ = (bits >> 5);
if (frm_hdr->profile_ > 3) { if (frm_hdr->profile_ > 3)
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Incorrect keyframe parameters."); "Incorrect keyframe parameters.");
} if (!frm_hdr->show_)
if (!frm_hdr->show_) {
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Frame not displayable."); "Frame not displayable.");
}
buf += 3; buf += 3;
buf_size -= 3; buf_size -= 3;
} }
@ -433,9 +420,8 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
} }
// Returns the position of the last non-zero coeff plus one // Returns the position of the last non-zero coeff plus one
static int GetCoeffsFast(VP8BitReader* const br, static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[],
const VP8BandProbas* const prob[], int ctx, const quant_t dq, int n, int16_t* out) {
int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx]; const uint8_t* p = prob[n]->probas_[ctx];
for (; n < 16; ++n) { for (; n < 16; ++n) {
if (!VP8GetBit(br, p[0])) { if (!VP8GetBit(br, p[0])) {
@ -461,46 +447,6 @@ static int GetCoeffsFast(VP8BitReader* const br,
return 16; return 16;
} }
// This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version
// of VP8GetBitAlt() targeting specific platforms.
static int GetCoeffsAlt(VP8BitReader* const br,
const VP8BandProbas* const prob[],
int ctx, const quant_t dq, int n, int16_t* out) {
const uint8_t* p = prob[n]->probas_[ctx];
for (; n < 16; ++n) {
if (!VP8GetBitAlt(br, p[0])) {
return n; // previous coeff was last non-zero coeff
}
while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs
p = prob[++n]->probas_[0];
if (n == 16) return 16;
}
{ // non zero coeff
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
int v;
if (!VP8GetBitAlt(br, p[2])) {
v = 1;
p = p_ctx[1];
} else {
v = GetLargeValue(br, p);
p = p_ctx[2];
}
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
}
}
return 16;
}
static WEBP_TSAN_IGNORE_FUNCTION void InitGetCoeffs(void) {
if (GetCoeffs == NULL) {
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
GetCoeffs = GetCoeffsAlt;
} else {
GetCoeffs = GetCoeffsFast;
}
}
}
static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) { static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
nz_coeffs <<= 2; nz_coeffs <<= 2;
nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz; nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;

View File

@ -11,16 +11,16 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DEC_VP8I_DEC_H_ #ifndef WEBP_DEC_VP8I_H_
#define WEBP_DEC_VP8I_DEC_H_ #define WEBP_DEC_VP8I_H_
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include "src/dec/common_dec.h" #include "./common.h"
#include "src/dec/vp8li_dec.h" #include "./vp8li.h"
#include "src/utils/bit_reader_utils.h" #include "../utils/bit_reader.h"
#include "src/utils/random_utils.h" #include "../utils/random.h"
#include "src/utils/thread_utils.h" #include "../utils/thread.h"
#include "src/dsp/dsp.h" #include "../dsp/dsp.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -30,9 +30,9 @@ extern "C" {
// Various defines and enums // Various defines and enums
// version numbers // version numbers
#define DEC_MAJ_VERSION 1 #define DEC_MAJ_VERSION 0
#define DEC_MIN_VERSION 0 #define DEC_MIN_VERSION 5
#define DEC_REV_VERSION 0 #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),
@ -57,6 +57,7 @@ extern "C" {
// '|' = left sample, '-' = top sample, '+' = top-left sample // '|' = left sample, '-' = top sample, '+' = top-left sample
// 't' = extra top-right sample for 4x4 modes // 't' = extra top-right sample for 4x4 modes
#define YUV_SIZE (BPS * 17 + BPS * 9) #define YUV_SIZE (BPS * 17 + BPS * 9)
#define Y_SIZE (BPS * 17)
#define Y_OFF (BPS * 1 + 8) #define Y_OFF (BPS * 1 + 8)
#define U_OFF (Y_OFF + BPS * 16 + BPS) #define U_OFF (Y_OFF + BPS * 16 + BPS)
#define V_OFF (U_OFF + 16) #define V_OFF (U_OFF + 16)
@ -316,4 +317,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8I_DEC_H_ */ #endif /* WEBP_DEC_VP8I_H_ */

View File

@ -14,22 +14,21 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "./alphai.h"
#include "src/dec/vp8li_dec.h" #include "./vp8li.h"
#include "src/dsp/dsp.h" #include "../dsp/dsp.h"
#include "src/dsp/lossless.h" #include "../dsp/lossless.h"
#include "src/dsp/lossless_common.h" #include "../dsp/yuv.h"
#include "src/dsp/yuv.h" #include "../utils/endian_inl.h"
#include "src/utils/endian_inl_utils.h" #include "../utils/huffman.h"
#include "src/utils/huffman_utils.h" #include "../utils/utils.h"
#include "src/utils/utils.h"
#define NUM_ARGB_CACHE_ROWS 16 #define NUM_ARGB_CACHE_ROWS 16
static const int kCodeLengthLiterals = 16; static const int kCodeLengthLiterals = 16;
static const int kCodeLengthRepeatCode = 16; static const int kCodeLengthRepeatCode = 16;
static const uint8_t kCodeLengthExtraBits[3] = { 2, 3, 7 }; static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
static const uint8_t kCodeLengthRepeatOffsets[3] = { 3, 3, 11 }; static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Five Huffman codes are used at each meta code: // Five Huffman codes are used at each meta code:
@ -86,7 +85,7 @@ static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
// All values computed for 8-bit first level lookup with Mark Adler's tool: // All values computed for 8-bit first level lookup with Mark Adler's tool:
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c // http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
#define FIXED_TABLE_SIZE (630 * 3 + 410) #define FIXED_TABLE_SIZE (630 * 3 + 410)
static const uint16_t kTableSize[12] = { static const int kTableSize[12] = {
FIXED_TABLE_SIZE + 654, FIXED_TABLE_SIZE + 654,
FIXED_TABLE_SIZE + 656, FIXED_TABLE_SIZE + 656,
FIXED_TABLE_SIZE + 658, FIXED_TABLE_SIZE + 658,
@ -253,11 +252,11 @@ static int ReadHuffmanCodeLengths(
int symbol; int symbol;
int max_symbol; int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH; int prev_code_len = DEFAULT_CODE_LENGTH;
HuffmanCode table[1 << LENGTHS_TABLE_BITS]; HuffmanTables tables;
if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS, if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
code_length_code_lengths, !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
NUM_CODE_LENGTH_CODES)) { code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End; goto End;
} }
@ -277,7 +276,7 @@ static int ReadHuffmanCodeLengths(
int code_len; int code_len;
if (max_symbol-- == 0) break; if (max_symbol-- == 0) break;
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits); VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value; code_len = p->value;
if (code_len < kCodeLengthLiterals) { if (code_len < kCodeLengthLiterals) {
@ -300,6 +299,7 @@ static int ReadHuffmanCodeLengths(
ok = 1; ok = 1;
End: End:
VP8LHuffmanTablesDeallocate(&tables);
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR; if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok; return ok;
} }
@ -307,7 +307,8 @@ static int ReadHuffmanCodeLengths(
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman // 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree. // tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int* const code_lengths, HuffmanCode* const table) { int* const code_lengths,
HuffmanTables* const table) {
int ok = 0; int ok = 0;
int size = 0; int size = 0;
VP8LBitReader* const br = &dec->br_; VP8LBitReader* const br = &dec->br_;
@ -362,12 +363,18 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL; uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL; HTreeGroup* htree_groups = NULL;
HuffmanCode* huffman_tables = NULL; HuffmanTables* huffman_tables = &hdr->huffman_tables_;
HuffmanCode* next = NULL;
int num_htree_groups = 1; int num_htree_groups = 1;
int num_htree_groups_max = 1;
int max_alphabet_size = 0; int max_alphabet_size = 0;
int* code_lengths = NULL; int* code_lengths = NULL;
const int table_size = kTableSize[color_cache_bits]; const int table_size = kTableSize[color_cache_bits];
int* mapping = NULL;
int ok = 0;
// Check the table has been 0 initialized (through InitMetadata).
assert(huffman_tables->root.start == NULL);
assert(huffman_tables->curr_segment == NULL);
if (allow_recursion && VP8LReadBits(br, 1)) { if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes. // use meta Huffman codes.
@ -384,10 +391,36 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// The huffman data is stored in red and green bytes. // The huffman data is stored in red and green bytes.
const int group = (huffman_image[i] >> 8) & 0xffff; const int group = (huffman_image[i] >> 8) & 0xffff;
huffman_image[i] = group; huffman_image[i] = group;
if (group >= num_htree_groups) { if (group >= num_htree_groups_max) {
num_htree_groups = group + 1; num_htree_groups_max = group + 1;
} }
} }
// Check the validity of num_htree_groups_max. If it seems too big, use a
// smaller value for later. This will prevent big memory allocations to end
// up with a bad bitstream anyway.
// The value of 1000 is totally arbitrary. We know that num_htree_groups_max
// is smaller than (1 << 16) and should be smaller than the number of pixels
// (though the format allows it to be bigger).
if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
// Create a mapping from the used indices to the minimal set of used
// values [0, num_htree_groups)
mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
if (mapping == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
// -1 means a value is unmapped, and therefore unused in the Huffman
// image.
memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
// Get the current mapping for the group and remap the Huffman image.
int* const mapped_group = &mapping[huffman_image[i]];
if (*mapped_group == -1) *mapped_group = num_htree_groups++;
huffman_image[i] = *mapped_group;
}
} else {
num_htree_groups = num_htree_groups_max;
}
} }
if (br->eos_) goto Error; if (br->eos_) goto Error;
@ -403,89 +436,104 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
} }
} }
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups); htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths)); sizeof(*code_lengths));
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) { if (htree_groups == NULL || code_lengths == NULL ||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
huffman_tables)) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY; dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error; goto Error;
} }
next = huffman_tables; for (i = 0; i < num_htree_groups_max; ++i) {
for (i = 0; i < num_htree_groups; ++i) { // If the index "i" is unused in the Huffman image, just make sure the
HTreeGroup* const htree_group = &htree_groups[i]; // coefficients are valid but do not store them.
HuffmanCode** const htrees = htree_group->htrees; if (mapping != NULL && mapping[i] == -1) {
int size; for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int total_size = 0; int alphabet_size = kAlphabetSize[j];
int is_trivial_literal = 1; if (j == 0 && color_cache_bits > 0) {
int max_bits = 0; alphabet_size += (1 << color_cache_bits);
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { }
int alphabet_size = kAlphabetSize[j]; // Passing in NULL so that nothing gets filled.
htrees[j] = next; if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, NULL)) {
if (j == 0 && color_cache_bits > 0) { goto Error;
alphabet_size += 1 << color_cache_bits;
}
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (next->bits == 0);
}
total_size += next->bits;
next += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
for (k = 1; k < alphabet_size; ++k) {
if (code_lengths[k] > local_max_bits) {
local_max_bits = code_lengths[k];
}
} }
max_bits += local_max_bits;
} }
} } else {
htree_group->is_trivial_literal = is_trivial_literal; HTreeGroup* const htree_group =
htree_group->is_trivial_code = 0; &htree_groups[(mapping == NULL) ? i : mapping[i]];
if (is_trivial_literal) { HuffmanCode** const htrees = htree_group->htrees;
const int red = htrees[RED][0].value; int size;
const int blue = htrees[BLUE][0].value; int total_size = 0;
const int alpha = htrees[ALPHA][0].value; int is_trivial_literal = 1;
htree_group->literal_arb = int max_bits = 0;
((uint32_t)alpha << 24) | (red << 16) | blue; for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) { int alphabet_size = kAlphabetSize[j];
htree_group->is_trivial_code = 1; if (j == 0 && color_cache_bits > 0) {
htree_group->literal_arb |= htrees[GREEN][0].value << 8; alphabet_size += (1 << color_cache_bits);
}
size =
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (htrees[j]->bits == 0);
}
total_size += htrees[j]->bits;
huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
for (k = 1; k < alphabet_size; ++k) {
if (code_lengths[k] > local_max_bits) {
local_max_bits = code_lengths[k];
}
}
max_bits += local_max_bits;
}
} }
htree_group->is_trivial_literal = is_trivial_literal;
htree_group->is_trivial_code = 0;
if (is_trivial_literal) {
const int red = htrees[RED][0].value;
const int blue = htrees[BLUE][0].value;
const int alpha = htrees[ALPHA][0].value;
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
htree_group->is_trivial_code = 1;
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
}
}
htree_group->use_packed_table =
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
} }
htree_group->use_packed_table = !htree_group->is_trivial_code &&
(max_bits < HUFFMAN_PACKED_BITS);
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
} }
WebPSafeFree(code_lengths); ok = 1;
// All OK. Finalize pointers and return. // All OK. Finalize pointers.
hdr->huffman_image_ = huffman_image; hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups; hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups; hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables;
return 1;
Error: Error:
WebPSafeFree(code_lengths); WebPSafeFree(code_lengths);
WebPSafeFree(huffman_image); WebPSafeFree(mapping);
WebPSafeFree(huffman_tables); if (!ok) {
VP8LHtreeGroupsFree(htree_groups); WebPSafeFree(huffman_image);
return 0; VP8LHuffmanTablesDeallocate(huffman_tables);
VP8LHtreeGroupsFree(htree_groups);
}
return ok;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Scaling. // Scaling.
#if !defined(WEBP_REDUCE_SIZE)
static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) { static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
const int num_channels = 4; const int num_channels = 4;
const int in_width = io->mb_w; const int in_width = io->mb_w;
@ -517,13 +565,10 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
out_width, out_height, 0, num_channels, work); out_width, out_height, 0, num_channels, work);
return 1; return 1;
} }
#endif // WEBP_REDUCE_SIZE
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Export to ARGB // Export to ARGB
#if !defined(WEBP_REDUCE_SIZE)
// We have special "export" function since we need to convert from BGRA // We have special "export" function since we need to convert from BGRA
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace, static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int rgba_stride, uint8_t* const rgba) { int rgba_stride, uint8_t* const rgba) {
@ -552,21 +597,16 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
uint8_t* const row_out = out + num_lines_out * out_stride; uint8_t* const row_out = out + num_lines_out * out_stride;
const int lines_left = mb_h - num_lines_in; const int lines_left = mb_h - num_lines_in;
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
int lines_imported;
assert(needed_lines > 0 && needed_lines <= lines_left); assert(needed_lines > 0 && needed_lines <= lines_left);
WebPMultARGBRows(row_in, in_stride, WebPMultARGBRows(row_in, in_stride,
dec->rescaler->src_width, needed_lines, 0); dec->rescaler->src_width, needed_lines, 0);
lines_imported = WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride); num_lines_in += needed_lines;
assert(lines_imported == needed_lines);
num_lines_in += lines_imported;
num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out); num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
} }
return num_lines_out; return num_lines_out;
} }
#endif // WEBP_REDUCE_SIZE
// Emit rows without any scaling. // Emit rows without any scaling.
static int EmitRows(WEBP_CSP_MODE colorspace, static int EmitRows(WEBP_CSP_MODE colorspace,
const uint8_t* row_in, int in_stride, const uint8_t* row_in, int in_stride,
@ -633,12 +673,9 @@ static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
while (num_lines_in < mb_h) { while (num_lines_in < mb_h) {
const int lines_left = mb_h - num_lines_in; const int lines_left = mb_h - num_lines_in;
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
int lines_imported;
WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0); WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
lines_imported = WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
WebPRescalerImport(dec->rescaler, lines_left, in, in_stride); num_lines_in += needed_lines;
assert(lines_imported == needed_lines);
num_lines_in += lines_imported;
in += needed_lines * in_stride; in += needed_lines * in_stride;
y_pos += ExportYUVA(dec, y_pos); y_pos += ExportYUVA(dec, y_pos);
} }
@ -718,15 +755,13 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
uint32_t* const rows_out = dec->argb_cache_; uint32_t* const rows_out = dec->argb_cache_;
// Inverse transforms. // Inverse transforms.
// TODO: most transforms only need to operate on the cropped region only.
memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
while (n-- > 0) { while (n-- > 0) {
VP8LTransform* const transform = &dec->transforms_[n]; VP8LTransform* const transform = &dec->transforms_[n];
VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
rows_in = rows_out; rows_in = rows_out;
} }
if (rows_in != rows_out) {
// No transform called, hence just copy.
memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
}
} }
// Processes (transforms, scales & color-converts) the rows decoded after the // Processes (transforms, scales & color-converts) the rows decoded after the
@ -752,12 +787,9 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA; const WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride; uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
const int num_rows_out = const int num_rows_out = io->use_scaling ?
#if !defined(WEBP_REDUCE_SIZE)
io->use_scaling ?
EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h, EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
rgba, buf->stride) : rgba, buf->stride) :
#endif // WEBP_REDUCE_SIZE
EmitRows(output->colorspace, rows_data, in_stride, EmitRows(output->colorspace, rows_data, in_stride,
io->mb_w, io->mb_h, rgba, buf->stride); io->mb_w, io->mb_h, rgba, buf->stride);
// Update 'last_out_row_'. // Update 'last_out_row_'.
@ -884,11 +916,7 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
#endif #endif
break; break;
case 2: case 2:
#if !defined(WORDS_BIGENDIAN)
memcpy(&pattern, src, sizeof(uint16_t)); memcpy(&pattern, src, sizeof(uint16_t));
#else
pattern = ((uint32_t)src[0] << 8) | src[1];
#endif
#if defined(__arm__) || defined(_M_ARM) #if defined(__arm__) || defined(_M_ARM)
pattern |= pattern << 16; pattern |= pattern << 16;
#elif defined(WEBP_USE_MIPS_DSP_R2) #elif defined(WEBP_USE_MIPS_DSP_R2)
@ -1025,13 +1053,12 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
ok = 0; ok = 0;
goto End; goto End;
} }
br->eos_ = VP8LIsEndOfStream(br); assert(br->eos_ == VP8LIsEndOfStream(br));
} }
// Process the remaining rows corresponding to last row-block. // Process the remaining rows corresponding to last row-block.
ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row); ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
End: End:
br->eos_ = VP8LIsEndOfStream(br);
if (!ok || (br->eos_ && pos < end)) { if (!ok || (br->eos_ && pos < end)) {
ok = 0; ok = 0;
dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
@ -1104,12 +1131,11 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
if (htree_group->use_packed_table) { if (htree_group->use_packed_table) {
code = ReadPackedSymbols(htree_group, br, src); code = ReadPackedSymbols(htree_group, br, src);
if (VP8LIsEndOfStream(br)) break;
if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne; if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
} else { } else {
code = ReadSymbol(htree_group->htrees[GREEN], br); code = ReadSymbol(htree_group->htrees[GREEN], br);
} }
if (VP8LIsEndOfStream(br)) break; if (br->eos_) break; // early out
if (code < NUM_LITERAL_CODES) { // Literal if (code < NUM_LITERAL_CODES) { // Literal
if (htree_group->is_trivial_literal) { if (htree_group->is_trivial_literal) {
*src = htree_group->literal_arb | (code << 8); *src = htree_group->literal_arb | (code << 8);
@ -1119,7 +1145,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
blue = ReadSymbol(htree_group->htrees[BLUE], br); blue = ReadSymbol(htree_group->htrees[BLUE], br);
alpha = ReadSymbol(htree_group->htrees[ALPHA], br); alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
if (VP8LIsEndOfStream(br)) break; if (br->eos_) break;
*src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue; *src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
} }
AdvanceByOne: AdvanceByOne:
@ -1147,7 +1173,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
dist_code = GetCopyDistance(dist_symbol, br); dist_code = GetCopyDistance(dist_symbol, br);
dist = PlaneCodeToDistance(width, dist_code); dist = PlaneCodeToDistance(width, dist_code);
if (VP8LIsEndOfStream(br)) break; if (br->eos_) break;
if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) { if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
goto Error; goto Error;
} else { } else {
@ -1184,12 +1210,24 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
} else { // Not reached } else { // Not reached
goto Error; goto Error;
} }
assert(br->eos_ == VP8LIsEndOfStream(br));
} }
br->eos_ = VP8LIsEndOfStream(br); br->eos_ = VP8LIsEndOfStream(br);
if (dec->incremental_ && br->eos_ && src < src_end) { // In incremental decoding:
// br->eos_ && src < src_last: if 'br' reached the end of the buffer and
// 'src_last' has not been reached yet, there is not enough data. 'dec' has to
// be reset until there is more data.
// !br->eos_ && src < src_last: this cannot happen as either the buffer is
// fully read, either enough has been read to reach 'src_last'.
// src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go
// beyond 'src_last' in case the image is cropped and an LZ77 goes further.
// The buffer might have been enough or there is some left. 'br->eos_' does
// not matter.
assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last);
if (dec->incremental_ && br->eos_ && src < src_last) {
RestoreState(dec); RestoreState(dec);
} else if (!br->eos_) { } else if ((dec->incremental_ && src >= src_last) || !br->eos_) {
// Process the remaining rows corresponding to last row-block. // Process the remaining rows corresponding to last row-block.
if (process_func != NULL) { if (process_func != NULL) {
process_func(dec, row > last_row ? last_row : row); process_func(dec, row > last_row ? last_row : row);
@ -1234,9 +1272,8 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
// Equivalent to AddPixelEq(), on a byte-basis. // Equivalent to AddPixelEq(), on a byte-basis.
new_data[i] = (data[i] + new_data[i - 4]) & 0xff; new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
} }
for (; i < 4 * final_num_colors; ++i) { for (; i < 4 * final_num_colors; ++i)
new_data[i] = 0; // black tail. new_data[i] = 0; // black tail.
}
WebPSafeFree(transform->data_); WebPSafeFree(transform->data_);
transform->data_ = new_color_map; transform->data_ = new_color_map;
} }
@ -1308,7 +1345,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL); assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_); WebPSafeFree(hdr->huffman_image_);
WebPSafeFree(hdr->huffman_tables_); VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_); VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_); VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_); VP8LColorCacheClear(&hdr->saved_color_cache_);
@ -1507,8 +1544,9 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) {
const int cache_pixs = width * num_rows_to_process; const int cache_pixs = width * num_rows_to_process;
uint8_t* const dst = output + width * cur_row; uint8_t* const dst = output + width * cur_row;
const uint32_t* const src = dec->argb_cache_; const uint32_t* const src = dec->argb_cache_;
int i;
ApplyInverseTransforms(dec, num_rows_to_process, in); ApplyInverseTransforms(dec, num_rows_to_process, in);
WebPExtractGreen(src, dst, cache_pixs); for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff;
AlphaApplyFilter(alph_dec, AlphaApplyFilter(alph_dec,
cur_row, cur_row + num_rows_to_process, dst, width); cur_row, cur_row + num_rows_to_process, dst, width);
num_rows -= num_rows_to_process; num_rows -= num_rows_to_process;
@ -1527,6 +1565,7 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (dec == NULL) return 0; if (dec == NULL) return 0;
assert(alph_dec != NULL); assert(alph_dec != NULL);
alph_dec->vp8l_dec_ = dec;
dec->width_ = alph_dec->width_; dec->width_ = alph_dec->width_;
dec->height_ = alph_dec->height_; dec->height_ = alph_dec->height_;
@ -1558,12 +1597,11 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
if (!ok) goto Err; if (!ok) goto Err;
// Only set here, once we are sure it is valid (to avoid thread races).
alph_dec->vp8l_dec_ = dec;
return 1; return 1;
Err: Err:
VP8LDelete(dec); VP8LDelete(alph_dec->vp8l_dec_);
alph_dec->vp8l_dec_ = NULL;
return 0; return 0;
} }
@ -1576,8 +1614,6 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
return 1; // done return 1; // done
} }
if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing();
// Decode (with special row processing). // Decode (with special row processing).
return alph_dec->use_8b_decode_ ? return alph_dec->use_8b_decode_ ?
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
@ -1624,7 +1660,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
// Sanity checks. // Sanity checks.
if (dec == NULL) return 0; if (dec == NULL) return 0;
assert(dec->hdr_.huffman_tables_ != NULL); assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL); assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0); assert(dec->hdr_.num_htree_groups_ > 0);
@ -1645,19 +1681,12 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (!AllocateInternalBuffers32b(dec, io->width)) goto Err; if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
#if !defined(WEBP_REDUCE_SIZE)
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
#else
if (io->use_scaling) {
dec->status_ = VP8_STATUS_INVALID_PARAM;
goto Err;
}
#endif
if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
// need the alpha-multiply functions for premultiplied output or rescaling // need the alpha-multiply functions for premultiplied output or rescaling
WebPInitAlphaProcessing(); WebPInitAlphaProcessing();
} }
if (!WebPIsRGBMode(dec->output_->colorspace)) { if (!WebPIsRGBMode(dec->output_->colorspace)) {
WebPInitConvertARGBToYUV(); WebPInitConvertARGBToYUV();
if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing(); if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();

View File

@ -12,14 +12,14 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
// Vikas Arora(vikaas.arora@gmail.com) // Vikas Arora(vikaas.arora@gmail.com)
#ifndef WEBP_DEC_VP8LI_DEC_H_ #ifndef WEBP_DEC_VP8LI_H_
#define WEBP_DEC_VP8LI_DEC_H_ #define WEBP_DEC_VP8LI_H_
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/utils/bit_reader_utils.h" #include "../utils/bit_reader.h"
#include "src/utils/color_cache_utils.h" #include "../utils/color_cache.h"
#include "src/utils/huffman_utils.h" #include "../utils/huffman.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -51,7 +51,7 @@ typedef struct {
uint32_t *huffman_image_; uint32_t *huffman_image_;
int num_htree_groups_; int num_htree_groups_;
HTreeGroup *htree_groups_; HTreeGroup *htree_groups_;
HuffmanCode *huffman_tables_; HuffmanTables huffman_tables_;
} VP8LMetadata; } VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder; typedef struct VP8LDecoder VP8LDecoder;
@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_VP8LI_DEC_H_ */ #endif /* WEBP_DEC_VP8LI_H_ */

View File

@ -13,11 +13,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8i_dec.h" #include "./vp8i.h"
#include "src/dec/vp8li_dec.h" #include "./vp8li.h"
#include "src/dec/webpi_dec.h" #include "./webpi.h"
#include "src/utils/utils.h" #include "../utils/utils.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG #include "../webp/mux_types.h" // ALPHA_FLAG
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// RIFF layout is: // RIFF layout is:
@ -39,8 +39,8 @@
// 20..23 VP8X flags bit-map corresponding to the chunk-types present. // 20..23 VP8X flags bit-map corresponding to the chunk-types present.
// 24..26 Width of the Canvas Image. // 24..26 Width of the Canvas Image.
// 27..29 Height of the Canvas Image. // 27..29 Height of the Canvas Image.
// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L, // There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
// XMP, EXIF ...) // VP8L, XMP, EXIF ...)
// All sizes are in little-endian order. // All sizes are in little-endian order.
// Note: chunk data size must be padded to multiple of 2 when written. // Note: chunk data size must be padded to multiple of 2 when written.
@ -289,6 +289,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
int found_riff = 0; int found_riff = 0;
int found_vp8x = 0; int found_vp8x = 0;
int animation_present = 0; int animation_present = 0;
int fragments_present = 0;
const int have_all_data = (headers != NULL) ? headers->have_all_data : 0; const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
VP8StatusCode status; VP8StatusCode status;
@ -317,6 +318,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
return status; // Wrong VP8X / insufficient data. return status; // Wrong VP8X / insufficient data.
} }
animation_present = !!(flags & ANIMATION_FLAG); animation_present = !!(flags & ANIMATION_FLAG);
fragments_present = !!(flags & FRAGMENTS_FLAG);
if (!found_riff && found_vp8x) { if (!found_riff && found_vp8x) {
// Note: This restriction may be removed in the future, if it becomes // Note: This restriction may be removed in the future, if it becomes
// necessary to send VP8X chunk to the decoder. // necessary to send VP8X chunk to the decoder.
@ -328,7 +330,8 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
image_width = canvas_width; image_width = canvas_width;
image_height = canvas_height; image_height = canvas_height;
if (found_vp8x && animation_present && headers == NULL) { if (found_vp8x && (animation_present || fragments_present) &&
headers == NULL) {
status = VP8_STATUS_OK; status = VP8_STATUS_OK;
goto ReturnWidthHeight; // Just return features from VP8X header. goto ReturnWidthHeight; // Just return features from VP8X header.
} }
@ -359,7 +362,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
return VP8_STATUS_BITSTREAM_ERROR; return VP8_STATUS_BITSTREAM_ERROR;
} }
if (format != NULL && !animation_present) { if (format != NULL && !(animation_present || fragments_present)) {
*format = hdrs.is_lossless ? 2 : 1; *format = hdrs.is_lossless ? 2 : 1;
} }
@ -421,9 +424,7 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
NULL, NULL, NULL, &has_animation, NULL, NULL, NULL, &has_animation,
NULL, headers); NULL, headers);
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) { if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
// The WebPDemux API + libwebp can be used to decode individual // TODO(jzern): full support of animation frames will require API additions.
// uncomposited frames or the WebPAnimDecoder can be used to fully
// reconstruct them (see webp/demux.h).
if (has_animation) { if (has_animation) {
status = VP8_STATUS_UNSUPPORTED_FEATURE; status = VP8_STATUS_UNSUPPORTED_FEATURE;
} }

View File

@ -11,15 +11,15 @@
// //
// Author: somnath@google.com (Somnath Banerjee) // Author: somnath@google.com (Somnath Banerjee)
#ifndef WEBP_DEC_WEBPI_DEC_H_ #ifndef WEBP_DEC_WEBPI_H_
#define WEBP_DEC_WEBPI_DEC_H_ #define WEBP_DEC_WEBPI_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "src/utils/rescaler_utils.h" #include "../utils/rescaler.h"
#include "src/dec/vp8_dec.h" #include "./decode_vp8.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object. // WebPDecParams: Decoding output parameters. Transient internal object.
@ -38,18 +38,27 @@ struct WebPDecParams {
int last_y; // coordinate of the line that was last output int last_y; // coordinate of the line that was last output
const WebPDecoderOptions* options; // if not NULL, use alt decoding features const WebPDecoderOptions* options; // if not NULL, use alt decoding features
// rescalers
WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a;
void* memory; // overall scratch memory for the output work. void* memory; // overall scratch memory for the output work.
OutputFunc emit; // output RGB or YUV samples OutputFunc emit; // output RGB or YUV samples
OutputAlphaFunc emit_alpha; // output alpha channel OutputAlphaFunc emit_alpha; // output alpha channel
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
WebPDecBuffer* final_output; // In case the user supplied a slow-memory
// output, we decode image in temporary buffer
// (this::output) and copy it here.
WebPDecBuffer tmp_buffer; // this::output will point to this one in case
// of slow memory.
}; };
// Should be called first, before any use of the WebPDecParams object. // Should be called first, before any use of the WebPDecParams object.
void WebPResetDecParams(WebPDecParams* const params); void WebPResetDecParams(WebPDecParams* const params);
// Delete all memory (after an error occurred, for instance)
void WebPFreeDecParams(WebPDecParams* const params);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Header parsing helpers // Header parsing helpers
@ -130,4 +139,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
} // extern "C" } // extern "C"
#endif #endif
#endif /* WEBP_DEC_WEBPI_DEC_H_ */ #endif /* WEBP_DEC_WEBPI_H_ */

View File

@ -1,18 +1,14 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir)
lib_LTLIBRARIES = libwebpdemux.la lib_LTLIBRARIES = libwebpdemux.la
libwebpdemux_la_SOURCES = libwebpdemux_la_SOURCES =
libwebpdemux_la_SOURCES += anim_decode.c demux.c libwebpdemux_la_SOURCES += anim_decode.c demux.c
libwebpdemuxinclude_HEADERS = libwebpdemuxinclude_HEADERS =
libwebpdemuxinclude_HEADERS += ../webp/decode.h
libwebpdemuxinclude_HEADERS += ../webp/demux.h libwebpdemuxinclude_HEADERS += ../webp/demux.h
libwebpdemuxinclude_HEADERS += ../webp/mux_types.h libwebpdemuxinclude_HEADERS += ../webp/mux_types.h
libwebpdemuxinclude_HEADERS += ../webp/types.h libwebpdemuxinclude_HEADERS += ../webp/types.h
noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpdemux_la_LIBADD = ../libwebp.la libwebpdemux_la_LIBADD = ../libwebp.la
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:4:0 libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:1:0
libwebpdemuxincludedir = $(includedir)/webp libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc pkgconfig_DATA = libwebpdemux.pc

View File

@ -11,15 +11,15 @@
// //
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "src/webp/config.h" #include "../webp/config.h"
#endif #endif
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "src/utils/utils.h" #include "../utils/utils.h"
#include "src/webp/decode.h" #include "../webp/decode.h"
#include "src/webp/demux.h" #include "../webp/demux.h"
#define NUM_CHANNELS 4 #define NUM_CHANNELS 4

View File

@ -11,21 +11,21 @@
// //
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "src/webp/config.h" #include "../webp/config.h"
#endif #endif
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "src/utils/utils.h" #include "../utils/utils.h"
#include "src/webp/decode.h" // WebPGetFeatures #include "../webp/decode.h" // WebPGetFeatures
#include "src/webp/demux.h" #include "../webp/demux.h"
#include "src/webp/format_constants.h" #include "../webp/format_constants.h"
#define DMUX_MAJ_VERSION 1 #define DMUX_MAJ_VERSION 0
#define DMUX_MIN_VERSION 0 #define DMUX_MIN_VERSION 3
#define DMUX_REV_VERSION 0 #define DMUX_REV_VERSION 1
typedef struct { typedef struct {
size_t start_; // start location of the data size_t start_; // start location of the data
@ -205,14 +205,12 @@ static void SetFrameInfo(size_t start_offset, size_t size,
frame->complete_ = complete; frame->complete_ = complete;
} }
// Store image bearing chunks to 'frame'. 'min_size' is an optional size // Store image bearing chunks to 'frame'.
// requirement, it may be zero.
static ParseStatus StoreFrame(int frame_num, uint32_t min_size, static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
MemBuffer* const mem, Frame* const frame) { MemBuffer* const mem, Frame* const frame) {
int alpha_chunks = 0; int alpha_chunks = 0;
int image_chunks = 0; int image_chunks = 0;
int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE || int done = (MemDataSize(mem) < min_size);
MemDataSize(mem) < min_size);
ParseStatus status = PARSE_OK; ParseStatus status = PARSE_OK;
if (done) return PARSE_NEED_MORE_DATA; if (done) return PARSE_NEED_MORE_DATA;
@ -403,9 +401,9 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
if (frame == NULL) return PARSE_ERROR; if (frame == NULL) return PARSE_ERROR;
// For the single image case we allow parsing of a partial frame, so no // For the single image case we allow parsing of a partial frame, but we need
// minimum size is imposed here. // at least CHUNK_HEADER_SIZE for parsing.
status = StoreFrame(1, 0, &dmux->mem_, frame); status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
if (status != PARSE_ERROR) { if (status != PARSE_ERROR) {
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
// Clear any alpha when the alpha flag is missing. // Clear any alpha when the alpha flag is missing.
@ -592,6 +590,7 @@ static int CheckFrameBounds(const Frame* const frame, int exact,
static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
const Frame* f = dmux->frames_; const Frame* f = dmux->frames_;
if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
@ -599,7 +598,7 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
if (dmux->loop_count_ < 0) return 0; if (dmux->loop_count_ < 0) return 0;
if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream if (is_fragmented) return 0;
while (f != NULL) { while (f != NULL) {
const int cur_frame_set = f->frame_num_; const int cur_frame_set = f->frame_num_;

View File

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

View File

@ -1,14 +1,7 @@
AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) noinst_LTLIBRARIES = libwebpdsp.la libwebpdsp_avx2.la
noinst_LTLIBRARIES = noinst_LTLIBRARIES += libwebpdsp_sse2.la libwebpdspdecode_sse2.la
noinst_LTLIBRARIES += libwebpdsp.la noinst_LTLIBRARIES += libwebpdsp_sse41.la libwebpdspdecode_sse41.la
noinst_LTLIBRARIES += libwebpdsp_avx2.la noinst_LTLIBRARIES += libwebpdsp_neon.la libwebpdspdecode_neon.la
noinst_LTLIBRARIES += libwebpdsp_sse2.la
noinst_LTLIBRARIES += libwebpdspdecode_sse2.la
noinst_LTLIBRARIES += libwebpdsp_sse41.la
noinst_LTLIBRARIES += libwebpdspdecode_sse41.la
noinst_LTLIBRARIES += libwebpdsp_neon.la
noinst_LTLIBRARIES += libwebpdspdecode_neon.la
noinst_LTLIBRARIES += libwebpdsp_msa.la
noinst_LTLIBRARIES += libwebpdspdecode_msa.la noinst_LTLIBRARIES += libwebpdspdecode_msa.la
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
@ -32,7 +25,6 @@ COMMON_SOURCES += filters.c
COMMON_SOURCES += filters_mips_dsp_r2.c COMMON_SOURCES += filters_mips_dsp_r2.c
COMMON_SOURCES += lossless.c COMMON_SOURCES += lossless.c
COMMON_SOURCES += lossless.h COMMON_SOURCES += lossless.h
COMMON_SOURCES += lossless_common.h
COMMON_SOURCES += lossless_mips_dsp_r2.c COMMON_SOURCES += lossless_mips_dsp_r2.c
COMMON_SOURCES += mips_macro.h COMMON_SOURCES += mips_macro.h
COMMON_SOURCES += rescaler.c COMMON_SOURCES += rescaler.c
@ -46,6 +38,8 @@ COMMON_SOURCES += yuv_mips32.c
COMMON_SOURCES += yuv_mips_dsp_r2.c COMMON_SOURCES += yuv_mips_dsp_r2.c
ENC_SOURCES = ENC_SOURCES =
ENC_SOURCES += argb.c
ENC_SOURCES += argb_mips_dsp_r2.c
ENC_SOURCES += cost.c ENC_SOURCES += cost.c
ENC_SOURCES += cost_mips32.c ENC_SOURCES += cost_mips32.c
ENC_SOURCES += cost_mips_dsp_r2.c ENC_SOURCES += cost_mips_dsp_r2.c
@ -55,7 +49,6 @@ ENC_SOURCES += enc_mips_dsp_r2.c
ENC_SOURCES += lossless_enc.c ENC_SOURCES += lossless_enc.c
ENC_SOURCES += lossless_enc_mips32.c ENC_SOURCES += lossless_enc_mips32.c
ENC_SOURCES += lossless_enc_mips_dsp_r2.c ENC_SOURCES += lossless_enc_mips_dsp_r2.c
ENC_SOURCES += ssim.c
libwebpdsp_avx2_la_SOURCES = libwebpdsp_avx2_la_SOURCES =
libwebpdsp_avx2_la_SOURCES += enc_avx2.c libwebpdsp_avx2_la_SOURCES += enc_avx2.c
@ -65,8 +58,6 @@ libwebpdsp_avx2_la_CFLAGS = $(AM_CFLAGS) $(AVX2_FLAGS)
libwebpdspdecode_sse41_la_SOURCES = libwebpdspdecode_sse41_la_SOURCES =
libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c
libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c
libwebpdspdecode_sse41_la_SOURCES += upsampling_sse41.c
libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c
libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdspdecode_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS) libwebpdspdecode_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS)
@ -82,32 +73,25 @@ libwebpdspdecode_sse2_la_CPPFLAGS = $(libwebpdsp_sse2_la_CPPFLAGS)
libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS) libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS)
libwebpdspdecode_neon_la_SOURCES = libwebpdspdecode_neon_la_SOURCES =
libwebpdspdecode_neon_la_SOURCES += alpha_processing_neon.c
libwebpdspdecode_neon_la_SOURCES += dec_neon.c libwebpdspdecode_neon_la_SOURCES += dec_neon.c
libwebpdspdecode_neon_la_SOURCES += filters_neon.c
libwebpdspdecode_neon_la_SOURCES += lossless_neon.c libwebpdspdecode_neon_la_SOURCES += lossless_neon.c
libwebpdspdecode_neon_la_SOURCES += neon.h libwebpdspdecode_neon_la_SOURCES += neon.h
libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c
libwebpdspdecode_neon_la_SOURCES += upsampling_neon.c libwebpdspdecode_neon_la_SOURCES += upsampling_neon.c
libwebpdspdecode_neon_la_SOURCES += yuv_neon.c
libwebpdspdecode_neon_la_CPPFLAGS = $(libwebpdsp_neon_la_CPPFLAGS) libwebpdspdecode_neon_la_CPPFLAGS = $(libwebpdsp_neon_la_CPPFLAGS)
libwebpdspdecode_neon_la_CFLAGS = $(libwebpdsp_neon_la_CFLAGS) libwebpdspdecode_neon_la_CFLAGS = $(libwebpdsp_neon_la_CFLAGS)
libwebpdspdecode_msa_la_SOURCES = libwebpdspdecode_msa_la_SOURCES =
libwebpdspdecode_msa_la_SOURCES += dec_msa.c libwebpdspdecode_msa_la_SOURCES += dec_msa.c
libwebpdspdecode_msa_la_SOURCES += filters_msa.c
libwebpdspdecode_msa_la_SOURCES += lossless_msa.c
libwebpdspdecode_msa_la_SOURCES += msa_macro.h libwebpdspdecode_msa_la_SOURCES += msa_macro.h
libwebpdspdecode_msa_la_SOURCES += rescaler_msa.c libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdspdecode_msa_la_SOURCES += upsampling_msa.c libwebpdspdecode_msa_la_CFLAGS = $(AM_CFLAGS)
libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_msa_la_CPPFLAGS)
libwebpdspdecode_msa_la_CFLAGS = $(libwebpdsp_msa_la_CFLAGS)
libwebpdsp_sse2_la_SOURCES = libwebpdsp_sse2_la_SOURCES =
libwebpdsp_sse2_la_SOURCES += argb_sse2.c
libwebpdsp_sse2_la_SOURCES += cost_sse2.c libwebpdsp_sse2_la_SOURCES += cost_sse2.c
libwebpdsp_sse2_la_SOURCES += enc_sse2.c libwebpdsp_sse2_la_SOURCES += enc_sse2.c
libwebpdsp_sse2_la_SOURCES += lossless_enc_sse2.c libwebpdsp_sse2_la_SOURCES += lossless_enc_sse2.c
libwebpdsp_sse2_la_SOURCES += ssim_sse2.c
libwebpdsp_sse2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) libwebpdsp_sse2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdsp_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS) libwebpdsp_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS)
libwebpdsp_sse2_la_LIBADD = libwebpdspdecode_sse2.la libwebpdsp_sse2_la_LIBADD = libwebpdspdecode_sse2.la
@ -126,29 +110,21 @@ libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS) libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS)
libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la
libwebpdsp_msa_la_SOURCES =
libwebpdsp_msa_la_SOURCES += enc_msa.c
libwebpdsp_msa_la_SOURCES += lossless_enc_msa.c
libwebpdsp_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS)
libwebpdsp_msa_la_CFLAGS = $(AM_CFLAGS)
libwebpdsp_msa_la_LIBADD = libwebpdspdecode_msa.la
libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES) libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES)
noinst_HEADERS = noinst_HEADERS =
noinst_HEADERS += ../dec/vp8_dec.h noinst_HEADERS += ../dec/decode_vp8.h
noinst_HEADERS += ../webp/decode.h noinst_HEADERS += ../webp/decode.h
libwebpdsp_la_CPPFLAGS = libwebpdsp_la_CPPFLAGS =
libwebpdsp_la_CPPFLAGS += $(AM_CPPFLAGS) libwebpdsp_la_CPPFLAGS += $(AM_CPPFLAGS)
libwebpdsp_la_CPPFLAGS += $(USE_SWAP_16BIT_CSP) libwebpdsp_la_CPPFLAGS += $(USE_EXPERIMENTAL_CODE) $(USE_SWAP_16BIT_CSP)
libwebpdsp_la_LDFLAGS = -lm libwebpdsp_la_LDFLAGS = -lm
libwebpdsp_la_LIBADD = libwebpdsp_la_LIBADD =
libwebpdsp_la_LIBADD += libwebpdsp_avx2.la libwebpdsp_la_LIBADD += libwebpdsp_avx2.la libwebpdsp_sse2.la
libwebpdsp_la_LIBADD += libwebpdsp_sse2.la
libwebpdsp_la_LIBADD += libwebpdsp_sse41.la libwebpdsp_la_LIBADD += libwebpdsp_sse41.la
libwebpdsp_la_LIBADD += libwebpdsp_neon.la libwebpdsp_la_LIBADD += libwebpdsp_neon.la
libwebpdsp_la_LIBADD += libwebpdsp_msa.la libwebpdsp_la_LIBADD += libwebpdspdecode_msa.la
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES) libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES)

View File

@ -12,13 +12,10 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <assert.h> #include <assert.h>
#include "src/dsp/dsp.h" #include "./dsp.h"
// Tables can be faster on some platform but incur some extra binary size (~2k). // Tables can be faster on some platform but incur some extra binary size (~2k).
#if !defined(USE_TABLES_FOR_ALPHA_MULT) // #define USE_TABLES_FOR_ALPHA_MULT
#define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -32,7 +29,7 @@ static uint32_t Mult(uint8_t x, uint32_t mult) {
return v; return v;
} }
#if (USE_TABLES_FOR_ALPHA_MULT == 1) #ifdef USE_TABLES_FOR_ALPHA_MULT
static const uint32_t kMultTables[2][256] = { static const uint32_t kMultTables[2][256] = {
{ // (255u << MFIX) / alpha { // (255u << MFIX) / alpha
@ -135,9 +132,9 @@ static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
return inverse ? (255u << MFIX) / a : a * KINV_255; return inverse ? (255u << MFIX) / a : a * KINV_255;
} }
#endif // USE_TABLES_FOR_ALPHA_MULT #endif // USE_TABLES_FOR_ALPHA_MULT
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) { void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
int x; int x;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
const uint32_t argb = ptr[x]; const uint32_t argb = ptr[x];
@ -157,8 +154,8 @@ void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
} }
} }
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha, void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
int width, int inverse) { int width, int inverse) {
int x; int x;
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
const uint32_t a = alpha[x]; const uint32_t a = alpha[x];
@ -220,9 +217,8 @@ void WebPMultRows(uint8_t* ptr, int stride,
#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24) #define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
#endif #endif
#if !WEBP_NEON_OMIT_C_CODE static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first, int w, int h, int stride) {
int w, int h, int stride) {
while (h-- > 0) { while (h-- > 0) {
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
@ -239,7 +235,6 @@ static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first,
rgba += stride; rgba += stride;
} }
} }
#endif // !WEBP_NEON_OMIT_C_CODE
#undef MULTIPLIER #undef MULTIPLIER
#undef PREMULTIPLY #undef PREMULTIPLY
@ -259,9 +254,9 @@ static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
return (x * m) >> 16; return (x * m) >> 16;
} }
static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444, static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
int w, int h, int stride, int w, int h, int stride,
int rg_byte_pos /* 0 or 1 */) { int rg_byte_pos /* 0 or 1 */) {
while (h-- > 0) { while (h-- > 0) {
int i; int i;
for (i = 0; i < w; ++i) { for (i = 0; i < w; ++i) {
@ -280,19 +275,18 @@ static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444,
} }
#undef MULTIPLIER #undef MULTIPLIER
static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444, static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
int w, int h, int stride) { int w, int h, int stride) {
#if (WEBP_SWAP_16BIT_CSP == 1) #ifdef WEBP_SWAP_16BIT_CSP
ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 1); ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
#else #else
ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 0); ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
#endif #endif
} }
#if !WEBP_NEON_OMIT_C_CODE static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
static int DispatchAlpha_C(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 = 0xff; uint32_t alpha_mask = 0xff;
int i, j; int i, j;
@ -309,9 +303,9 @@ static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xff); return (alpha_mask != 0xff);
} }
static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride, static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
int width, int height, int width, int height,
uint32_t* dst, int dst_stride) { uint32_t* dst, int dst_stride) {
int i, j; int i, j;
for (j = 0; j < height; ++j) { for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
@ -322,9 +316,9 @@ static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
} }
} }
static int ExtractAlpha_C(const uint8_t* argb, int argb_stride, static int ExtractAlpha(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) {
uint8_t alpha_mask = 0xff; uint8_t alpha_mask = 0xff;
int i, j; int i, j;
@ -340,66 +334,11 @@ static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
return (alpha_mask == 0xff); return (alpha_mask == 0xff);
} }
static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
int i;
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
}
#endif // !WEBP_NEON_OMIT_C_CODE
//------------------------------------------------------------------------------
static int HasAlpha8b_C(const uint8_t* src, int length) {
while (length-- > 0) if (*src++ != 0xff) return 1;
return 0;
}
static int HasAlpha32b_C(const uint8_t* src, int length) {
int x;
for (x = 0; length-- > 0; x += 4) if (src[x] != 0xff) return 1;
return 0;
}
//------------------------------------------------------------------------------
// Simple channel manipulations.
static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
}
#ifdef WORDS_BIGENDIAN
static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
const uint8_t* b, int len, uint32_t* out) {
int i;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
}
}
#endif
static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
int len, int step, uint32_t* out) {
int i, offset = 0;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
offset += step;
}
}
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int); void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int); void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int); int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int); void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int); int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
#ifdef WORDS_BIGENDIAN
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
const uint8_t* b, int, uint32_t*);
#endif
void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
int len, int step, uint32_t* out);
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Init function // Init function
@ -407,27 +346,20 @@ int (*WebPHasAlpha32b)(const uint8_t* src, int length);
extern void WebPInitAlphaProcessingMIPSdspR2(void); extern void WebPInitAlphaProcessingMIPSdspR2(void);
extern void WebPInitAlphaProcessingSSE2(void); extern void WebPInitAlphaProcessingSSE2(void);
extern void WebPInitAlphaProcessingSSE41(void); extern void WebPInitAlphaProcessingSSE41(void);
extern void WebPInitAlphaProcessingNEON(void);
WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) { static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
WebPMultARGBRow = WebPMultARGBRow_C; (VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
WebPMultRow = WebPMultRow_C;
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C;
#ifdef WORDS_BIGENDIAN WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
WebPPackARGB = PackARGB_C; if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
#endif
WebPPackRGB = PackRGB_C;
#if !WEBP_NEON_OMIT_C_CODE
WebPApplyAlphaMultiply = ApplyAlphaMultiply_C;
WebPDispatchAlpha = DispatchAlpha_C;
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
WebPExtractAlpha = ExtractAlpha_C;
WebPExtractGreen = ExtractGreen_C;
#endif
WebPHasAlpha8b = HasAlpha8b_C; WebPMultARGBRow = WebPMultARGBRowC;
WebPHasAlpha32b = HasAlpha32b_C; WebPMultRow = WebPMultRowC;
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
WebPDispatchAlpha = DispatchAlpha;
WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
WebPExtractAlpha = ExtractAlpha;
// If defined, use CPUInfo() to overwrite some pointers with faster versions. // If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) { if (VP8GetCPUInfo != NULL) {
@ -447,26 +379,5 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
} }
#endif #endif
} }
alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
#if defined(WEBP_USE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitAlphaProcessingNEON();
}
#endif
assert(WebPMultARGBRow != NULL);
assert(WebPMultRow != NULL);
assert(WebPApplyAlphaMultiply != NULL);
assert(WebPApplyAlphaMultiply4444 != NULL);
assert(WebPDispatchAlpha != NULL);
assert(WebPDispatchAlphaToGreen != NULL);
assert(WebPExtractAlpha != NULL);
assert(WebPExtractGreen != NULL);
#ifdef WORDS_BIGENDIAN
assert(WebPPackARGB != NULL);
#endif
assert(WebPPackRGB != NULL);
assert(WebPHasAlpha8b != NULL);
assert(WebPHasAlpha32b != NULL);
} }

View File

@ -12,13 +12,13 @@
// Author(s): Branimir Vasic (branimir.vasic@imgtec.com) // Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
// Djordje Pesut (djordje.pesut@imgtec.com) // Djordje Pesut (djordje.pesut@imgtec.com)
#include "src/dsp/dsp.h" #include "./dsp.h"
#if defined(WEBP_USE_MIPS_DSP_R2) #if defined(WEBP_USE_MIPS_DSP_R2)
static int DispatchAlpha_MIPSdspR2(const uint8_t* alpha, int alpha_stride, static int DispatchAlpha(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 = 0xffffffff; uint32_t alpha_mask = 0xffffffff;
int i, j, temp0; int i, j, temp0;
@ -79,8 +79,7 @@ static int DispatchAlpha_MIPSdspR2(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xff); return (alpha_mask != 0xff);
} }
static void MultARGBRow_MIPSdspR2(uint32_t* const ptr, int width, static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
int inverse) {
int x; int x;
const uint32_t c_00ffffff = 0x00ffffffu; const uint32_t c_00ffffff = 0x00ffffffu;
const uint32_t c_ff000000 = 0xff000000u; const uint32_t c_ff000000 = 0xff000000u;
@ -125,100 +124,14 @@ static void MultARGBRow_MIPSdspR2(uint32_t* const ptr, int width,
} }
} }
#ifdef WORDS_BIGENDIAN
static void PackARGB_MIPSdspR2(const uint8_t* a, const uint8_t* r,
const uint8_t* g, const uint8_t* b, int len,
uint32_t* out) {
int temp0, temp1, temp2, temp3, offset;
const int rest = len & 1;
const uint32_t* const loop_end = out + len - rest;
const int step = 4;
__asm__ volatile (
"xor %[offset], %[offset], %[offset] \n\t"
"beq %[loop_end], %[out], 0f \n\t"
"2: \n\t"
"lbux %[temp0], %[offset](%[a]) \n\t"
"lbux %[temp1], %[offset](%[r]) \n\t"
"lbux %[temp2], %[offset](%[g]) \n\t"
"lbux %[temp3], %[offset](%[b]) \n\t"
"ins %[temp1], %[temp0], 16, 16 \n\t"
"ins %[temp3], %[temp2], 16, 16 \n\t"
"addiu %[out], %[out], 4 \n\t"
"precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t"
"sw %[temp0], -4(%[out]) \n\t"
"addu %[offset], %[offset], %[step] \n\t"
"bne %[loop_end], %[out], 2b \n\t"
"0: \n\t"
"beq %[rest], $zero, 1f \n\t"
"lbux %[temp0], %[offset](%[a]) \n\t"
"lbux %[temp1], %[offset](%[r]) \n\t"
"lbux %[temp2], %[offset](%[g]) \n\t"
"lbux %[temp3], %[offset](%[b]) \n\t"
"ins %[temp1], %[temp0], 16, 16 \n\t"
"ins %[temp3], %[temp2], 16, 16 \n\t"
"precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t"
"sw %[temp0], 0(%[out]) \n\t"
"1: \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[temp3]"=&r"(temp3), [offset]"=&r"(offset), [out]"+&r"(out)
: [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step),
[loop_end]"r"(loop_end), [rest]"r"(rest)
: "memory"
);
}
#endif // WORDS_BIGENDIAN
static void PackRGB_MIPSdspR2(const uint8_t* r, const uint8_t* g,
const uint8_t* b, int len, int step,
uint32_t* out) {
int temp0, temp1, temp2, offset;
const int rest = len & 1;
const int a = 0xff;
const uint32_t* const loop_end = out + len - rest;
__asm__ volatile (
"xor %[offset], %[offset], %[offset] \n\t"
"beq %[loop_end], %[out], 0f \n\t"
"2: \n\t"
"lbux %[temp0], %[offset](%[r]) \n\t"
"lbux %[temp1], %[offset](%[g]) \n\t"
"lbux %[temp2], %[offset](%[b]) \n\t"
"ins %[temp0], %[a], 16, 16 \n\t"
"ins %[temp2], %[temp1], 16, 16 \n\t"
"addiu %[out], %[out], 4 \n\t"
"precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t"
"sw %[temp0], -4(%[out]) \n\t"
"addu %[offset], %[offset], %[step] \n\t"
"bne %[loop_end], %[out], 2b \n\t"
"0: \n\t"
"beq %[rest], $zero, 1f \n\t"
"lbux %[temp0], %[offset](%[r]) \n\t"
"lbux %[temp1], %[offset](%[g]) \n\t"
"lbux %[temp2], %[offset](%[b]) \n\t"
"ins %[temp0], %[a], 16, 16 \n\t"
"ins %[temp2], %[temp1], 16, 16 \n\t"
"precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t"
"sw %[temp0], 0(%[out]) \n\t"
"1: \n\t"
: [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
[offset]"=&r"(offset), [out]"+&r"(out)
: [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step),
[loop_end]"r"(loop_end), [rest]"r"(rest)
: "memory"
);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Entry point // Entry point
extern void WebPInitAlphaProcessingMIPSdspR2(void); extern void WebPInitAlphaProcessingMIPSdspR2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingMIPSdspR2(void) { WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingMIPSdspR2(void) {
WebPDispatchAlpha = DispatchAlpha_MIPSdspR2; WebPDispatchAlpha = DispatchAlpha;
WebPMultARGBRow = MultARGBRow_MIPSdspR2; WebPMultARGBRow = MultARGBRow;
#ifdef WORDS_BIGENDIAN
WebPPackARGB = PackARGB_MIPSdspR2;
#endif
WebPPackRGB = PackRGB_MIPSdspR2;
} }
#else // !WEBP_USE_MIPS_DSP_R2 #else // !WEBP_USE_MIPS_DSP_R2

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