Compare commits

..

2 Commits
1.0.3 ... 0.3.0

Author SHA1 Message Date
3b44c5eb71 libwebp.jar: build w/Java 1.6 for Android compat
broken since:
 a5c297c swig/java: reduce wrapper function code duplication

this was a part of v0.3.1, but not v0.3.0.

Change-Id: I001d4bd0a7a1aa1b2d267bc63bc1d8226bff00c1
(cherry picked from commit de899516c7)
2013-10-16 19:17:16 +02:00
c28544a420 fix memleak in WebPIDelete()
happens when decoding is partial (past Partition0), without error and
interrupted by calling WebPIDelete()

WebPIDelete() needs to call VP8ExitCritical() to free in-flight resources

Change-Id: Id4faef1b92f7edd8c17d642c58860e70dd570506
(cherry picked from commit 40ae3520b1)
2013-10-16 19:16:53 +02:00
296 changed files with 20329 additions and 70275 deletions

1
.gitattributes vendored
View File

@ -2,4 +2,3 @@
.gitignore export-ignore .gitignore export-ignore
.mailmap export-ignore .mailmap export-ignore
*.pdf -text -diff *.pdf -text -diff
*.ppm -text -diff

13
.gitignore vendored
View File

@ -1,6 +1,5 @@
*.l[ao] *.l[ao]
*.[ao] *.[ao]
*.pc
.deps .deps
.libs .libs
/aclocal.m4 /aclocal.m4
@ -15,27 +14,15 @@
/libtool /libtool
/ltmain.sh /ltmain.sh
/missing /missing
/mkinstalldirs
/stamp-h1 /stamp-h1
Makefile Makefile
Makefile.in Makefile.in
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/stamp-h1
/output /output
/doc/output /doc/output
*.idb *.idb
*.pdb *.pdb
/iosbuild /iosbuild
/WebP.framework /WebP.framework
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
.gradle
/build
extras/get_disto
extras/webp_quality

View File

@ -1,13 +1,6 @@
Johann Koenig <johann.koenig@duck.com> <johann.koenig@duck.com> <johannkoenig@google.com>
Johann Koenig <johann.koenig@duck.com> <johannkoenig@google.com>
Mikołaj Zalewski <mikolajz@google.com> Mikołaj Zalewski <mikolajz@google.com>
Pascal Massimino <pascal.massimino@gmail.com> Pascal Massimino <pascal.massimino@gmail.com>
Pascal Massimino <pascal.massimino@gmail.com> <skal@google.com>
Vikas Arora <vikasa@google.com> Vikas Arora <vikasa@google.com>
<vikasa@google.com> <vikasa@gmail.com> <vikasa@google.com> <vikasa@gmail.com>
<vikasa@google.com> <vikaas.arora@gmail.com> <vikasa@google.com> <vikaas.arora@gmail.com>
<slobodan.prijic@imgtec.com> <Slobodan.Prijic@imgtec.com>
<vrabaud@google.com> <vincent.rabaud@gmail.com>
Tamar Levy <tamar.levy@intel.com>
<qrczak@google.com> <qrczak>
Hui Su <huisu@google.com>

28
AUTHORS
View File

@ -1,43 +1,17 @@
Contributors: Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Charles Munger (clm at google dot com)
- Christian Duvivier (cduvivier at google dot com) - Christian Duvivier (cduvivier at google dot com)
- Djordje Pesut (djordje dot pesut at imgtec 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 Koenig (johann dot koenig at duck dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com) - Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
- Lode Vandevenne (lode at google dot com)
- Lou Quillio (louquillio at google dot com) - Lou Quillio (louquillio at google dot com)
- Mans Rullgard (mans at mansr dot com) - Mans Rullgard (mans at mansr dot com)
- Marcin Kowalczyk (qrczak at google dot com)
- Martin Olsson (mnemo at minimum dot se) - Martin Olsson (mnemo at minimum dot se)
- Mikołaj Zalewski (mikolajz at google dot com) - Mikołaj Zalewski (mikolajz at google dot com)
- Mislav Bradac (mislavm at google dot com)
- 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)
- 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)
- Pierre Joye (pierre dot php at gmail dot com) - Pierre Joye (pierre dot php at gmail dot com)
- Sam Clegg (sbc at chromium dot org)
- Scott Hancher (seh at google dot com)
- Scott LaVarnway (slavarnway at google dot com) - Scott LaVarnway (slavarnway at google dot com)
- Scott Talbot (s at chikachow dot org)
- Slobodan Prijic (slobodan dot prijic at imgtec dot com)
- Somnath Banerjee (somnath dot banerjee at gmail dot com) - Somnath Banerjee (somnath dot banerjee at gmail dot com)
- Sriraman Tallam (tmsriram at google dot com)
- Tamar Levy (tamar dot levy at intel dot com)
- Timothy Gu (timothygu99 at gmail dot com)
- Urvang Joshi (urvang at google dot com) - Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com) - Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Yang Zhang (yang dot zhang at arm dot com)
- Yannis Guyon (yguyon at google dot com)

View File

@ -1,280 +1,75 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD include $(CLEAR_VARS)
WEBP_CFLAGS += -fvisibility=hidden LOCAL_SRC_FILES := \
src/dec/alpha.c \
src/dec/buffer.c \
src/dec/frame.c \
src/dec/idec.c \
src/dec/io.c \
src/dec/layer.c \
src/dec/quant.c \
src/dec/tree.c \
src/dec/vp8.c \
src/dec/vp8l.c \
src/dec/webp.c \
src/dsp/cpu.c \
src/dsp/dec.c \
src/dsp/dec_sse2.c \
src/dsp/enc.c \
src/dsp/enc_sse2.c \
src/dsp/lossless.c \
src/dsp/upsampling.c \
src/dsp/upsampling_sse2.c \
src/dsp/yuv.c \
src/enc/alpha.c \
src/enc/analysis.c \
src/enc/backward_references.c \
src/enc/config.c \
src/enc/cost.c \
src/enc/filter.c \
src/enc/frame.c \
src/enc/histogram.c \
src/enc/iterator.c \
src/enc/layer.c \
src/enc/picture.c \
src/enc/quant.c \
src/enc/syntax.c \
src/enc/token.c \
src/enc/tree.c \
src/enc/vp8l.c \
src/enc/webpenc.c \
src/utils/bit_reader.c \
src/utils/bit_writer.c \
src/utils/color_cache.c \
src/utils/filters.c \
src/utils/huffman.c \
src/utils/huffman_encode.c \
src/utils/quant_levels.c \
src/utils/quant_levels_dec.c \
src/utils/rescaler.c \
src/utils/thread.c \
src/utils/utils.c \
ifeq ($(APP_OPTIM),release) LOCAL_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD \
WEBP_CFLAGS += -finline-functions -ffast-math \ -DWEBP_USE_THREAD \
-ffunction-sections -fdata-sections -finline-functions -frename-registers -ffast-math \
ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),) -s -fomit-frame-pointer -Isrc/webp
WEBP_CFLAGS += -frename-registers -s
endif
endif
# mips32 fails to build with clang from r14b LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
# 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)),) ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
# 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 LOCAL_SRC_FILES += src/dsp/dec_neon.c.neon
USE_CPUFEATURES := yes LOCAL_SRC_FILES += src/dsp/upsampling_neon.c.neon
WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H LOCAL_SRC_FILES += src/dsp/enc_neon.c.neon
else
NEON := c
endif endif
dec_srcs := \
src/dec/alpha_dec.c \
src/dec/buffer_dec.c \
src/dec/frame_dec.c \
src/dec/idec_dec.c \
src/dec/io_dec.c \
src/dec/quant_dec.c \
src/dec/tree_dec.c \
src/dec/vp8_dec.c \
src/dec/vp8l_dec.c \
src/dec/webp_dec.c \
demux_srcs := \
src/demux/anim_decode.c \
src/demux/demux.c \
dsp_dec_srcs := \
src/dsp/alpha_processing.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_sse41.c \
src/dsp/cpu.c \
src/dsp/dec.c \
src/dsp/dec_clip_tables.c \
src/dsp/dec_mips32.c \
src/dsp/dec_mips_dsp_r2.c \
src/dsp/dec_msa.c \
src/dsp/dec_neon.$(NEON) \
src/dsp/dec_sse2.c \
src/dsp/dec_sse41.c \
src/dsp/filters.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/lossless.c \
src/dsp/lossless_mips_dsp_r2.c \
src/dsp/lossless_msa.c \
src/dsp/lossless_neon.$(NEON) \
src/dsp/lossless_sse2.c \
src/dsp/rescaler.c \
src/dsp/rescaler_mips32.c \
src/dsp/rescaler_mips_dsp_r2.c \
src/dsp/rescaler_msa.c \
src/dsp/rescaler_neon.$(NEON) \
src/dsp/rescaler_sse2.c \
src/dsp/upsampling.c \
src/dsp/upsampling_mips_dsp_r2.c \
src/dsp/upsampling_msa.c \
src/dsp/upsampling_neon.$(NEON) \
src/dsp/upsampling_sse2.c \
src/dsp/upsampling_sse41.c \
src/dsp/yuv.c \
src/dsp/yuv_mips32.c \
src/dsp/yuv_mips_dsp_r2.c \
src/dsp/yuv_neon.$(NEON) \
src/dsp/yuv_sse2.c \
src/dsp/yuv_sse41.c \
dsp_enc_srcs := \
src/dsp/cost.c \
src/dsp/cost_mips32.c \
src/dsp/cost_mips_dsp_r2.c \
src/dsp/cost_neon.$(NEON) \
src/dsp/cost_sse2.c \
src/dsp/enc.c \
src/dsp/enc_mips32.c \
src/dsp/enc_mips_dsp_r2.c \
src/dsp/enc_msa.c \
src/dsp/enc_neon.$(NEON) \
src/dsp/enc_sse2.c \
src/dsp/enc_sse41.c \
src/dsp/lossless_enc.c \
src/dsp/lossless_enc_mips32.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_sse2.c \
src/dsp/lossless_enc_sse41.c \
src/dsp/ssim.c \
src/dsp/ssim_sse2.c \
enc_srcs := \
src/enc/alpha_enc.c \
src/enc/analysis_enc.c \
src/enc/backward_references_cost_enc.c \
src/enc/backward_references_enc.c \
src/enc/config_enc.c \
src/enc/cost_enc.c \
src/enc/filter_enc.c \
src/enc/frame_enc.c \
src/enc/histogram_enc.c \
src/enc/iterator_enc.c \
src/enc/near_lossless_enc.c \
src/enc/picture_enc.c \
src/enc/picture_csp_enc.c \
src/enc/picture_psnr_enc.c \
src/enc/picture_rescale_enc.c \
src/enc/picture_tools_enc.c \
src/enc/predictor_enc.c \
src/enc/quant_enc.c \
src/enc/syntax_enc.c \
src/enc/token_enc.c \
src/enc/tree_enc.c \
src/enc/vp8l_enc.c \
src/enc/webp_enc.c \
mux_srcs := \
src/mux/anim_encode.c \
src/mux/muxedit.c \
src/mux/muxinternal.c \
src/mux/muxread.c \
utils_dec_srcs := \
src/utils/bit_reader_utils.c \
src/utils/color_cache_utils.c \
src/utils/filters_utils.c \
src/utils/huffman_utils.c \
src/utils/quant_levels_dec_utils.c \
src/utils/random_utils.c \
src/utils/rescaler_utils.c \
src/utils/thread_utils.c \
src/utils/utils.c \
utils_enc_srcs := \
src/utils/bit_writer_utils.c \
src/utils/huffman_encode_utils.c \
src/utils/quant_levels_utils.c \
################################################################################
# libwebpdecoder
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(dec_srcs) \
$(dsp_dec_srcs) \
$(utils_dec_srcs) \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
ifeq ($(USE_CPUFEATURES),yes)
LOCAL_STATIC_LIBRARIES := cpufeatures LOCAL_STATIC_LIBRARIES := cpufeatures
endif
LOCAL_MODULE := webpdecoder_static
include $(BUILD_STATIC_LIBRARY)
ifeq ($(ENABLE_SHARED),1)
include $(CLEAR_VARS)
LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
LOCAL_MODULE := webpdecoder
include $(BUILD_SHARED_LIBRARY)
endif # ENABLE_SHARED=1
################################################################################
# libwebp
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(dsp_enc_srcs) \
$(enc_srcs) \
$(utils_enc_srcs) \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
LOCAL_MODULE:= webp LOCAL_MODULE:= webp
ifeq ($(ENABLE_SHARED),1)
include $(BUILD_SHARED_LIBRARY)
else
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
endif
################################################################################
# libwebpdemux
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(demux_srcs)
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
LOCAL_MODULE := webpdemux
ifeq ($(ENABLE_SHARED),1)
LOCAL_SHARED_LIBRARIES := webp
include $(BUILD_SHARED_LIBRARY)
else
LOCAL_STATIC_LIBRARIES := webp
include $(BUILD_STATIC_LIBRARY)
endif
################################################################################
# libwebpmux
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(mux_srcs)
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
# prefer arm over thumb mode for performance gains
LOCAL_ARM_MODE := arm
LOCAL_MODULE := webpmux
ifeq ($(ENABLE_SHARED),1)
LOCAL_SHARED_LIBRARIES := webp
include $(BUILD_SHARED_LIBRARY)
else
LOCAL_STATIC_LIBRARIES := webp
include $(BUILD_STATIC_LIBRARY)
endif
################################################################################
WEBP_SRC_PATH := $(LOCAL_PATH)
include $(WEBP_SRC_PATH)/imageio/Android.mk
include $(WEBP_SRC_PATH)/examples/Android.mk
ifeq ($(USE_CPUFEATURES),yes)
$(call import-module,android/cpufeatures) $(call import-module,android/cpufeatures)
endif

View File

@ -1,672 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(WebP C)
# Options for coder / decoder executables.
option(WEBP_ENABLE_SIMD "Enable any SIMD optimization." ON)
option(WEBP_BUILD_ANIM_UTILS "Build animation utilities." ON)
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." ON)
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." ON)
option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON)
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON)
option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON)
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON)
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
option(WEBP_BUILD_EXTRAS "Build extras." ON)
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
OFF)
set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2)
# Option needed for handling Unicode file names on Windows.
if(WIN32)
option(WEBP_UNICODE "Build Unicode executables." ON)
endif()
if(WEBP_BUILD_WEBP_JS)
set(WEBP_ENABLE_SIMD OFF)
set(WEBP_BUILD_ANIM_UTILS OFF)
set(WEBP_BUILD_CWEBP OFF)
set(WEBP_BUILD_DWEBP OFF)
set(WEBP_BUILD_GIF2WEBP OFF)
set(WEBP_BUILD_IMG2WEBP OFF)
set(WEBP_BUILD_VWEBP OFF)
set(WEBP_BUILD_WEBPINFO OFF)
set(WEBP_BUILD_WEBPMUX OFF)
set(WEBP_BUILD_EXTRAS OFF)
endif()
set(WEBP_DEP_LIBRARIES)
set(WEBP_DEP_INCLUDE_DIRS)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release"
CACHE "Build type: Release, Debug, MinSizeRel or RelWithDebInfo" STRING
FORCE)
endif()
# Include dependencies.
include(cmake/deps.cmake)
include(GNUInstallDirs)
# ##############################################################################
# Options.
if(WEBP_ENABLE_SWAP_16BIT_CSP)
add_definitions(-DWEBP_SWAP_16BIT_CSP=1)
endif()
if(NOT WEBP_BITTRACE STREQUAL "0")
add_definitions(-DBITTRACE=${WEBP_BITTRACE})
endif()
if(WEBP_UNICODE)
# Windows recommends setting both UNICODE and _UNICODE.
add_definitions(-DUNICODE -D_UNICODE)
endif()
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\$\{prefix\}")
set(libdir "\$\{prefix\}/lib")
set(includedir "\$\{prefix\}/include")
set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT})
set(INSTALLED_LIBRARIES)
# ##############################################################################
# Android only.
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures STATIC
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
list(APPEND INSTALLED_LIBRARIES cpufeatures)
target_link_libraries(cpufeatures dl)
set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures)
set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS}
${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()
function(configure_pkg_config FILE)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}.in"
"${CMAKE_CURRENT_BINARY_DIR}/${FILE}")
if(HAVE_MATH_LIBRARY)
# MSVC doesn't have libm
file(READ ${CMAKE_CURRENT_BINARY_DIR}/${FILE} data)
string(REPLACE "-lm" "" data ${data})
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${FILE} ${data})
endif()
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
endfunction()
# ##############################################################################
# WebP source files. Read the Makefile.am to get the source files.
# We expect the Makefiles to define the sources as defined in the first regex.
# E.g.: libimagedec_la_SOURCES = image_dec.c image_dec.h
function(parse_Makefile_am FOLDER VAR SRC_REGEX)
file(READ ${FOLDER}/Makefile.am MAKEFILE_AM)
string(REGEX MATCHALL
"${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*"
FILES_PER_LINE
${MAKEFILE_AM})
set(SRCS ${${VAR}})
foreach(FILES ${FILES_PER_LINE})
string(FIND ${FILES} "=" OFFSET)
math(EXPR OFFSET "${OFFSET} + 2")
string(SUBSTRING ${FILES}
${OFFSET}
-1
FILES)
if(FILES)
string(REGEX MATCHALL
"[0-9a-z\\._]+"
FILES
${FILES})
foreach(FILE ${FILES})
list(APPEND SRCS ${FOLDER}/${FILE})
endforeach()
endif()
endforeach()
set(${VAR} ${SRCS} PARENT_SCOPE)
endfunction()
set(WEBP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
parse_makefile_am(${WEBP_SRC_DIR}/dec "WEBP_DEC_SRCS" "")
parse_makefile_am(${WEBP_SRC_DIR}/demux "WEBP_DEMUX_SRCS" "")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_COMMON_SRCS" "COMMON")
parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "ENC")
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.
foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE})
list(REMOVE_ITEM WEBP_DSP_ENC_SRCS ${FILE})
list(REMOVE_ITEM WEBP_DSP_DEC_SRCS ${FILE})
endforeach()
# 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)
# ##############################################################################
# Build the webpdecoder library.
if(MSVC)
# avoid security warnings for e.g., fopen() used in the examples.
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_definitions(-Wall)
endif()
include_directories(${WEBP_DEP_INCLUDE_DIRS})
add_library(webpdecode OBJECT ${WEBP_DEC_SRCS})
target_include_directories(webpdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS})
target_include_directories(webpdspdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputilsdecode
OBJECT
${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS})
target_include_directories(webputilsdecode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdecoder
$<TARGET_OBJECTS:webpdecode>
$<TARGET_OBJECTS:webpdspdecode>
$<TARGET_OBJECTS:webputilsdecode>)
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
target_include_directories(
webpdecoder
PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
set_target_properties(
webpdecoder
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/libwebpdecoder.pc")
# Build the webp library.
add_library(webpencode OBJECT ${WEBP_ENC_SRCS})
target_include_directories(webpencode
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webpdsp
OBJECT
${WEBP_DSP_COMMON_SRCS}
${WEBP_DSP_DEC_SRCS}
${WEBP_DSP_ENC_SRCS})
target_include_directories(webpdsp
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webputils
OBJECT
${WEBP_UTILS_COMMON_SRCS}
${WEBP_UTILS_DEC_SRCS}
${WEBP_UTILS_ENC_SRCS})
target_include_directories(webputils
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
add_library(webp
$<TARGET_OBJECTS:webpdecode>
$<TARGET_OBJECTS:webpdsp>
$<TARGET_OBJECTS:webpencode>
$<TARGET_OBJECTS:webputils>)
target_link_libraries(webp ${WEBP_DEP_LIBRARIES})
target_include_directories(webp
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
set_target_properties(
webp
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
# Make sure the OBJECT libraries are built with position independent code (it is
# not ON by default).
set_target_properties(webpdecode
webpdspdecode
webputilsdecode
webpencode
webpdsp
webputils
PROPERTIES POSITION_INDEPENDENT_CODE ON)
configure_pkg_config("src/libwebp.pc")
# Build the webp demux library.
add_library(webpdemux ${WEBP_DEMUX_SRCS})
target_link_libraries(webpdemux webp)
target_include_directories(webpdemux
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
PUBLIC $<INSTALL_INTERFACE:include>)
set_target_properties(
webpdemux
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h")
configure_pkg_config("src/demux/libwebpdemux.pc")
# Set 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})
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE)
string(REGEX MATCH
"AC_INIT\\([^\n]*\\[[0-9\\.]+\\]"
TMP
${CONFIGURE_FILE})
string(REGEX MATCH
"[0-9\\.]+"
PROJECT_VERSION
${TMP})
# Define the libraries to install.
list(APPEND INSTALLED_LIBRARIES webpdecoder webp webpdemux)
# Deal with SIMD. Change the compile flags for SIMD files we use.
list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH)
math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE
"${WEBP_SIMD_FILES_TO_INCLUDE_LENGTH}-1")
foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE})
list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE)
list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG)
set_source_files_properties(${FILE}
PROPERTIES
COMPILE_FLAGS
${SIMD_COMPILE_FLAG})
endforeach()
if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND)
set(WEBP_BUILD_GIF2WEBP OFF)
endif()
if(WEBP_BUILD_ANIM_UTILS AND NOT GIF_FOUND)
set(WEBP_BUILD_ANIM_UTILS OFF)
endif()
# Build the executables if asked for.
if(WEBP_BUILD_ANIM_UTILS
OR WEBP_BUILD_CWEBP
OR WEBP_BUILD_DWEBP
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP
OR WEBP_BUILD_VWEBP)
# Example utility library.
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS"
"example_util_[^ ]*")
list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h)
add_library(exampleutil ${EXAMPLEUTIL_SRCS})
target_include_directories(
exampleutil
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS"
"imageio_util_[^ ]*")
add_library(imageioutil ${IMAGEIOUTILS_SRCS})
target_link_libraries(imageioutil webp)
# Image-decoding utility library.
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS"
"imagedec_[^ ]*")
add_library(imagedec ${IMAGEDEC_SRCS})
target_link_libraries(imagedec
imageioutil
webpdemux
webp
${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()
if(WEBP_BUILD_DWEBP)
# dwebp
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "DWEBP_SRCS" "dwebp")
add_executable(dwebp ${DWEBP_SRCS})
target_link_libraries(dwebp exampleutil imagedec imageenc)
target_include_directories(dwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS dwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_CWEBP)
# cwebp
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" "cwebp")
add_executable(cwebp ${CWEBP_SRCS})
target_link_libraries(cwebp exampleutil imagedec webp)
target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_GIF2WEBP OR WEBP_BUILD_IMG2WEBP)
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "")
add_library(libwebpmux ${WEBP_MUX_SRCS})
target_link_libraries(libwebpmux webp)
target_include_directories(libwebpmux
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})
parse_version(mux/Makefile.am webpmux WEBP_MUX_SOVERSION)
set_target_properties(libwebpmux
PROPERTIES VERSION
${PACKAGE_VERSION}
SOVERSION
${WEBP_MUX_SOVERSION})
set_target_properties(libwebpmux
PROPERTIES PUBLIC_HEADER
"${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\
${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;")
set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux)
list(APPEND INSTALLED_LIBRARIES libwebpmux)
configure_pkg_config("src/mux/libwebpmux.pc")
endif()
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
libwebpmux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
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
libwebpmux)
target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_VWEBP)
# vwebp
find_package(GLUT)
if(GLUT_FOUND)
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "VWEBP_SRCS" "vwebp")
add_executable(vwebp ${VWEBP_SRCS})
target_link_libraries(vwebp
${OPENGL_LIBRARIES}
exampleutil
GLUT::GLUT
imageioutil
webp
webpdemux)
target_include_directories(vwebp
PRIVATE GLUT::GLUT
${CMAKE_CURRENT_BINARY_DIR}/src
${OPENGL_INCLUDE_DIR})
install(TARGETS vwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
check_c_compiler_flag("-Wno-deprecated-declarations" HAS_NO_DEPRECATED)
if(HAS_NO_DEPRECATED)
target_compile_options(vwebp PRIVATE "-Wno-deprecated-declarations")
endif()
endif()
endif()
endif()
if(WEBP_BUILD_WEBPINFO)
# webpinfo
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPINFO_SRCS"
"webpinfo")
add_executable(webpinfo ${WEBPINFO_SRCS})
target_link_libraries(webpinfo exampleutil imageioutil)
target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_WEBPMUX)
# webpmux
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS"
"webpmux")
add_executable(webpmux ${WEBPMUX_SRCS})
target_link_libraries(webpmux exampleutil imageioutil libwebpmux webp)
target_include_directories(webpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS webpmux RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(WEBP_BUILD_EXTRAS)
set(EXTRAS_MAKEFILE "${CMAKE_CURRENT_SOURCE_DIR}/extras")
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_EXTRAS_SRCS" "libwebpextras_la")
parse_makefile_am(${EXTRAS_MAKEFILE} "GET_DISTO_SRCS" "get_disto")
parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality")
parse_makefile_am(${EXTRAS_MAKEFILE} "VWEBP_SDL_SRCS" "vwebp_sdl")
# get_disto
add_executable(get_disto ${GET_DISTO_SRCS})
target_link_libraries(get_disto imagedec)
target_include_directories(get_disto
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
install(TARGETS get_disto RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# webp_quality
add_executable(webp_quality ${WEBP_QUALITY_SRCS} ${WEBP_EXTRAS_SRCS})
target_link_libraries(webp_quality exampleutil imagedec)
target_include_directories(webp_quality PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS webp_quality RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# vwebp_sdl
find_package(SDL)
if(SDL_FOUND)
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
target_include_directories(vwebp_sdl
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/src
${SDL_INCLUDE_DIR})
set(WEBP_HAVE_SDL 1)
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
install(TARGETS vwebp_sdl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
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)
target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
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)
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(
webp_wasm
PROPERTIES LINK_FLAGS "-s WASM=1 \
-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(webpdspdecode PUBLIC EMSCRIPTEN)
endif()
if(WEBP_BUILD_ANIM_UTILS)
# anim_diff
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DIFF_SRCS"
"anim_diff")
add_executable(anim_diff ${ANIM_DIFF_SRCS})
target_link_libraries(anim_diff
exampleutil
imagedec
imageenc
imageioutil
webp
libwebpmux
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
# anim_dump
include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS})
parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DUMP_SRCS"
"anim_dump")
add_executable(anim_dump ${ANIM_DUMP_SRCS})
target_link_libraries(anim_dump
exampleutil
imagedec
imageenc
imageioutil
webp
libwebpmux
webpdemux
${WEBP_DEP_GIF_LIBRARIES})
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
endif()
# Install the different headers and libraries.
include(GNUInstallDirs)
install(TARGETS ${INSTALLED_LIBRARIES}
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
set(ConfigPackageLocation ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/)
install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${ConfigPackageLocation})
# Create the CMake version file.
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion)
# Create the Config file.
include(CMakePackageConfigHelpers)
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_MANDIR}/man1
COMPONENT doc)
endif()
endforeach()

5394
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 BUILD_EXTRAS
SUBDIRS += extras
endif
SUBDIRS += examples

View File

@ -11,8 +11,6 @@ LIBWEBPDEMUX_BASENAME = libwebpdemux
ARCH = x86 ARCH = x86
!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ] !ELSE IF ! [ cl 2>&1 | find "x64" > NUL ]
ARCH = x64 ARCH = x64
!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ]
ARCH = ARM
!ELSE !ELSE
!ERROR Unable to auto-detect toolchain architecture! \ !ERROR Unable to auto-detect toolchain architecture! \
If cl.exe is in your PATH rerun nmake with ARCH=<arch>. If cl.exe is in your PATH rerun nmake with ARCH=<arch>.
@ -29,22 +27,15 @@ PLATFORM_LDFLAGS = /SAFESEH
NOLOGO = /nologo NOLOGO = /nologo
CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG
CCDEBUG = cl.exe $(NOLOGO) /Od /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 /GS
CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN
CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE
LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS) LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS)
LNKDLL = link.exe /DLL $(NOLOGO) LNKDLL = link.exe /DLL $(NOLOGO)
LNKEXE = link.exe $(NOLOGO) LNKEXE = link.exe $(NOLOGO)
LNKLIB = lib.exe $(NOLOGO) LNKLIB = lib.exe $(NOLOGO)
MT = mt.exe $(NOLOGO) MT = mt.exe $(NOLOGO)
RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English
RCDEBUG = $(RCNODBG) /D_DEBUG
!IF "$(ARCH)" == "ARM"
CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD
!ELSE
CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD
!ENDIF
CFGSET = FALSE CFGSET = FALSE
!IF "$(OBJDIR)" == "" !IF "$(OBJDIR)" == ""
@ -58,11 +49,6 @@ OUTDIR = $(OBJDIR)
!IF "$(RTLIBCFG)" == "static" !IF "$(RTLIBCFG)" == "static"
RTLIB = /MT RTLIB = /MT
RTLIBD = /MTd RTLIBD = /MTd
!ELSE IF "$(RTLIBCFG)" == "legacy"
RTLIBCFG = static
RTLIB = /MT
RTLIBD = /MTd
CFLAGS = $(CFLAGS) /GS- /arch:IA32
!ELSE !ELSE
RTLIB = /MD RTLIB = /MD
RTLIBD = /MDd RTLIBD = /MDd
@ -79,8 +65,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 \
@ -98,11 +82,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
@ -119,7 +101,9 @@ LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib
LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib
LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib
!ELSE IF "$(DLLBUILD)" == "TRUE" !ELSE IF "$(DLLBUILD)" == "TRUE"
DLLC = webp_dll.c
DLLINC = webp_dll.h DLLINC = webp_dll.h
DLL_OBJS = $(DIROBJ)\$(DLLC:.c=.obj)
CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL
LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib
LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib
@ -129,16 +113,12 @@ LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb
CFGSET = TRUE CFGSET = TRUE
!ENDIF !ENDIF
!IF "$(UNICODE)" == "1"
CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
!ENDIF
####################### #######################
# Usage # Usage
# #
!IF "$(CFGSET)" == "FALSE" !IF "$(CFGSET)" == "FALSE"
!MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>] !MESSAGE Usage: nmake /f Makefile.vc [CFG=<config>]
!MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [UNICODE=1] [<target>] !MESSAGE . [OBJDIR=<path>] [RTLIBCFG=<rtlib>] [<target>]
!MESSAGE !MESSAGE
!MESSAGE where <config> is one of: !MESSAGE where <config> is one of:
!MESSAGE - release-static - release static library !MESSAGE - release-static - release static library
@ -152,12 +132,8 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
!MESSAGE . features enabled. !MESSAGE . features enabled.
!MESSAGE - (empty) - build libwebp-based targets for CFG !MESSAGE - (empty) - build libwebp-based targets for CFG
!MESSAGE - all - build (de)mux-based targets for CFG !MESSAGE - all - build (de)mux-based targets for CFG
!MESSAGE - gif2webp - requires libgif & >= VS2013
!MESSAGE - anim_diff - requires libgif & >= VS2013
!MESSAGE - anim_dump
!MESSAGE !MESSAGE
!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 OBJDIR is the path where you like to build (obj, bins, etc.), !MESSAGE OBJDIR is the path where you like to build (obj, bins, etc.),
!MESSAGE defaults to ..\obj !MESSAGE defaults to ..\obj
@ -175,163 +151,85 @@ CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE
# #
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\layer.obj \
$(DIROBJ)\dec\tree_dec.obj \ $(DIROBJ)\dec\quant.obj \
$(DIROBJ)\dec\vp8_dec.obj \ $(DIROBJ)\dec\tree.obj \
$(DIROBJ)\dec\vp8l_dec.obj \ $(DIROBJ)\dec\vp8.obj \
$(DIROBJ)\dec\webp_dec.obj \ $(DIROBJ)\dec\vp8l.obj \
$(DIROBJ)\dec\webp.obj \
DEMUX_OBJS = \ DEMUX_OBJS = \
$(DIROBJ)\demux\anim_decode.obj \
$(DIROBJ)\demux\demux.obj \ $(DIROBJ)\demux\demux.obj \
DSP_DEC_OBJS = \ DSP_DEC_OBJS = \
$(DIROBJ)\dsp\alpha_processing.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_sse41.obj \
$(DIROBJ)\dsp\cpu.obj \ $(DIROBJ)\dsp\cpu.obj \
$(DIROBJ)\dsp\dec.obj \ $(DIROBJ)\dsp\dec.obj \
$(DIROBJ)\dsp\dec_clip_tables.obj \
$(DIROBJ)\dsp\dec_mips32.obj \
$(DIROBJ)\dsp\dec_mips_dsp_r2.obj \
$(DIROBJ)\dsp\dec_msa.obj \
$(DIROBJ)\dsp\dec_neon.obj \ $(DIROBJ)\dsp\dec_neon.obj \
$(DIROBJ)\dsp\dec_sse2.obj \ $(DIROBJ)\dsp\dec_sse2.obj \
$(DIROBJ)\dsp\dec_sse41.obj \
$(DIROBJ)\dsp\filters.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\lossless.obj \ $(DIROBJ)\dsp\lossless.obj \
$(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \
$(DIROBJ)\dsp\lossless_msa.obj \
$(DIROBJ)\dsp\lossless_neon.obj \
$(DIROBJ)\dsp\lossless_sse2.obj \
$(DIROBJ)\dsp\rescaler.obj \
$(DIROBJ)\dsp\rescaler_mips32.obj \
$(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \
$(DIROBJ)\dsp\rescaler_msa.obj \
$(DIROBJ)\dsp\rescaler_neon.obj \
$(DIROBJ)\dsp\rescaler_sse2.obj \
$(DIROBJ)\dsp\upsampling.obj \ $(DIROBJ)\dsp\upsampling.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_mips_dsp_r2.obj \
$(DIROBJ)\dsp\yuv_neon.obj \
$(DIROBJ)\dsp\yuv_sse2.obj \
$(DIROBJ)\dsp\yuv_sse41.obj \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
$(DIROBJ)\dsp\cost.obj \
$(DIROBJ)\dsp\cost_mips32.obj \
$(DIROBJ)\dsp\cost_mips_dsp_r2.obj \
$(DIROBJ)\dsp\cost_neon.obj \
$(DIROBJ)\dsp\cost_sse2.obj \
$(DIROBJ)\dsp\enc.obj \ $(DIROBJ)\dsp\enc.obj \
$(DIROBJ)\dsp\enc_mips32.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\lossless_enc.obj \
$(DIROBJ)\dsp\lossless_enc_mips32.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_sse2.obj \
$(DIROBJ)\dsp\lossless_enc_sse41.obj \
$(DIROBJ)\dsp\ssim.obj \
$(DIROBJ)\dsp\ssim_sse2.obj \
EX_ANIM_UTIL_OBJS = \ EX_FORMAT_DEC_OBJS = \
$(DIROBJ)\examples\anim_util.obj \ $(DIROBJ)\examples\jpegdec.obj \
$(DIROBJ)\examples\metadata.obj \
IMAGEIO_DEC_OBJS = \ $(DIROBJ)\examples\pngdec.obj \
$(DIROBJ)\imageio\image_dec.obj \ $(DIROBJ)\examples\tiffdec.obj \
$(DIROBJ)\imageio\jpegdec.obj \ $(DIROBJ)\examples\wicdec.obj \
$(DIROBJ)\imageio\metadata.obj \
$(DIROBJ)\imageio\pngdec.obj \
$(DIROBJ)\imageio\pnmdec.obj \
$(DIROBJ)\imageio\tiffdec.obj \
$(DIROBJ)\imageio\webpdec.obj \
$(DIROBJ)\imageio\wicdec.obj \
IMAGEIO_ENC_OBJS = \
$(DIROBJ)\imageio\image_enc.obj \
EX_GIF_DEC_OBJS = \
$(DIROBJ)\examples\gifdec.obj \
EX_UTIL_OBJS = \ 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\filter.obj \
$(DIROBJ)\enc\filter_enc.obj \ $(DIROBJ)\enc\frame.obj \
$(DIROBJ)\enc\frame_enc.obj \ $(DIROBJ)\enc\histogram.obj \
$(DIROBJ)\enc\histogram_enc.obj \ $(DIROBJ)\enc\iterator.obj \
$(DIROBJ)\enc\iterator_enc.obj \ $(DIROBJ)\enc\layer.obj \
$(DIROBJ)\enc\near_lossless_enc.obj \ $(DIROBJ)\enc\picture.obj \
$(DIROBJ)\enc\picture_enc.obj \ $(DIROBJ)\enc\quant.obj \
$(DIROBJ)\enc\picture_csp_enc.obj \ $(DIROBJ)\enc\syntax.obj \
$(DIROBJ)\enc\picture_psnr_enc.obj \ $(DIROBJ)\enc\token.obj \
$(DIROBJ)\enc\picture_rescale_enc.obj \ $(DIROBJ)\enc\tree.obj \
$(DIROBJ)\enc\picture_tools_enc.obj \ $(DIROBJ)\enc\vp8l.obj \
$(DIROBJ)\enc\predictor_enc.obj \ $(DIROBJ)\enc\webpenc.obj \
$(DIROBJ)\enc\quant_enc.obj \
$(DIROBJ)\enc\syntax_enc.obj \
$(DIROBJ)\enc\token_enc.obj \
$(DIROBJ)\enc\tree_enc.obj \
$(DIROBJ)\enc\vp8l_enc.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\muxedit.obj \ $(DIROBJ)\mux\muxedit.obj \
$(DIROBJ)\mux\muxinternal.obj \ $(DIROBJ)\mux\muxinternal.obj \
$(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\thread.obj \
$(DIROBJ)\utils\thread_utils.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) \
@ -340,67 +238,24 @@ LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS) LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS)
OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP)
!IF "$(ARCH)" == "ARM"
ex: $(OUT_LIBS)
all: ex
!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)
# NB: gif2webp.exe and anim_diff.exe are excluded from 'all' as libgif requires $(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(EX_FORMAT_DEC_OBJS)
# C99 support which is only available from VS2013 onward. $(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj
gif2webp: $(DIRBIN)\gif2webp.exe $(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj
anim_diff: $(DIRBIN)\anim_diff.exe $(DIRBIN)\vwebp.exe: $(EX_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
anim_dump: $(DIRBIN)\anim_dump.exe
$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS)
$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS)
$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX)
$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS)
$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX)
$(DIRBIN)\gif2webp.exe: $(LIBWEBP)
$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS)
$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP)
$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj
$(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 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)
@ -411,29 +266,20 @@ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): $(OUTPUT_DIRS)
!IF "$(DLLBUILD)" == "TRUE" !IF "$(DLLBUILD)" == "TRUE"
$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \ $(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS): \
$(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLINC) $(DIROBJ)\$(DLLC)
{$(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) $**
-xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y
clean:: clean::
@-erase /s $(DIROBJ)\$(DLLINC) 2> NUL @-erase /s $(DIROBJ)\$(DLLC) $(DIROBJ)\$(DLLINC) 2> NUL
!ELSE !ELSE
$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX): $(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX):
$(LNKLIB) /out:$@ $** $(LNKLIB) /out:$@ $**
@ -447,34 +293,22 @@ $(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_ */ >> $@
# expose a WebPFree() function for use in managed code
$(DIROBJ)\$(DLLC): $(DIROBJ)\$(DLLINC)
@echo #include ^<stdlib.h^> > $@
@echo #include "webp_dll.h" >> $@
@echo // This function should be used in place of free() for memory >> $@
@echo // returned by the WebP API. >> $@
@echo WEBP_EXTERN(void) WebPFree(void* ptr) { >> $@
@echo free(ptr); >> $@
@echo } >> $@
.SUFFIXES: .c .obj .res .exe .SUFFIXES: .c .obj .res .exe
# File-specific flag builds. Note batch rules take precedence over wildcards,
# so for now name each file individually.
$(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\gif2webp.obj: examples\gif2webp.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
$(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
$(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \
/Fo$(DIROBJ)\examples\ examples\$(@B).c
# 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::
@ -488,18 +322,9 @@ $(DIROBJ)\examples\gifdec.obj: examples\gifdec.c
{src\utils}.c{$(DIROBJ)\utils}.obj:: {src\utils}.c{$(DIROBJ)\utils}.obj::
$(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $< $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $<
LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib
!IF "$(UNICODE)" == "1"
LNKLIBS = $(LNKLIBS) Shell32.lib
!ENDIF
{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe: {$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) $(LNKEXE) $(LDFLAGS) /OUT:$@ $** \
$(MT) -manifest $@.manifest -outputresource:$@;1 ole32.lib windowscodecs.lib shlwapi.lib
del $@.manifest
{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe:
$(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS)
$(MT) -manifest $@.manifest -outputresource:$@;1 $(MT) -manifest $@.manifest -outputresource:$@;1
del $@.manifest del $@.manifest

171
NEWS
View File

@ -1,171 +1,3 @@
- 7/4/2019: version 1.0.3
This is a binary compatible release.
* resize fixes for Nx1 sizes and the addition of non-opaque alpha values for
odd sizes (issues #418, #434)
* lossless encode/decode performance improvements
* lossy compression performance improvement at low quality levels with flat
content (issue #432)
* python swig files updated to support python 3
Tool updates:
vwebp will now preserve the aspect ratio of images that exceed monitor
resolution by scaling the image to fit (issue #433)
- 1/14/2019: version 1.0.2
This is a binary compatible release.
* (Windows) unicode file support in the tools (linux and mac already had
support, issue #398)
* lossless encoder speedups
* lossy encoder speedup on ARM
* lossless multi-threaded security fix (chromium:917029)
- 11/2/2018: version 1.0.1
This is a binary compatible release.
* lossless encoder speedups
* big-endian fix for alpha decoding (issue #393)
* gif2webp fix for loop count=65535 transcode (issue #382)
* further security related hardening in libwebp & libwebpmux
(issues #383, #385, #386, #387, #388, #391)
(oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170,
#9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349,
#10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152)
* miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400)
- 4/2/2018: version 1.0.0
This is a binary compatible release.
* lossy encoder improvements to avoid chroma shifts in various circumstances
(issues #308, #340)
* big-endian fixes for decode, RGBA import and WebPPictureDistortion
Tool updates:
gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
web browsers, transcoding tools (issue #379)
img2webp, webpmux - allow options to be passed in via a file (issue #355)
- 11/24/2017: version 0.6.1
This is a binary compatible release.
* lossless performance and compression improvements + a new 'cruncher' mode
(-m 6 -q 100)
* ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
* webp-js: emscripten/webassembly based javascript decoder
* miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
#363)
Tool updates / additions:
added webpinfo - prints file format information (issue #330)
gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
'-loop_compatibility' can be used for the old behavior
- 1/26/2017: version 0.6.0
* lossless performance and compression improvements
* miscellaneous performance improvements (SSE2, NEON, MSA)
* 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
This is a binary compatible release.
This release covers CVE-2016-8888 and CVE-2016-9085.
* further security related hardening in the tools; fixes to
gif2webp/AnimEncoder (issues #310, #314, #316, #322), cwebp/libwebp (issue
#312)
* full libwebp (encoder & decoder) iOS framework; libwebpdecoder
WebP.framework renamed to WebPDecoder.framework (issue #307)
* CMake support for Android Studio (2.2)
* miscellaneous build related fixes (issue #306, #313)
* miscellaneous documentation improvements (issue #225)
* minor lossy encoder fixes and improvements
- 6/14/2016: version 0.5.1
This is a binary compatible release.
* miscellaneous bug fixes (issues #280, #289)
* reverted alpha plane encoding with color cache for compatibility with
libwebp 0.4.0->0.4.3 (issues #291, #298)
* lossless encoding performance improvements
* memory reduction in both lossless encoding and decoding
* force mux output to be in the extended format (VP8X) when undefined chunks
are present (issue #294)
* gradle, cmake build support
* workaround for compiler bug causing 64-bit decode failures on android
devices using clang-3.8 in the r11c NDK
* various WebPAnimEncoder improvements
- 12/17/2015: version 0.5.0
* miscellaneous bug & build fixes (issues #234, #258, #274, #275, #278)
* encoder & decoder speed-ups on x86/ARM/MIPS for lossy & lossless
- note! YUV->RGB conversion was sped-up, but the results will be slightly
different from previous releases
* various lossless encoder improvements
* gif2webp improvements, -min_size option added
* tools fully support input from stdin and output to stdout (issue #168)
* New WebPAnimEncoder API for creating animations
* New WebPAnimDecoder API for decoding animations
* other API changes:
- libwebp:
WebPPictureSmartARGBToYUVA() (-pre 4 in cwebp)
WebPConfig::exact (-exact in cwebp; -alpha_cleanup is now the default)
WebPConfig::near_lossless (-near_lossless in cwebp)
WebPFree() (free'ing webp allocated memory in other languages)
WebPConfigLosslessPreset()
WebPMemoryWriterClear()
- libwebpdemux: removed experimental fragment related fields and functions
- libwebpmux: WebPMuxSetCanvasSize()
* new libwebpextras library with some uncommon import functions:
WebPImportGray/WebPImportRGB565/WebPImportRGB4444
- 10/15/15: version 0.4.4
This is a binary compatible release.
* rescaling out-of-bounds read fix (issue #254)
* various build fixes and improvements (issues #253, #259, #262, #267, #268)
* container documentation update
* gif2webp transparency fix (issue #245)
- 3/3/15: version 0.4.3
This is a binary compatible release.
* Android / gcc / iOS / MSVS build fixes and improvements
* lossless decode fix (issue #239 -- since 0.4.0)
* documentation / vwebp updates for animation
* multi-threading fix (issue #234)
- 10/13/14: version 0.4.2
This is a binary compatible release.
* Android / gcc build fixes
* (Windows) fix reading from stdin and writing to stdout
* gif2webp: miscellaneous fixes
* fix 'alpha-leak' with lossy compression (issue #220)
* the lossless bitstream spec has been amended to reflect the current code
- 7/24/14: version 0.4.1
This is a binary compatible release.
* AArch64 (arm64) & MIPS support/optimizations
* NEON assembly additions:
- ~25% faster lossy decode / encode (-m 4)
- ~10% faster lossless decode
- ~5-10% faster lossless encode (-m 3/4)
* dwebp/vwebp can read from stdin
* cwebp/gif2webp can write to stdout
* cwebp can read webp files; useful if storing sources as webp lossless
- 12/19/13: version 0.4.0
* improved gif2webp tool
* numerous fixes, compression improvement and speed-up
* dither option added to decoder (dwebp -dither 50 ...)
* improved multi-threaded modes (-mt option)
* improved filtering strength determination
* New function: WebPMuxGetCanvasSize
* BMP and TIFF format output added to 'dwebp'
* Significant memory reduction for decoding lossy images with alpha.
* Intertwined decoding of RGB and alpha for a shorter
time-to-first-decoded-pixel.
* WebPIterator has a new member 'has_alpha' denoting whether the frame
contains transparency.
* Container spec amended with new 'blending method' for animation.
- 6/13/13: version 0.3.1 - 6/13/13: version 0.3.1
This is a binary compatible release. This is a binary compatible release.
* Add incremental decoding support for images containing ALPH and ICCP chunks. * Add incremental decoding support for images containing ALPH and ICCP chunks.
@ -216,8 +48,7 @@
- 9/19/11: version 0.1.3 - 9/19/11: version 0.1.3
* Advanced decoding APIs. * Advanced decoding APIs.
* On-the-fly cropping and rescaling of images. * On-the-fly cropping and rescaling of images.
* SSE2 instructions for decoding performance optimizations on x86 based * SSE2 instructions for decoding performance optimizations on x86 based platforms.
platforms.
* Support Multi-threaded decoding. * Support Multi-threaded decoding.
* 40% improvement in Decoding performance. * 40% improvement in Decoding performance.
* Add support for RGB565, RGBA4444 & ARGB image colorspace. * Add support for RGB565, RGBA4444 & ARGB image colorspace.

39
PATENTS
View File

@ -1,23 +1,22 @@
Additional IP Rights Grant (Patents) Additional IP Rights Grant (Patents)
------------------------------------
"These implementations" means the copyrightable works that implement the WebM "This implementation" means the copyrightable works distributed by
codecs distributed by Google as part of the WebM Project. Google as part of the WebM Project.
Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, Google hereby grants to you a perpetual, worldwide, non-exclusive,
royalty-free, irrevocable (except as stated in this section) patent license to no-charge, royalty-free, irrevocable (except as stated in this section)
make, have made, use, offer to sell, sell, import, transfer, and otherwise patent license to make, have made, use, offer to sell, sell, import,
run, modify and propagate the contents of these implementations of WebM, where transfer, and otherwise run, modify and propagate the contents of this
such license applies only to those patent claims, both currently owned by implementation of VP8, where such license applies only to those patent
Google and acquired in the future, licensable by Google that are necessarily claims, both currently owned by Google and acquired in the future,
infringed by these implementations of WebM. This grant does not include claims licensable by Google that are necessarily infringed by this
that would be infringed only as a consequence of further modification of these implementation of VP8. This grant does not include claims that would be
implementations. If you or your agent or exclusive licensee institute or order infringed only as a consequence of further modification of this
or agree to the institution of patent litigation or any other patent implementation. If you or your agent or exclusive licensee institute or
enforcement activity against any entity (including a cross-claim or order or agree to the institution of patent litigation against any
counterclaim in a lawsuit) alleging that any of these implementations of WebM entity (including a cross-claim or counterclaim in a lawsuit) alleging
or any code incorporated within any of these implementations of WebM that this implementation of VP8 or any code incorporated within this
constitute direct or contributory patent infringement, or inducement of implementation of VP8 constitutes direct or contributory patent
patent infringement, then any patent rights granted to you under this License infringement, or inducement of patent infringement, then any patent
for these implementations of WebM shall terminate as of the date such rights granted to you under this License for this implementation of VP8
litigation is filed. shall terminate as of the date such litigation is filed.

369
README
View File

@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.0.3 \____/____/\_____/_____/____/v0.3.1
Description: Description:
============ ============
@ -15,12 +15,11 @@ as well as the command line tools 'cwebp' and 'dwebp'.
See http://developers.google.com/speed/webp See http://developers.google.com/speed/webp
The latest source tree is available at Latest sources are available from http://www.webmproject.org/code/
https://chromium.googlesource.com/webm/libwebp
It is released under the same license as the WebM project. It is released under the same license as the WebM project.
See http://www.webmproject.org/license/software/ or the See http://www.webmproject.org/license/software/ or the
"COPYING" file for details. An additional intellectual file "COPYING" file for details. An additional intellectual
property rights grant can be found in the file PATENTS. property rights grant can be found in the file PATENTS.
Building: Building:
@ -54,12 +53,6 @@ Please refer to makefile.unix for additional details and customizations.
Using autoconf tools: Using autoconf tools:
--------------------- ---------------------
Prerequisites:
A compiler (e.g., gcc), make, autoconf, automake, libtool.
On a Debian-like system the following should install everything you need for a
minimal build:
$ sudo apt-get install gcc make autoconf automake libtool
When building from git sources, you will need to run autogen.sh to generate the When building from git sources, you will need to run autogen.sh to generate the
configure script. configure script.
@ -84,86 +77,10 @@ be installed independently using a minor modification in the corresponding
Makefile.am configure files (see comments there). See './configure --help' for Makefile.am configure files (see comments there). See './configure --help' for
more options. more options.
Building for MIPS Linux:
------------------------
MIPS Linux toolchain stable available releases can be found at:
https://community.imgtec.com/developers/mips/tools/codescape-mips-sdk/available-releases/
# Add toolchain to PATH
export PATH=$PATH:/path/to/toolchain/bin
# 32-bit build for mips32r5 (p5600)
HOST=mips-mti-linux-gnu
MIPS_CFLAGS="-O3 -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64 \
-msched-weight -mload-store-pairs -fPIE"
MIPS_LDFLAGS="-mips32r5 -mabi=32 -mmsa -mfp64 -pie"
# 64-bit build for mips64r6 (i6400)
HOST=mips-img-linux-gnu
MIPS_CFLAGS="-O3 -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64 \
-msched-weight -mload-store-pairs -fPIE"
MIPS_LDFLAGS="-mips64r6 -mabi=64 -mmsa -mfp64 -pie"
./configure --host=${HOST} --build=`config.guess` \
CC="${HOST}-gcc -EL" \
CFLAGS="$MIPS_CFLAGS" \
LDFLAGS="$MIPS_LDFLAGS"
make
make install
CMake:
------
With CMake, you can compile libwebp, cwebp, dwebp, gif2web, img2webp, webpinfo
and the JS bindings.
Prerequisites:
A compiler (e.g., gcc with autotools) and CMake.
On a Debian-like system the following should install everything you need for a
minimal build:
$ sudo apt-get install build-essential cmake
When building from git sources, you will need to run cmake to generate the
makefiles.
mkdir build && cd build && cmake ../
make
make install
If you also want any of the executables, you will need to enable them through
CMake, e.g.:
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
or through your favorite interface (like ccmake or cmake-qt-gui).
Use option -DWEBP_UNICODE=ON for Unicode support on Windows (with chcp 65001).
Finally, once installed, you can also use WebP in your CMake project by doing:
find_package(WebP)
which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
Gradle:
-------
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
dwebp and webpmux_example.
Prerequisites:
A compiler (e.g., gcc with autotools) and gradle.
On a Debian-like system the following should install everything you need for a
minimal build:
$ sudo apt-get install build-essential gradle
When building from git sources, you will need to run the Gradle wrapper with the
appropriate target, e.g. :
./gradlew buildAllExecutables
SWIG bindings: SWIG bindings:
-------------- --------------
To generate language bindings from swig/libwebp.swig at least swig-1.3 To generate language bindings from swig/libwebp.i at least swig-1.3
(http://www.swig.org) is required. (http://www.swig.org) is required.
Currently the following functions are mapped: Currently the following functions are mapped:
@ -198,7 +115,7 @@ DLL that can be loaded via System.loadLibrary("webp_jni").
Python bindings: Python bindings:
To build the swig-generated Python extension code at least Python 2.6 is To build the swig-generated Python extension code at least Python 2.6 is
required. Python < 2.6 may build with some minor changes to libwebp.swig or the required. Python < 2.6 may build with some minor changes to libwebp.i or the
generated code, but is untested. generated code, but is untested.
Encoding tool: Encoding tool:
@ -223,34 +140,28 @@ A longer list of options is available using the -longhelp command line flag:
Usage: Usage:
cwebp [-preset <...>] [options] in_file [-o out_file] cwebp [-preset <...>] [options] in_file [-o out_file]
If input size (-s) for an image is not specified, it is If input size (-s) for an image is not specified, it is assumed to be a PNG,
assumed to be a PNG, JPEG, TIFF or WebP file. JPEG or TIFF file.
options:
Options: -h / -help ............ short help
-h / -help ............. short help -H / -longhelp ........ long help
-H / -longhelp ......... long help -q <float> ............. quality factor (0:small..100:big)
-q <float> ............. quality factor (0:small..100:big), default=75 -alpha_q <int> ......... Transparency-compression quality (0..100).
-alpha_q <int> ......... transparency-compression quality (0..100), -preset <string> ....... Preset setting, one of:
default=100
-preset <string> ....... preset setting, one of:
default, photo, picture, default, photo, picture,
drawing, icon, text drawing, icon, text
-preset must come first, as it overwrites other parameters -preset must come first, as it overwrites other parameters.
-z <int> ............... activates lossless preset with given -m <int> ............... compression method (0=fast, 6=slowest)
level in [0:fast, ..., 9:slowest] -segments <int> ........ number of segments to use (1..4)
-size <int> ............ Target size (in bytes)
-psnr <float> .......... Target PSNR (in dB. typically: 42)
-m <int> ............... compression method (0=fast, 6=slowest), default=4 -s <int> <int> ......... Input size (width x height) for YUV
-segments <int> ........ number of segments to use (1..4), default=4 -sns <int> ............. Spatial Noise Shaping (0:off, 100:max)
-size <int> ............ target size (in bytes) -f <int> ............... filter strength (0=off..100)
-psnr <float> .......... target PSNR (in dB. typically: 42) -sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
-strong ................ use strong filter instead of simple (default).
-s <int> <int> ......... input size (width x height) for YUV -nostrong .............. use simple filter instead of strong.
-sns <int> ............. spatial noise shaping (0:off, 100:max), default=50
-f <int> ............... filter strength (0=off..100), default=60
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp), default=0
-strong ................ use strong filter instead of simple (default)
-nostrong .............. use simple filter instead of strong
-sharp_yuv ............. use sharper (and slower) RGB->YUV conversion
-partition_limit <int> . limit quality to fit the 512k limit on -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)
@ -258,42 +169,37 @@ Options:
-resize <w> <h> ........ resize picture (after any cropping) -resize <w> <h> ........ resize picture (after any cropping)
-mt .................... use multi-threading if available -mt .................... use multi-threading if available
-low_memory ............ reduce memory usage (slower encoding) -low_memory ............ reduce memory usage (slower encoding)
-map <int> ............. print map of extra info -map <int> ............. print map of extra info.
-print_psnr ............ prints averaged PSNR distortion -print_psnr ............ prints averaged PSNR distortion.
-print_ssim ............ prints averaged SSIM distortion -print_ssim ............ prints averaged SSIM distortion.
-print_lsim ............ prints local-similarity distortion -print_lsim ............ prints local-similarity distortion.
-d <file.pgm> .......... dump the compressed output (PGM file) -d <file.pgm> .......... dump the compressed output (PGM file).
-alpha_method <int> .... transparency-compression method (0..1), default=1 -alpha_method <int> .... Transparency-compression method (0..1)
-alpha_filter <string> . predictive filtering for alpha plane, -alpha_filter <string> . predictive filtering for alpha plane.
one of: none, fast (default) or best One of: none, fast (default) or best.
-exact ................. preserve RGB values in transparent area, default=off -alpha_cleanup ......... Clean RGB values in transparent area.
-blend_alpha <hex> ..... blend colors against background color -noalpha ............... discard any transparency information.
expressed as RGB values written in -lossless .............. Encode image losslessly.
hexadecimal, e.g. 0xc0e0d0 for red=0xc0 -hint <string> ......... Specify image characteristics hint.
green=0xe0 and blue=0xd0 One of: photo, picture or graph
-noalpha ............... discard any transparency information
-lossless .............. encode image losslessly, default=off
-near_lossless <int> ... use near-lossless image
preprocessing (0..100=off), default=100
-hint <string> ......... specify image characteristics hint,
one of: photo, picture or graph
-metadata <string> ..... comma separated list of metadata to -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 (default), exif, icc, xmp Valid values: all, none (default), exif, icc, xmp
-short ................. condense printed message -short ................. condense printed message
-quiet ................. don't print anything -quiet ................. don't print anything.
-version ............... print version number and exit -version ............... print version number and exit.
-noasm ................. disable all assembly optimizations -noasm ................. disable all assembly optimizations.
-v ..................... verbose, e.g. print encoding/decoding times -v ..................... verbose, e.g. print encoding/decoding times
-progress .............. report encoding progress -progress .............. report encoding progress
Experimental Options: Experimental Options:
-jpeg_like ............. roughly match expected JPEG size -jpeg_like ............. Roughly match expected JPEG size.
-af .................... auto-adjust filter strength -af .................... auto-adjust filter strength.
-pre <int> ............. pre-processing filter -pre <int> ............. pre-processing filter
The main options you might want to try in order to further tune the The main options you might want to try in order to further tune the
visual quality are: visual quality are:
-preset -preset
@ -345,46 +251,21 @@ Decodes the WebP image file to PNG format [Default]
Use following options to convert into alternate image formats: Use following options to convert into alternate image formats:
-pam ......... save the raw RGBA samples as a color PAM -pam ......... save the raw RGBA samples as a color PAM
-ppm ......... save the raw RGB samples as a color PPM -ppm ......... save the raw RGB samples as a color PPM
-bmp ......... save as uncompressed BMP format
-tiff ........ save as uncompressed TIFF format
-pgm ......... save the raw YUV samples as a grayscale PGM -pgm ......... save the raw YUV samples as a grayscale PGM
file with IMC4 layout file with IMC4 layout.
-yuv ......... save the raw YUV samples in flat layout -yuv ......... save the raw YUV samples in flat layout.
Other options are: Other options are:
-version ..... print version number and exit -version .... print version number and exit.
-nofancy ..... don't use the fancy YUV420 upscaler -nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering -nofilter .... disable in-loop filtering.
-nodither .... disable dithering
-dither <d> .. dithering strength (in 0..100)
-alpha_dither use alpha-plane dithering if needed
-mt .......... use multi-threading -mt .......... use multi-threading
-crop <x> <y> <w> <h> ... crop output with the given rectangle -crop <x> <y> <w> <h> ... crop output with the given rectangle
-resize <w> <h> ......... scale the output (*after* any cropping) -scale <w> <h> .......... scale the output (*after* any cropping)
-flip ........ flip the output vertically -alpha ....... only save the alpha plane.
-alpha ....... only save the alpha plane -h ....... this help message.
-incremental . use incremental decoding (useful for tests) -v ....... verbose (e.g. print encoding/decoding times)
-h ........... this help message -noasm ....... disable all assembly optimizations.
-v ........... verbose (e.g. print encoding/decoding times)
-quiet ....... quiet mode, don't print anything
-noasm ....... disable all assembly optimizations
WebP file analysis tool:
========================
'webpinfo' can be used to print out the chunk level structure and bitstream
header information of WebP files. It can also check if the files are of valid
WebP format.
Usage: webpinfo [options] in_files
Note: there could be multiple input files;
options must come before input files.
Options:
-version ........... Print version number and exit.
-quiet ............. Do not show chunk parsing information.
-diag .............. Show parsing error diagnosis.
-summary ........... Show chunk stats summary.
-bitstream_info .... Parse bitstream header.
Visualization tool: Visualization tool:
=================== ===================
@ -398,23 +279,18 @@ Usage: vwebp in_file [options]
Decodes the WebP image file and visualize it using OpenGL Decodes the WebP image file and visualize it using OpenGL
Options are: Options are:
-version ..... print version number and exit -version .... print version number and exit.
-noicc ....... don't use the icc profile if present -noicc ....... don't use the icc profile if present.
-nofancy ..... don't use the fancy YUV420 upscaler -nofancy ..... don't use the fancy YUV420 upscaler.
-nofilter .... disable in-loop filtering -nofilter .... disable in-loop filtering.
-dither <int> dithering strength (0..100), default=50 -mt .......... use multi-threading.
-noalphadither disable alpha plane dithering -info ........ print info.
-usebgcolor .. display background color -h ....... this help message.
-mt .......... use multi-threading
-info ........ print info
-h ........... this help message
Keyboard shortcuts: Keyboard shortcuts:
'c' ................ toggle use of color profile 'c' ................ toggle use of color profile.
'b' ................ toggle background color display 'i' ................ overlay file information.
'i' ................ overlay file information 'q' / 'Q' / ESC .... quit.
'd' ................ disable blending & disposal (debug)
'q' / 'Q' / ESC .... quit
Building: Building:
--------- ---------
@ -442,112 +318,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
Note: if a single file name is passed as the argument, the arguments will be
tokenized from this file. The file name must not start with the character '-'.
Animated GIF conversion:
========================
Animated GIF files can be converted to WebP files with animation using the
gif2webp utility available under examples/. The files can then be viewed using
vwebp.
Usage:
gif2webp [options] gif_file -o webp_file
Options:
-h / -help ............. this help
-lossy ................. encode image using lossy compression
-mixed ................. for each frame in the image, pick lossy
or lossless compression heuristically
-q <float> ............. quality factor (0:small..100:big)
-m <int> ............... compression method (0=fast, 6=slowest)
-min_size .............. minimize output size (default:off)
lossless compression by default; can be
combined with -q, -m, -lossy or -mixed
options
-kmin <int> ............ min distance between key frames
-kmax <int> ............ max distance between key frames
-f <int> ............... filter strength (0=off..100)
-metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present
Valid values: all, none, icc, xmp (default)
-loop_compatibility .... use compatibility mode for Chrome
version prior to M62 (inclusive)
-mt .................... use multi-threading if available
-version ............... print version number and exit
-v ..................... verbose
-quiet ................. don't print anything
Building:
---------
With the libgif development files installed, gif2webp can be built using
makefile.unix:
$ make -f makefile.unix examples/gif2webp
or using autoconf:
$ ./configure --enable-everything
$ make
Comparison of animated images:
==============================
Test utility anim_diff under examples/ can be used to compare two animated
images (each can be GIF or WebP).
Usage: anim_diff <image1> <image2> [options]
Options:
-dump_frames <folder> dump decoded frames in PAM format
-min_psnr <float> ... minimum per-frame PSNR
-raw_comparison ..... if this flag is not used, RGB is
premultiplied before comparison
-max_diff <int> ..... maximum allowed difference per channel
between corresponding pixels in subsequent
frames
-h .................. this help
-version ............ print version number and exit
Building:
---------
With the libgif development files and a C++ compiler installed, anim_diff can
be built using makefile.unix:
$ make -f makefile.unix examples/anim_diff
or using autoconf:
$ ./configure --enable-everything
$ make
Encoding API: Encoding API:
============= =============
@ -597,7 +367,7 @@ The encoding flow looks like:
// Setup a config, starting form a preset and tuning some additional // Setup a config, starting form a preset and tuning some additional
// parameters // parameters
WebPConfig config; WebPConfig config;
if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) { if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor))
return 0; // version error return 0; // version error
} }
// ... additional tuning // ... additional tuning
@ -625,20 +395,15 @@ The encoding flow looks like:
// Set up a byte-output write method. WebPMemoryWriter, for instance. // Set up a byte-output write method. WebPMemoryWriter, for instance.
WebPMemoryWriter wrt; WebPMemoryWriter wrt;
WebPMemoryWriterInit(&wrt); // initialize 'wrt'
pic.writer = MyFileWriter; pic.writer = MyFileWriter;
pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work; pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work;
// initialize 'wrt' here...
// Compress! // Compress!
int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred! int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred!
WebPPictureFree(&pic); // must be called independently of the 'ok' result. WebPPictureFree(&pic); // must be called independently of the 'ok' result.
// output data should have been handled by the writer at that point. // output data should have been handled by the writer at that point.
// -> compressed data is the memory buffer described by wrt.mem / wrt.size
// deallocate the memory used by compressed data
WebPMemoryWriterClear(&wrt);
-------------------------------------- END PSEUDO EXAMPLE -------------------------------------- END PSEUDO EXAMPLE
@ -777,8 +542,8 @@ an otherwise too-large picture. Some CPU can be saved too, incidentally.
Bugs: Bugs:
===== =====
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/ http://www.webmproject.org/code/contribute/submitting-patches/

View File

@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __  __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\ / \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__ \ / __/ _ \ __/ / / (_/ /__
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.3 \__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.1.1
Description: Description:
@ -25,57 +25,42 @@ 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.
icc get ICC profile icc Get ICC profile.
exif get EXIF metadata exif Get EXIF metadata.
xmp get XMP metadata xmp Get XMP metadata.
frame n get nth frame frame n Get nth frame.
SET_OPTIONS: SET_OPTIONS:
Set color profile/metadata: Set color profile/metadata.
icc file.icc set ICC profile icc file.icc Set ICC profile.
exif file.exif set EXIF metadata exif file.exif Set EXIF metadata.
xmp file.xmp set XMP metadata xmp file.xmp Set XMP metadata.
where: 'file.icc' contains the ICC profile to be set, where: 'file.icc' contains the ICC profile to be set,
'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.
exif strip EXIF metadata exif Strip EXIF metadata.
xmp strip XMP metadata xmp Strip XMP metadata.
FRAME_OPTIONS(i): FRAME_OPTIONS(i):
Create animation: Create animation.
file_i +di+[xi+yi[+mi[bi]]] file_i +di+xi+yi+mi
where: 'file_i' is the i'th animation frame (WebP format), where: 'file_i' is the i'th animation frame (WebP format),
'di' is the pause duration before next frame, 'di' is the pause duration before next frame.
'xi','yi' specify the image offset for this frame, 'xi','yi' specify the image offset for this frame.
'mi' is the dispose method for this frame (0 or 1), 'mi' is the dispose method for this frame (0 or 1).
'bi' is the blending method for this frame (+b or -b)
LOOP_COUNT: LOOP_COUNT:
Number of times to repeat the animation. Number of times to repeat the animation.
@ -86,16 +71,13 @@ BACKGROUND_COLOR:
A,R,G,B A,R,G,B
where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying
the Alpha, Red, Green and Blue component values respectively the Alpha, Red, Green and Blue component values respectively
[Default: 255,255,255,255] [Default: 255,255,255,255].
INPUT & OUTPUT are in WebP format. 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:
=================== ===================
@ -150,7 +132,7 @@ WebP files. This API currently supports reading of XMP/EXIF metadata, ICC
profile and animated images. Other features may be added in subsequent profile and animated images. Other features may be added in subsequent
releases. releases.
Code example: Demuxing WebP data to extract all the frames, ICC profile Code Example: Demuxing WebP data to extract all the frames, ICC profile
and EXIF/XMP metadata. and EXIF/XMP metadata.
WebPDemuxer* demux = WebPDemux(&webp_data); WebPDemuxer* demux = WebPDemux(&webp_data);
@ -187,65 +169,12 @@ and EXIF/XMP metadata.
For a detailed Demux API reference, please refer to the header file For a detailed Demux API reference, please refer to the header file
(src/webp/demux.h). (src/webp/demux.h).
AnimEncoder API:
================
The AnimEncoder API can be used to create animated WebP images.
Code example:
WebPAnimEncoderOptions enc_options;
WebPAnimEncoderOptionsInit(&enc_options);
// ... (Tune 'enc_options' as needed).
WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
while(<there are more frames>) {
WebPConfig config;
WebPConfigInit(&config);
// ... (Tune 'config' as needed).
WebPAnimEncoderAdd(enc, frame, duration, &config);
}
WebPAnimEncoderAssemble(enc, webp_data);
WebPAnimEncoderDelete(enc);
// ... (Write the 'webp_data' to a file, or re-mux it further).
For a detailed AnimEncoder API reference, please refer to the header file
(src/webp/mux.h).
AnimDecoder API:
================
This AnimDecoder API allows decoding (possibly) animated WebP images.
Code Example:
WebPAnimDecoderOptions dec_options;
WebPAnimDecoderOptionsInit(&dec_options);
// Tune 'dec_options' as needed.
WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
WebPAnimInfo anim_info;
WebPAnimDecoderGetInfo(dec, &anim_info);
for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
while (WebPAnimDecoderHasMoreFrames(dec)) {
uint8_t* buf;
int timestamp;
WebPAnimDecoderGetNext(dec, &buf, &timestamp);
// ... (Render 'buf' based on 'timestamp').
// ... (Do NOT free 'buf', as it is owned by 'dec').
}
WebPAnimDecoderReset(dec);
}
const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
// ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
WebPAnimDecoderDelete(dec);
For a detailed AnimDecoder API reference, please refer to the header file
(src/webp/demux.h).
Bugs: Bugs:
===== =====
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/ http://www.webmproject.org/code/contribute/submitting-patches/

View File

@ -1,80 +0,0 @@
__ __ ____ ____ ____ __ ____
/ \\/ \ _ \ _ \ _ \ (__)/ __\
\ / __/ _ \ __/ _) \_ \
\__\__/_____/____/_/ /____/____/
Description:
============
This file describes the compilation of libwebp into a JavaScript decoder
using Emscripten and CMake.
- install the Emscripten SDK following the procedure described at:
https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
After installation, you should have some global variable positioned to the
location of the SDK. In particular, $EMSCRIPTEN should point to the
top-level directory containing Emscripten tools.
- make sure the file $EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake is
accessible. This is the toolchain file used by CMake to invoke Emscripten.
If $EMSCRIPTEN is unset search for Emscripten.cmake under $EMSDK and set
$EMSCRIPTEN accordingly, for example:
unix-like environments: export EMSCRIPTEN=$EMSDK/fastcomp/emscripten
windows: set EMSCRIPTEN=%EMSDK%\fastcomp\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

@ -1,439 +0,0 @@
// Define dependencies.
buildscript {
repositories {
maven {
url "https://jcenter.bintray.com"
}
}
dependencies {
classpath "com.android.tools.build:gradle:${ANDROID_GRADLE_PLUGIN_VERSION}"
}
}
// Define versions in the project.
project.ext {
buildToolsVersion = "${BUILD_TOOLS_VERSION}"
compileSdkVersion = COMPILE_SDK_VERSION.toInteger()
}
// Core libraries and executables.
apply plugin: "c"
def NEON
model {
buildTypes {
debug
release
}
platforms {
arm {
architecture "arm"
}
arm64 {
architecture "arm64"
}
x86 {
architecture "x86"
}
x64 {
architecture "x86_64"
}
mips32r2
mips32r5
mips64r6
}
toolChains {
gcc(Gcc) {
target("mips32r2") {
cCompiler.args "-mips32r2"
}
target("mips32r5") {
cCompiler.args "-mips32r5"
}
target("mips64r6") {
cCompiler.args "-mips64r6"
}
}
}
binaries {
all {
if (toolChain in Gcc) {
cCompiler.args "-fPIC"
cCompiler.args "-Wall"
cCompiler.define "ANDROID"
cCompiler.define "HAVE_MALLOC_H"
}
// Optimizations.
if (buildType == buildTypes.release) {
if (toolChain in Gcc) {
cCompiler.args "-finline-functions"
cCompiler.args "-ffast-math"
cCompiler.args "-ffunction-sections"
cCompiler.args "-fdata-sections"
}
if (toolChain in Clang) {
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.
if (getTargetPlatform() == "arm") {
NEON = "c.neon"
cCompiler.define "HAVE_CPU_FEATURES_H"
} else {
NEON = "c"
}
cCompiler.args "-I" + file(".").absolutePath
}
// Link to pthread for shared libraries.
withType(SharedLibraryBinarySpec) {
if (toolChain in Gcc) {
cCompiler.define "HAVE_PTHREAD"
cCompiler.define "WEBP_USE_THREAD"
linker.args "-pthread"
}
}
}
components {
webp(NativeLibrarySpec) {
sources {
c {
source {
srcDir "src/dec"
include "alpha_dec.c"
include "buffer_dec.c"
include "frame_dec.c"
include "idec_dec.c"
include "io_dec.c"
include "quant_dec.c"
include "tree_dec.c"
include "vp8_dec.c"
include "vp8l_dec.c"
include "webp_dec.c"
srcDir "src/dsp"
include "alpha_processing.c"
include "alpha_processing_mips_dsp_r2.c"
include "alpha_processing_neon.$NEON"
include "alpha_processing_sse2.c"
include "alpha_processing_sse41.c"
include "cpu.c"
include "dec.c"
include "dec_clip_tables.c"
include "dec_mips32.c"
include "dec_mips_dsp_r2.c"
include "dec_msa.c"
include "dec_neon.$NEON"
include "dec_sse2.c"
include "dec_sse41.c"
include "filters.c"
include "filters_mips_dsp_r2.c"
include "filters_msa.c"
include "filters_neon.$NEON"
include "filters_sse2.c"
include "lossless.c"
include "lossless_mips_dsp_r2.c"
include "lossless_msa.c"
include "lossless_neon.$NEON"
include "lossless_sse2.c"
include "rescaler.c"
include "rescaler_mips32.c"
include "rescaler_mips_dsp_r2.c"
include "rescaler_msa.c"
include "rescaler_neon.$NEON"
include "rescaler_sse2.c"
include "upsampling.c"
include "upsampling_mips_dsp_r2.c"
include "upsampling_msa.c"
include "upsampling_neon.$NEON"
include "upsampling_sse2.c"
include "upsampling_sse41.c"
include "yuv.c"
include "yuv_mips32.c"
include "yuv_mips_dsp_r2.c"
include "yuv_neon.$NEON"
include "yuv_sse2.c"
include "yuv_sse41.c"
srcDir "src/utils"
include "bit_reader_utils.c"
include "color_cache_utils.c"
include "filters_utils.c"
include "huffman_utils.c"
include "quant_levels_dec_utils.c"
include "random_utils.c"
include "rescaler_utils.c"
include "thread_utils.c"
include "utils.c"
srcDir "src/dsp"
include "cost.c"
include "cost_mips32.c"
include "cost_mips_dsp_r2.c"
include "cost_neon.$NEON"
include "cost_sse2.c"
include "enc.c"
include "enc_mips32.c"
include "enc_mips_dsp_r2.c"
include "enc_msa.c"
include "enc_neon.$NEON"
include "enc_sse2.c"
include "enc_sse41.c"
include "lossless_enc.c"
include "lossless_enc_mips32.c"
include "lossless_enc_mips_dsp_r2.c"
include "lossless_enc_msa.c"
include "lossless_enc_neon.$NEON"
include "lossless_enc_sse2.c"
include "lossless_enc_sse41.c"
include "ssim.c"
include "ssim_sse2.c"
srcDir "src/enc"
include "alpha_enc.c"
include "analysis_enc.c"
include "backward_references_cost_enc.c"
include "backward_references_enc.c"
include "config_enc.c"
include "cost_enc.c"
include "filter_enc.c"
include "frame_enc.c"
include "histogram_enc.c"
include "iterator_enc.c"
include "near_lossless_enc.c"
include "picture_enc.c"
include "picture_csp_enc.c"
include "picture_psnr_enc.c"
include "picture_rescale_enc.c"
include "picture_tools_enc.c"
include "predictor_enc.c"
include "quant_enc.c"
include "syntax_enc.c"
include "token_enc.c"
include "tree_enc.c"
include "vp8l_enc.c"
include "webp_enc.c"
srcDir "src/utils"
include "bit_writer_utils.c"
include "huffman_encode_utils.c"
include "quant_levels_utils.c"
}
exportedHeaders {
srcDir "src"
}
}
}
}
webpdemux(NativeLibrarySpec) {
sources {
c {
source {
srcDir "src/demux"
include "anim_decode.c"
include "demux.c"
}
}
}
}
webpmux(NativeLibrarySpec) {
sources {
c {
source {
srcDir "src/mux/"
include "anim_encode.c"
include "muxedit.c"
include "muxinternal.c"
include "muxread.c"
}
}
}
}
// Executables from examples.
example_util(NativeLibrarySpec) {
binaries {
all {
lib library: "webp", linkage: "static"
}
}
sources {
c {
source {
srcDir "./examples"
include "example_util.c"
}
}
}
}
imageio_util(NativeLibrarySpec) {
binaries {
all {
lib library: "webp", linkage: "static"
}
}
sources {
c {
source {
srcDir "./imageio"
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 "jpegdec.c"
include "metadata.c"
include "pngdec.c"
include "pnmdec.c"
include "tiffdec.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) {
binaries {
all {
lib library: "example_util", linkage: "static"
lib library: "imagedec", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpdemux", linkage: "static"
lib library: "webp", linkage: "static"
}
}
sources {
c {
source {
srcDir "./examples"
include "cwebp.c"
}
}
}
}
dwebp(NativeExecutableSpec) {
binaries {
all {
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"
}
}
sources {
c {
source {
srcDir "./examples"
include "dwebp.c"
}
}
}
}
webpmux_example(NativeExecutableSpec) {
binaries {
all {
lib library: "example_util", linkage: "static"
lib library: "imageio_util", linkage: "static"
lib library: "webpmux", linkage: "static"
lib library: "webp"
}
}
sources {
c {
source {
srcDir "./examples"
include "webpmux.c"
}
}
}
}
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 {
// Task to test all possible configurations.
buildAllExecutables(Task) {
dependsOn $.binaries.findAll { it.buildable }
}
}
}
// Task to generate the wrapper.
task wrapper(type: Wrapper) {
gradleVersion = '2.13'
}

View File

@ -1,11 +0,0 @@
set(WebP_VERSION @PROJECT_VERSION@)
set(WEBP_VERSION ${WebP_VERSION})
@PACKAGE_INIT@
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
set(WebP_INCLUDE_DIRS "webp")
set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")

View File

@ -1,153 +0,0 @@
/* Adapted from the autotools src/webp/config.h.in. */
/* Define if building universal (internal helper macro) */
/* TODO: handle properly in CMake */
#cmakedefine AC_APPLE_UNIVERSAL_BUILD 1
/* Set to 1 if __builtin_bswap16 is available */
#cmakedefine HAVE_BUILTIN_BSWAP16 1
/* Set to 1 if __builtin_bswap32 is available */
#cmakedefine HAVE_BUILTIN_BSWAP32 1
/* Set to 1 if __builtin_bswap64 is available */
#cmakedefine HAVE_BUILTIN_BSWAP64 1
/* Define to 1 if you have the <cpu-features.h> header file. */
#cmakedefine HAVE_CPU_FEATURES_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <GLUT/glut.h> header file. */
#cmakedefine HAVE_GLUT_GLUT_H 1
/* Define to 1 if you have the <GL/glut.h> header file. */
#cmakedefine HAVE_GL_GLUT_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H 1
/* Define to 1 if you have the <OpenGL/glut.h> header file. */
#cmakedefine HAVE_OPENGL_GLUT_H 1
/* Have PTHREAD_PRIO_INHERIT. */
#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
/* Define to 1 if you have the <shlwapi.h> header file. */
#cmakedefine HAVE_SHLWAPI_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
/* Define to 1 if you have the <wincodec.h> header file. */
#cmakedefine HAVE_WINCODEC_H 1
/* Define to 1 if you have the <windows.h> header file. */
#cmakedefine HAVE_WINDOWS_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
/* TODO: handle properly in CMake */
#cmakedefine LT_OBJDIR "@LT_OBJDIR@"
/* Name of package */
#cmakedefine PACKAGE "@PROJECT_NAME@"
/* Define to the address where bug reports for this package should be sent. */
#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
/* Define to the full name of this package. */
#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@"
/* Define to the full name and version of this package. */
#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@"
/* Define to the one symbol short name of this package. */
#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@"
/* Define to the home page for this package. */
#cmakedefine PACKAGE_URL "@PACKAGE_URL@"
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine PTHREAD_CREATE_JOINABLE 1
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
/* Version number of package */
#cmakedefine VERSION "@VERSION@"
/* Set to 1 if GIF library is installed */
#cmakedefine WEBP_HAVE_GIF 1
/* Set to 1 if OpenGL is supported */
#cmakedefine WEBP_HAVE_GL 1
/* Set to 1 if JPEG library is installed */
#cmakedefine WEBP_HAVE_JPEG 1
/* Set to 1 if NEON is supported */
#cmakedefine WEBP_HAVE_NEON
/* Set to 1 if runtime detection of NEON is enabled */
/* TODO: handle properly in CMake */
#cmakedefine WEBP_HAVE_NEON_RTCD
/* Set to 1 if PNG library is installed */
#cmakedefine WEBP_HAVE_PNG 1
/* Set to 1 if SDL library is installed */
#cmakedefine WEBP_HAVE_SDL 1
/* Set to 1 if SSE2 is supported */
#cmakedefine WEBP_HAVE_SSE2 1
/* Set to 1 if SSE4.1 is supported */
#cmakedefine WEBP_HAVE_SSE41 1
/* Set to 1 if TIFF library is installed */
#cmakedefine WEBP_HAVE_TIFF 1
/* Enable near lossless encoding */
#cmakedefine WEBP_NEAR_LOSSLESS 1
/* Undefine this to disable thread support. */
#cmakedefine WEBP_USE_THREAD 1
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif

View File

@ -1,136 +0,0 @@
# Check for SIMD extensions.
include(CMakePushCheckState)
function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
if(NOT ENABLE_SIMD)
message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.")
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
return()
endif()
unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
check_c_source_compiles("
#include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\"
int main(void) {
#if !defined(WEBP_USE_${WEBP_SIMD_FLAG})
this is not valid code
#endif
return 0;
}
" WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
cmake_pop_check_state()
if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG})
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE)
else()
set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE)
endif()
endfunction()
# those are included in the names of WEBP_USE_* in c++ code.
set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FILE_EXTENSIONS
"_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
if(MSVC)
# MSVC does not have a SSE4 flag but AVX support implies SSE4 support.
set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;")
set(SIMD_DISABLE_FLAGS)
else()
set(SIMD_ENABLE_FLAGS
"-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
set(SIMD_DISABLE_FLAGS
"-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
endif()
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
set(WEBP_SIMD_FILES_TO_INCLUDE)
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
if(${ANDROID})
if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
# This is because Android studio uses the configuration "-march=armv7-a
# -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
# optimizations but should (as this configuration does not exist anymore).
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ")
endif()
endif()
list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH)
math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
unset(HIGHEST_SSE_FLAG)
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG)
# First try with no extra flag added as the compiler might have default flags
# (especially on Android).
unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE)
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS)
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG})
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
else()
if(MSVC)
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
else()
set(SIMD_COMPILE_FLAG " ")
endif()
endif()
# Check which files we should include or not.
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
"src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
if(${I_SIMD} LESS 2 AND NOT HIGHEST_SSE_FLAG)
set(HIGHEST_SSE_FLAG ${SIMD_COMPILE_FLAG})
endif()
# Memorize the file and flags.
foreach(FILE ${SIMD_FILES})
list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE})
if(${I_SIMD} LESS 2)
list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${HIGHEST_SSE_FLAG})
else()
list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG})
endif()
endforeach()
else()
# Remove the file from the list.
foreach(FILE ${SIMD_FILES})
list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE})
endforeach()
# Explicitly disable SIMD.
if(SIMD_DISABLE_FLAGS)
list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
include(CheckCCompilerFlag)
if(SIMD_COMPILE_FLAG)
unset(HAS_COMPILE_FLAG CACHE)
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)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}")
endif()
endif()
endif()
endif()
cmake_pop_check_state()
endforeach()

View File

@ -1,170 +0,0 @@
# Generate the config.h to compile with specific intrinsics / libs.
# Check for compiler options.
include(CheckCSourceCompiles)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap16(0);
return 0;
}
" HAVE_BUILTIN_BSWAP16)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap32(0);
return 0;
}
" HAVE_BUILTIN_BSWAP32)
check_c_source_compiles("
int main(void) {
(void)__builtin_bswap64(0);
return 0;
}
" HAVE_BUILTIN_BSWAP64)
# Check for libraries.
find_package(Threads)
if(Threads_FOUND)
if(CMAKE_USE_PTHREADS_INIT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
endif()
foreach(PTHREAD_TEST HAVE_PTHREAD_PRIO_INHERIT PTHREAD_CREATE_UNDETACHED)
check_c_source_compiles("
#include <pthread.h>
int main (void) {
int attr = ${PTHREAD_TEST};
return attr;
}
" ${PTHREAD_TEST})
endforeach()
list(APPEND WEBP_DEP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
# TODO: this seems unused, check with autotools.
set(LT_OBJDIR ".libs/")
# Only useful for vwebp, so useless for now.
find_package(OpenGL)
set(WEBP_HAVE_GL ${OPENGL_FOUND})
# Check if we need to link to the C math library. We do not look for it as it is
# not found when cross-compiling, while it is here.
check_c_source_compiles("
#include <math.h>
int main(int argc, char** argv) {
return (int)pow(argc, 2.5);
}
" HAVE_MATH_LIBRARY)
if(NOT HAVE_MATH_LIBRARY)
message(STATUS "Adding -lm flag.")
list(APPEND WEBP_DEP_LIBRARIES m)
endif()
# Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS)
foreach(I_LIB PNG JPEG TIFF)
find_package(${I_LIB})
set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
if(${I_LIB}_FOUND)
list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
${${I_LIB}_INCLUDE_DIRS})
endif()
endforeach()
if(WEBP_DEP_IMG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
# GIF detection, gifdec isn't part of the imageio lib.
include(CMakePushCheckState)
set(WEBP_DEP_GIF_LIBRARIES)
set(WEBP_DEP_GIF_INCLUDE_DIRS)
find_package(GIF)
set(WEBP_HAVE_GIF ${GIF_FOUND})
if(GIF_FOUND)
# GIF find_package only locates the header and library, it doesn't fail
# compile tests when detecting the version, but falls back to 3 (as of at
# least cmake 3.7.2). Make sure the library links to avoid incorrect detection
# when cross compiling.
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
check_c_source_compiles("
#include <gif_lib.h>
int main(void) {
(void)DGifOpenFileHandle;
return 0;
}
" GIF_COMPILES)
cmake_pop_check_state()
if(GIF_COMPILES)
list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
else()
unset(GIF_FOUND)
endif()
endif()
# Check for specific headers.
include(CheckIncludeFiles)
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
check_include_files(dlfcn.h HAVE_DLFCN_H)
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(memory.h HAVE_MEMORY_H)
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(stdlib.h HAVE_STDLIB_H)
check_include_files(strings.h HAVE_STRINGS_H)
check_include_files(string.h HAVE_STRING_H)
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(wincodec.h HAVE_WINCODEC_H)
check_include_files(windows.h HAVE_WINDOWS_H)
# Windows specifics
if(HAVE_WINCODEC_H)
list(APPEND WEBP_DEP_LIBRARIES
shlwapi
ole32
windowscodecs)
endif()
# Check for SIMD extensions.
include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake)
# Define extra info.
set(PACKAGE ${PROJECT_NAME})
set(PACKAGE_NAME ${PROJECT_NAME})
# Read from configure.ac.
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC)
string(REGEX MATCHALL
"\\[([0-9a-z\\.:/]*)\\]"
CONFIGURE_AC_PACKAGE_INFO
${CONFIGURE_AC})
function(strip_bracket VAR)
string(LENGTH ${${VAR}} TMP_LEN)
math(EXPR TMP_LEN ${TMP_LEN}-2)
string(SUBSTRING ${${VAR}}
1
${TMP_LEN}
TMP_SUB)
set(${VAR} ${TMP_SUB} PARENT_SCOPE)
endfunction()
list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION)
strip_bracket(PACKAGE_VERSION)
list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT)
strip_bracket(PACKAGE_BUGREPORT)
list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL)
strip_bracket(PACKAGE_URL)
# Build more info.
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME ${PACKAGE_NAME})
set(VERSION ${PACKAGE_VERSION})

View File

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

View File

@ -1,8 +1,7 @@
AC_INIT([libwebp], [1.0.3], AC_INIT([libwebp], [0.3.1],
[https://bugs.chromium.org/p/webp],, [http://code.google.com/p/webp/issues],,
[http://developers.google.com/speed/webp]) [http://developers.google.com/speed/webp])
AC_CANONICAL_HOST AC_CANONICAL_TARGET
AC_PREREQ([2.60])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
dnl === automake >= 1.12 requires this for 'unusual archivers' support. dnl === automake >= 1.12 requires this for 'unusual archivers' support.
@ -10,15 +9,11 @@ dnl === it must occur before LT_INIT (AC_PROG_LIBTOOL).
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_PROG_LIBTOOL AC_PROG_LIBTOOL
AC_PROG_SED
AM_PROG_CC_C_O AM_PROG_CC_C_O
dnl === Enable less verbose output when building. dnl === Enable less verbose output when building.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl == test endianness
AC_C_BIGENDIAN
dnl === SET_IF_UNSET(shell_var, value) dnl === SET_IF_UNSET(shell_var, value)
dnl === Set the shell variable 'shell_var' to 'value' if it is unset. dnl === Set the shell variable 'shell_var' to 'value' if it is unset.
AC_DEFUN([SET_IF_UNSET], [test "${$1+set}" = "set" || $1=$2]) AC_DEFUN([SET_IF_UNSET], [test "${$1+set}" = "set" || $1=$2])
@ -29,204 +24,40 @@ AC_ARG_ENABLE([everything],
disabled with --disable-target]), disabled with --disable-target]),
[SET_IF_UNSET([enable_libwebpdecoder], [$enableval]) [SET_IF_UNSET([enable_libwebpdecoder], [$enableval])
SET_IF_UNSET([enable_libwebpdemux], [$enableval]) SET_IF_UNSET([enable_libwebpdemux], [$enableval])
SET_IF_UNSET([enable_libwebpextras], [$enableval])
SET_IF_UNSET([enable_libwebpmux], [$enableval])]) SET_IF_UNSET([enable_libwebpmux], [$enableval])])
dnl === If --enable-asserts is not defined, define NDEBUG
AC_MSG_CHECKING(whether asserts are enabled)
AC_ARG_ENABLE([asserts],
AS_HELP_STRING([--enable-asserts],
[Enable assert checks]))
if test "x${enable_asserts-no}" = "xno"; then
AM_CPPFLAGS="${AM_CPPFLAGS} -DNDEBUG"
fi
AC_MSG_RESULT(${enable_asserts-no})
AC_SUBST([AM_CPPFLAGS])
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=DIR], AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=DIR],
[Path to the pkgconfig directory @<:@LIBDIR/pkgconfig@:>@]), [Path to the pkgconfig directory @<:@LIBDIR/pkgconfig@:>@]),
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig']) [pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
AC_SUBST([pkgconfigdir]) AC_SUBST([pkgconfigdir])
dnl === TEST_AND_ADD_CFLAGS(var, flag) dnl === TEST_AND_ADD_CFLAGS(flag)
dnl === Checks whether $CC supports 'flag' and adds it to 'var' dnl === Checks whether $CC supports 'flag' and adds it to AM_CFLAGS on success.
dnl === on success.
AC_DEFUN([TEST_AND_ADD_CFLAGS], AC_DEFUN([TEST_AND_ADD_CFLAGS],
[SAVED_CFLAGS="$CFLAGS" [SAVED_CFLAGS="$CFLAGS"
CFLAGS="-Werror $2" CFLAGS="-Werror $1"
AC_MSG_CHECKING([whether $CC supports $2]) AC_MSG_CHECKING([whether $CC supports $1])
dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition. dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])], AC_COMPILE_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])],
[AC_MSG_RESULT([yes])] [AC_MSG_RESULT([yes])]
dnl Simply append the variable avoiding a dnl Simply append the variable avoiding a
dnl compatibility ifdef for AS_VAR_APPEND as this dnl compatibility ifdef for AS_VAR_APPEND as this
dnl variable shouldn't grow all that large. dnl variable shouldn't grow all that large.
[$1="${$1} $2"], [AM_CFLAGS="$AM_CFLAGS $1"],
[AC_MSG_RESULT([no])]) [AC_MSG_RESULT([no])])
CFLAGS="$SAVED_CFLAGS"]) CFLAGS="$SAVED_CFLAGS"])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-fvisibility=hidden]) TEST_AND_ADD_CFLAGS([-Wall])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall]) TEST_AND_ADD_CFLAGS([-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion]) TEST_AND_ADD_CFLAGS([-Wextra])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement]) TEST_AND_ADD_CFLAGS([-Wmissing-declarations])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra]) TEST_AND_ADD_CFLAGS([-Wmissing-prototypes])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion]) TEST_AND_ADD_CFLAGS([-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-nonliteral]) TEST_AND_ADD_CFLAGS([-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security]) TEST_AND_ADD_CFLAGS([-Wunused-but-set-variable])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-declarations]) TEST_AND_ADD_CFLAGS([-Wunused])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wmissing-prototypes]) TEST_AND_ADD_CFLAGS([-Wvla])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
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])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wvla])
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62040
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61622
AS_IF([test "$GCC" = "yes" ], [
gcc_version=`$CC -dumpversion`
gcc_wht_bug=""
case "$host_cpu" in
aarch64|arm64)
case "$gcc_version" in
4.9|4.9.0|4.9.1) gcc_wht_bug=yes ;;
esac
esac
AS_IF([test "$gcc_wht_bug" = "yes"], [
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-frename-registers])])])
# Use -flax-vector-conversions, if available, when building intrinsics with
# older versions of gcc. The flag appeared in 4.3.x, but if backported, and
# -fno-lax-vector-conversions is set, errors may occur with the intrinsics
# files along with the older system includes, e.g., emmintrin.h.
# Originally observed with cc (GCC) 4.2.1 20070831 patched [FreeBSD] (9.3).
# https://bugs.chromium.org/p/webp/issues/detail?id=274
AS_IF([test "$GCC" = "yes" ], [
case "$host_cpu" in
amd64|i?86|x86_64)
AC_COMPILE_IFELSE(
dnl only check for -flax-vector-conversions with older gcc, skip
dnl clang as it reports itself as 4.2.1, but the flag isn't needed.
[AC_LANG_SOURCE([#if !defined(__clang__) && defined(__GNUC__) && \
((__GNUC__ << 8) | __GNUC_MINOR__) < 0x403
#error old gcc
#endif
int main(void) { return 0; }
])],,
[TEST_AND_ADD_CFLAGS([INTRINSICS_CFLAGS],
[-flax-vector-conversions])])
;;
esac])
AC_SUBST([AM_CFLAGS]) AC_SUBST([AM_CFLAGS])
dnl === Check for machine specific flags
AC_ARG_ENABLE([sse4.1],
AS_HELP_STRING([--disable-sse4.1],
[Disable detection of SSE4.1 support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sse4_1" != "xno" -a "x$enable_sse2" != "xno"], [
SSE41_FLAGS="$INTRINSICS_CFLAGS $SSE41_FLAGS"
TEST_AND_ADD_CFLAGS([SSE41_FLAGS], [-msse4.1])
AS_IF([test -n "$SSE41_FLAGS"], [
SAVED_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $SSE41_FLAGS"
AC_CHECK_HEADER([smmintrin.h],
[AC_DEFINE(WEBP_HAVE_SSE41, [1],
[Set to 1 if SSE4.1 is supported])],
[SSE41_FLAGS=""])
CFLAGS=$SAVED_CFLAGS])
AC_SUBST([SSE41_FLAGS])])
AC_ARG_ENABLE([sse2],
AS_HELP_STRING([--disable-sse2],
[Disable detection of SSE2 support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sse2" != "xno"], [
SSE2_FLAGS="$INTRINSICS_CFLAGS $SSE2_FLAGS"
TEST_AND_ADD_CFLAGS([SSE2_FLAGS], [-msse2])
AS_IF([test -n "$SSE2_FLAGS"], [
SAVED_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $SSE2_FLAGS"
AC_CHECK_HEADER([emmintrin.h],
[AC_DEFINE(WEBP_HAVE_SSE2, [1],
[Set to 1 if SSE2 is supported])],
[SSE2_FLAGS=""])
CFLAGS=$SAVED_CFLAGS])
AC_SUBST([SSE2_FLAGS])])
AC_ARG_ENABLE([neon],
AS_HELP_STRING([--disable-neon],
[Disable detection of NEON support
@<:@default=auto@:>@]))
AC_ARG_ENABLE([neon_rtcd],
AS_HELP_STRING([--disable-neon-rtcd],
[Disable runtime detection of NEON support via
/proc/cpuinfo on Linux hosts
@<:@default=auto@:>@]))
# For ARM(7) hosts:
# Both NEON flags unset and NEON support detected = build all modules with NEON
# NEON detected with the use of -mfpu=neon = build only NEON modules with NEON
AS_IF([test "x$enable_neon" != "xno"], [
case "$host_cpu" in
arm|armv7*)
# Test for NEON support without flags before falling back to -mfpu=neon
for flag in '' '-mfpu=neon'; do
LOCAL_NEON_FLAGS="$INTRINSICS_CFLAGS $NEON_FLAGS"
TEST_AND_ADD_CFLAGS([LOCAL_NEON_FLAGS], [$flag])
SAVED_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $LOCAL_NEON_FLAGS"
dnl Note AC_LANG_PROGRAM([]) uses an old-style main definition.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <arm_neon.h>
int main(void) {
int8x8_t v = vdup_n_s8(0);
(void)v;
return 0;
}])],
[NEON_FLAGS="$(echo $LOCAL_NEON_FLAGS | $SED 's/^ *//')"
AS_IF([test -n "$NEON_FLAGS"], [
AS_IF([test "${host_os%%-*}" = "linux" -o \
"x$enable_neon_rtcd" = "xno"], [
CFLAGS=$SAVED_CFLAGS
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
break
],[
AC_MSG_WARN(m4_normalize([NEON runtime cpu-detection is
unavailable for ${host_os%%-*}. Force
with CFLAGS=-mfpu=neon or
--disable-neon-rtcd.]))
enable_neon_rtcd=no
NEON_FLAGS=""
])
],[
CFLAGS=$SAVED_CFLAGS
AC_DEFINE(WEBP_HAVE_NEON, [1], [Set to 1 if NEON is supported])
break
])])
CFLAGS=$SAVED_CFLAGS
done
AS_IF([test -n "$NEON_FLAGS"], [
# If NEON is available and rtcd is disabled apply NEON_FLAGS globally.
AS_IF([test "x$enable_neon_rtcd" = "xno"], [
AM_CFLAGS="$AM_CFLAGS $NEON_FLAGS"
NEON_FLAGS=""],
[AC_DEFINE(WEBP_HAVE_NEON_RTCD, [1],
[Set to 1 if runtime detection of NEON is enabled])])])
case "$host_os" in
*android*) AC_CHECK_HEADERS([cpu-features.h]) ;;
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}.
AC_DEFUN([CLEAR_LIBVARS], [$1_INCLUDES=""; $1_LIBS=""]) AC_DEFUN([CLEAR_LIBVARS], [$1_INCLUDES=""; $1_LIBS=""])
@ -262,26 +93,6 @@ AC_DEFUN([LIBCHECK_EPILOGUE],
CPPFLAGS=$SAVED_CPPFLAGS CPPFLAGS=$SAVED_CPPFLAGS
LIBS=$SAVED_LIBS]) LIBS=$SAVED_LIBS])
dnl === Check for gcc builtins
dnl === CHECK_FOR_BUILTIN([builtin], [param], [define])
dnl === links a C AC_LANG_PROGRAM, with <builtin>(<param>)
dnl === AC_DEFINE'ing <define> if successful.
AC_DEFUN([CHECK_FOR_BUILTIN],
[AC_LANG_PUSH([C])
AC_MSG_CHECKING([for $1])
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [(void)$1($2)])],
[AC_MSG_RESULT([yes])
AC_DEFINE([$3], [1],
[Set to 1 if $1 is available])],
[AC_MSG_RESULT([no])]),
AC_LANG_POP])
dnl AC_CHECK_FUNC doesn't work with builtin's.
CHECK_FOR_BUILTIN([__builtin_bswap16], [1u << 15], [HAVE_BUILTIN_BSWAP16])
CHECK_FOR_BUILTIN([__builtin_bswap32], [1u << 31], [HAVE_BUILTIN_BSWAP32])
CHECK_FOR_BUILTIN([__builtin_bswap64], [1ull << 63], [HAVE_BUILTIN_BSWAP64])
dnl === Check for pthread support dnl === Check for pthread support
AC_ARG_ENABLE([threading], AC_ARG_ENABLE([threading],
AS_HELP_STRING([--disable-threading], AS_HELP_STRING([--disable-threading],
@ -295,20 +106,11 @@ if test "$enable_threading" = "yes"; then
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
CC="$PTHREAD_CC" CC="$PTHREAD_CC"
], ],
[AC_CHECK_FUNC([_beginthreadex], [enable_threading=no])
[AC_DEFINE([WEBP_USE_THREAD], [1],
[Undefine this to disable thread
support.])],
[enable_threading=no])])
fi fi
AC_MSG_NOTICE([checking if threading is enabled... ${enable_threading-no}]) AC_MSG_NOTICE([checking if threading is enabled... ${enable_threading-no}])
dnl === check for OpenGL/GLUT support === dnl === check for OpenGL/GLUT support ===
AC_ARG_ENABLE([gl], AS_HELP_STRING([--disable-gl],
[Disable detection of OpenGL support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_gl" != "xno"], [
CLEAR_LIBVARS([GL]) CLEAR_LIBVARS([GL])
WITHLIB_OPTION([gl], [GL]) WITHLIB_OPTION([gl], [GL])
@ -322,8 +124,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
@ -366,7 +166,7 @@ AS_IF([test "x$enable_gl" != "xno"], [
# find libGL # find libGL
GL_SAVED_LIBS="$LIBS" GL_SAVED_LIBS="$LIBS"
AC_SEARCH_LIBS([glBegin], [GL OpenGL opengl32]) AC_SEARCH_LIBS([glBegin], [GL OpenGL])
LIBS="$GL_SAVED_LIBS" LIBS="$GL_SAVED_LIBS"
# A direct link to libGL may not be necessary on e.g., linux. # A direct link to libGL may not be necessary on e.g., linux.
@ -387,8 +187,6 @@ AS_IF([test "x$enable_gl" != "xno"], [
glutMainLoop(); glutMainLoop();
]) ])
], ],
AC_DEFINE(WEBP_HAVE_GL, [1],
[Set to 1 if OpenGL is supported])
[glut_support=yes], [] [glut_support=yes], []
) )
if test "$glut_support" = "yes"; then if test "$glut_support" = "yes"; then
@ -409,83 +207,20 @@ AS_IF([test "x$enable_gl" != "xno"], [
if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then if test "$glut_support" = "yes" -a "$enable_libwebpdemux" = "yes"; then
build_vwebp=yes build_vwebp=yes
fi fi
])
AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"]) AM_CONDITIONAL([BUILD_VWEBP], [test "$build_vwebp" = "yes"])
dnl === check for SDL support ===
AC_ARG_ENABLE([sdl],
AS_HELP_STRING([--disable-sdl],
[Disable detection of SDL support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sdl" != "xno"], [
CLEAR_LIBVARS([SDL])
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
if test -n "$LIBSDL_CONFIG"; then
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
fi
WITHLIB_OPTION([sdl], [SDL])
sdl_header="no"
LIBCHECK_PROLOGUE([SDL])
AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
[AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
[AC_MSG_WARN(SDL library not available - no sdl.h)])])
if test x"$sdl_header" != "xno"; then
AC_LANG_PUSH(C)
SDL_SAVED_LIBS="$LIBS"
for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
LIBS="$SDL_SAVED_LIBS $lib"
# Perform a full link to ensure SDL_main is resolved if needed.
AC_LINK_IFELSE(
[AC_LANG_SOURCE([
#include <$sdl_header>
int main(int argc, char** argv) {
SDL_Init(0);
return 0;
}])],
[SDL_LIBS="$LDFLAGS $LIBS"
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_SDL"
AC_DEFINE(WEBP_HAVE_SDL, [1],
[Set to 1 if SDL library is installed])
sdl_support=yes]
)
if test x"$sdl_support" = "xyes"; then
break
fi
done
# LIBS is restored by LIBCHECK_EPILOGUE
AC_LANG_POP
if test x"$sdl_header" = "xSDL.h"; then
SDL_INCLUDES="$SDL_INCLUDES -DWEBP_HAVE_JUST_SDL_H"
fi
fi
LIBCHECK_EPILOGUE([SDL])
if test x"$sdl_support" = "xyes"; then
build_vwebp_sdl=yes
else
AC_MSG_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],
[Disable detection of PNG format support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_png" != "xno"], [
CLEAR_LIBVARS([PNG]) CLEAR_LIBVARS([PNG])
AC_PATH_PROGS([LIBPNG_CONFIG], AC_PATH_PROGS(LIBPNG_CONFIG,
[libpng-config libpng16-config libpng15-config libpng14-config \ [libpng-config libpng15-config libpng14-config libpng12-config])
libpng12-config])
if test -n "$LIBPNG_CONFIG"; then if test -n "$LIBPNG_CONFIG"; then
PNG_INCLUDES=`$LIBPNG_CONFIG --cflags` PNG_INCLUDES=`$LIBPNG_CONFIG --cflags`
PNG_LIBS="`$LIBPNG_CONFIG --ldflags`" PNG_PREFIX=`$LIBPNG_CONFIG --prefix`
if test "${PNG_PREFIX}/lib" != "/usr/lib" ; then
PNG_LIBS="-L${PNG_PREFIX}/lib"
fi
PNG_LIBS="$PNG_LIBS `$LIBPNG_CONFIG --libs`"
fi fi
WITHLIB_OPTION([png], [PNG]) WITHLIB_OPTION([png], [PNG])
@ -511,15 +246,9 @@ AS_IF([test "x$enable_png" != "xno"], [
], ],
) )
LIBCHECK_EPILOGUE([PNG]) LIBCHECK_EPILOGUE([PNG])
])
dnl === check for JPEG support === dnl === check for JPEG support ===
AC_ARG_ENABLE([jpeg],
AS_HELP_STRING([--disable-jpeg],
[Disable detection of JPEG format support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_jpeg" != "xno"], [
CLEAR_LIBVARS([JPEG]) CLEAR_LIBVARS([JPEG])
WITHLIB_OPTION([jpeg], [JPEG]) WITHLIB_OPTION([jpeg], [JPEG])
@ -537,15 +266,9 @@ AS_IF([test "x$enable_jpeg" != "xno"], [
AC_MSG_WARN(jpeg library not available - no jpeglib.h) AC_MSG_WARN(jpeg library not available - no jpeglib.h)
) )
LIBCHECK_EPILOGUE([JPEG]) LIBCHECK_EPILOGUE([JPEG])
])
dnl === check for TIFF support === dnl === check for TIFF support ===
AC_ARG_ENABLE([tiff],
AS_HELP_STRING([--disable-tiff],
[Disable detection of TIFF format support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_tiff" != "xno"], [
CLEAR_LIBVARS([TIFF]) CLEAR_LIBVARS([TIFF])
WITHLIB_OPTION([tiff], [TIFF]) WITHLIB_OPTION([tiff], [TIFF])
@ -563,14 +286,9 @@ AS_IF([test "x$enable_tiff" != "xno"], [
AC_MSG_WARN(tiff library not available - no tiffio.h) AC_MSG_WARN(tiff library not available - no tiffio.h)
) )
LIBCHECK_EPILOGUE([TIFF]) LIBCHECK_EPILOGUE([TIFF])
])
dnl === check for GIF support === dnl === check for GIF support ===
AC_ARG_ENABLE([gif], AS_HELP_STRING([--disable-gif],
[Disable detection of GIF format support
@<:@default=auto@:>@]))
AS_IF([test "x$enable_gif" != "xno"], [
CLEAR_LIBVARS([GIF]) CLEAR_LIBVARS([GIF])
WITHLIB_OPTION([gif], [GIF]) WITHLIB_OPTION([gif], [GIF])
@ -578,8 +296,6 @@ AS_IF([test "x$enable_gif" != "xno"], [
AC_CHECK_HEADER(gif_lib.h, AC_CHECK_HEADER(gif_lib.h,
AC_CHECK_LIB([gif], [DGifOpenFileHandle], AC_CHECK_LIB([gif], [DGifOpenFileHandle],
[GIF_LIBS="$GIF_LIBS -lgif" [GIF_LIBS="$GIF_LIBS -lgif"
AC_DEFINE(WEBP_HAVE_GIF, [1],
[Set to 1 if GIF library is installed])
gif_support=yes gif_support=yes
], ],
AC_MSG_WARN(Optional gif library not found), AC_MSG_WARN(Optional gif library not found),
@ -588,40 +304,15 @@ AS_IF([test "x$enable_gif" != "xno"], [
) )
LIBCHECK_EPILOGUE([GIF]) LIBCHECK_EPILOGUE([GIF])
if test "$gif_support" = "yes" -a \
"$enable_libwebpdemux" = "yes"; then
build_anim_diff=yes
fi
if test "$gif_support" = "yes" -a \ if test "$gif_support" = "yes" -a \
"$enable_libwebpmux" = "yes"; then "$enable_libwebpmux" = "yes"; then
build_gif2webp=yes build_gif2webp=yes
fi fi
])
AM_CONDITIONAL([BUILD_ANIMDIFF], [test "${build_anim_diff}" = "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], if test "$target_os" = "mingw32"; then
AS_HELP_STRING([--disable-wic],
[Disable Windows Imaging Component (WIC) detection.
@<:@default=auto@:>@]),,
[enable_wic=yes])
case $host_os in
mingw*)
if test "$enable_wic" = "yes"; then
AC_CHECK_HEADERS([wincodec.h shlwapi.h windows.h]) AC_CHECK_HEADERS([wincodec.h shlwapi.h windows.h])
if test "$ac_cv_header_wincodec_h" = "yes"; then if test "$ac_cv_header_wincodec_h" = "yes"; then
AC_MSG_CHECKING(for Windows Imaging Component support) AC_MSG_CHECKING(for Windows Imaging Component support)
@ -661,9 +352,8 @@ if test "$enable_wic" = "yes"; then
AC_MSG_RESULT(${wic_support-no}) AC_MSG_RESULT(${wic_support-no})
fi fi
fi fi
esac
dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP=1 dnl === If --enable-swap-16bit-csp is defined, add -DWEBP_SWAP_16BIT_CSP
USE_SWAP_16BIT_CSP="" 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)
@ -671,25 +361,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)
@ -697,16 +385,15 @@ AC_ARG_ENABLE([libwebpmux],
AS_HELP_STRING([--enable-libwebpmux], AS_HELP_STRING([--enable-libwebpmux],
[Build libwebpmux @<:@default=no@:>@])) [Build libwebpmux @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpmux-no}) AC_MSG_RESULT(${enable_libwebpmux-no})
AM_CONDITIONAL([BUILD_MUX], [test "$enable_libwebpmux" = "yes"]) 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([BUILD_DEMUX], [test "$enable_libwebpdemux" = "yes"]) AM_CONDITIONAL([WANT_DEMUX], [test "$enable_libwebpdemux" = "yes"])
dnl === Check whether decoder library should be built. dnl === Check whether decoder library should be built.
AC_MSG_CHECKING(whether decoder library is to be built) AC_MSG_CHECKING(whether decoder library is to be built)
@ -716,21 +403,13 @@ AC_ARG_ENABLE([libwebpdecoder],
AC_MSG_RESULT(${enable_libwebpdecoder-no}) AC_MSG_RESULT(${enable_libwebpdecoder-no})
AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"]) AM_CONDITIONAL([BUILD_LIBWEBPDECODER], [test "$enable_libwebpdecoder" = "yes"])
dnl === Check whether libwebpextras should be built
AC_MSG_CHECKING(whether libwebpextras is to be built)
AC_ARG_ENABLE([libwebpextras],
AS_HELP_STRING([--enable-libwebpextras],
[Build libwebpextras @<:@default=no@:>@]))
AC_MSG_RESULT(${enable_libwebpextras-no})
AM_CONDITIONAL([BUILD_EXTRAS], [test "$enable_libwebpextras" = "yes"])
dnl ========================= dnl =========================
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([src/webp/config.h]) AC_CONFIG_HEADERS([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/libwebp.pc src/libwebpdecoder.pc \ src/libwebp.pc src/libwebpdecoder.pc \
@ -745,33 +424,26 @@ WebP Configuration Summary
Shared libraries: ${enable_shared} Shared libraries: ${enable_shared}
Static libraries: ${enable_static} Static libraries: ${enable_static}
Threading support: ${enable_threading-no} Threaded decode: ${enable_threading-no}
libwebp: yes libwebp: yes
libwebpdecoder: ${enable_libwebpdecoder-no} libwebpdecoder: ${enable_libwebpdecoder-no}
libwebpdemux: ${enable_libwebpdemux-no} libwebpdemux: ${enable_libwebpdemux-no}
libwebpmux: ${enable_libwebpmux-no} libwebpmux: ${enable_libwebpmux-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}
anim_diff : ${build_anim_diff-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

@ -46,16 +46,25 @@ for:
* **Animation.** An image may have multiple frames with pauses between them, * **Animation.** An image may have multiple frames with pauses between them,
making it an animation. making it an animation.
* **Image Fragmentation.** A single bitstream in WebP has an inherent
limitation for width or height of 2^14 pixels, and, when using VP8, a 512
KiB limit on the size of the first compressed partition. To support larger
images, the format supports images that are composed of multiple fragments,
each encoded as a separate bitstream. All fragments logically form a single
image: they have common metadata, color profile, etc. Image fragmentation
may also improve efficiency for larger images, e.g., grass can be encoded
differently than sky.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC 2119][]. document are to be interpreted as described in [RFC 2119][].
Bit numbering in chunk diagrams starts at `0` for the most significant bit
('MSB 0') as described in [RFC 1166][].
**Note:** Out of the features mentioned above, lossy compression, lossless **Note:** Out of the features mentioned above, lossy compression, lossless
compression, transparency, metadata, color profile and animation are finalized compression, transparency, metadata, color profile and animation are finalized
and are to be considered stable. and are to be considered stable. On the other hand, image fragmentation is
experimental as of now, and is open to discussion, feedback and comments.
The same is indicated using annotation "_status: experimental_" in the relevant
sections of this document.
Terminology &amp; Basics Terminology &amp; Basics
------------------------ ------------------------
@ -94,10 +103,8 @@ _1-based_
: An unsigned integer field storing values offset by `-1`. e.g., Such a field : An unsigned integer field storing values offset by `-1`. e.g., Such a field
would store value _25_ as _24_. would store value _25_ as _24_.
RIFF file format
RIFF File Format
---------------- ----------------
The WebP file format is based on the RIFF (resource interchange file format) The WebP file format is based on the RIFF (resource interchange file format)
document format. document format.
@ -137,8 +144,7 @@ _ChunkHeader('ABCD')_
chunks that apply to any RIFF file format, while FourCCs specific to a file chunks that apply to any RIFF file format, while FourCCs specific to a file
format are all lowercase. WebP does not follow this convention. format are all lowercase. WebP does not follow this convention.
WebP file header
WebP File Header
---------------- ----------------
0 1 2 3 0 1 2 3
@ -171,8 +177,7 @@ the 'WEBP' FourCC. The file SHOULD NOT contain anything after it. As the size
of any chunk is even, the size given by the RIFF header is also even. The of any chunk is even, the size given by the RIFF header is also even. The
contents of individual chunks will be described in the following sections. contents of individual chunks will be described in the following sections.
Simple file format (lossy)
Simple File Format (Lossy)
-------------------------- --------------------------
This layout SHOULD be used if the image requires _lossy_ encoding and does not This layout SHOULD be used if the image requires _lossy_ encoding and does not
@ -210,8 +215,7 @@ width and height. That is assumed to be the width and height of the canvas.
The VP8 specification describes how to decode the image into Y'CbCr The VP8 specification describes how to decode the image into Y'CbCr
format. To convert to RGB, Rec. 601 SHOULD be used. format. To convert to RGB, Rec. 601 SHOULD be used.
Simple file format (lossless)
Simple File Format (Lossless)
----------------------------- -----------------------------
**Note:** Older readers may not support files using the lossless format. **Note:** Older readers may not support files using the lossless format.
@ -249,8 +253,7 @@ The current specification of the VP8L bitstream can be found at
contains the VP8L image width and height. That is assumed to be the width contains the VP8L image width and height. That is assumed to be the width
and height of the canvas. and height of the canvas.
Extended file format
Extended File Format
-------------------- --------------------
**Note:** Older readers may not support files using the extended format. **Note:** Older readers may not support files using the extended format.
@ -271,15 +274,13 @@ An extended format file consists of:
* An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_ * An optional list of [unknown chunks](#unknown-chunks). _\[status: experimental\]_
For a _still image_, the _image data_ consists of a single frame, which is made For a _still image_, the _image data_ consists of a single frame, whereas for
up of: an _animated image_, it consists of multiple frames. More details about frames
can be found in the [Animation](#animation) section.
* An optional [alpha subchunk](#alpha). Moreover, each frame can be fragmented or non-fragmented, as will be described
in the [Extended WebP file header](#extended_header) section. More details about
* A [bitstream subchunk](#bitstream-vp8vp8l). fragments can be found in the [Fragments](#fragments) section.
For an _animated image_, the _image data_ consists of multiple frames. More
details about frames can be found in the [Animation](#animation) section.
All chunks SHOULD be placed in the same order as listed above. If a chunk All chunks SHOULD be placed in the same order as listed above. If a chunk
appears in the wrong place, the file is invalid, but readers MAY parse the appears in the wrong place, the file is invalid, but readers MAY parse the
@ -301,7 +302,7 @@ Extended WebP file header:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('VP8X') | | ChunkHeader('VP8X') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|R| Reserved | |Rsv|I|L|E|X|A|F| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Canvas Width Minus One | ... | Canvas Width Minus One | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -334,9 +335,9 @@ Animation (A): 1 bit
: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be : Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
used to control the animation. used to control the animation.
Reserved (R): 1 bit Image Fragmentation (F): 1 bit _\[status: experimental\]_
: SHOULD be `0`. : Set if any of the frames in the image are represented by fragments.
Reserved: 24 bits Reserved: 24 bits
@ -381,20 +382,13 @@ animation.
Background Color: 32 bits (_uint32_) Background Color: 32 bits (_uint32_)
: The default background color of the canvas in \[Blue, Green, Red, Alpha\] : The default background color of the canvas in \[Blue, Green, Red, Alpha\]
byte order. This color MAY be used to fill the unused space on the canvas byte order. This color is used to fill the unused space on the canvas around the
around the frames, as well as the transparent pixels of the first frame. frames, as well as the transparent pixels of the first frame. Background color
Background color is also used when disposal method is `1`. is also used when disposal method is `1`.
**Note**: **Note**: Viewers that have a preferred background against which to present the
images (web browsers, for example) should ignore this value and use their
* Background color MAY contain a transparency value (alpha), even if the preferred background color instead.
_Alpha_ flag in [VP8X chunk](#extended_header) is unset.
* Viewer applications SHOULD treat the background color value as a hint, and
are not required to use it.
* The canvas is cleared at the start of each loop. The background color MAY be
used to achieve this.
Loop Count: 16 bits (_uint16_) Loop Count: 16 bits (_uint16_)
@ -404,6 +398,7 @@ This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
If the _Animation_ flag is not set and this chunk is present, it If the _Animation_ flag is not set and this chunk is present, it
SHOULD be ignored. SHOULD be ignored.
ANMF chunk: ANMF chunk:
For animated images, this chunk contains information about a _single_ frame. For animated images, this chunk contains information about a _single_ frame.
@ -420,7 +415,7 @@ If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... | Frame Height Minus One | ... | Frame Height Minus One |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Duration | Reserved |B|D| | Frame Duration | Reserved |D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Data | | Frame Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -446,39 +441,28 @@ 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 multiple
implementation defined. Many tools and browsers assign a minimum duration areas of the canvas at once during the animation.
similar to GIF.
Reserved: 6 bits Reserved: 7 bits
: SHOULD be 0. : SHOULD be 0.
Blending method (B): 1 bit
: Indicates how transparent pixels of _the current frame_ are to be blended
with corresponding pixels of the previous canvas:
* `0`: Use alpha blending. After disposing of the previous frame, render the
current frame on the canvas using [alpha-blending](#alpha-blending). If
the current frame does not have an alpha channel, assume alpha value of
255, effectively replacing the rectangle.
* `1`: Do not blend. After disposing of the previous frame, render the
current frame on the canvas by overwriting the rectangle covered by the
current frame.
Disposal method (D): 1 bit Disposal method (D): 1 bit
: Indicates how _the current frame_ is to be treated after it has been : Indicates how _the current frame_ is to be treated after it has been displayed
displayed (before rendering the next frame) on the canvas: (before rendering the next frame) on the canvas:
* `0`: Do not dispose. Leave the canvas as is. * `0`: Do not dispose. Leave the canvas as is.
* `1`: Dispose to background color. Fill the _rectangle_ on the canvas * `1`: Dispose to background color. Fill the _rectangle_ on the canvas covered
covered by the _current frame_ with background color specified in the by the _current frame_ with background color specified in the
[ANIM chunk](#anim_chunk). [ANIM chunk](#anim_chunk).
After disposing the current frame, render the next frame on the canvas using
[alpha-blending](#alpha-blending). If the next frame does not have an alpha
channel, assume alpha value of 255, effectively replacing the rectangle.
**Notes**: **Notes**:
* The frame disposal only applies to the _frame rectangle_, that is, the * The frame disposal only applies to the _frame rectangle_, that is, the
@ -508,7 +492,9 @@ Disposal method (D): 1 bit
Frame Data: _Chunk Size_ - `16` bytes Frame Data: _Chunk Size_ - `16` bytes
: Consists of: : For a fragmented frame, it consists of multiple [fragment chunks](#fragments).
: For a non-fragmented frame, it consists of:
* An optional [alpha subchunk](#alpha) for the frame. * An optional [alpha subchunk](#alpha) for the frame.
@ -519,6 +505,49 @@ Frame Data: _Chunk Size_ - `16` bytes
**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual **Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
_padded_ chunks as described by the [RIFF file format](#riff-file-format). _padded_ chunks as described by the [RIFF file format](#riff-file-format).
#### Fragments _\[status: experimental\]_
For images that are represented by fragments, this chunk contains data for
a single fragment. If the _Image Fragmentation Flag_ is not set, then this chunk
SHOULD NOT be present.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ChunkHeader('FRGM') |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Fragment X | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
... Fragment Y | Fragment Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fragment X: 24 bits (_uint24_)
: The X coordinate of the upper left corner of the fragment is `Fragment X * 2`
Fragment Y: 24 bits (_uint24_)
: The Y coordinate of the upper left corner of the fragment is `Fragment Y * 2`
Fragment Data: _Chunk Size_ - `6` bytes
: It contains:
* An optional [alpha subchunk](#alpha) for the fragment.
* The [bitstream subchunk](#bitstream-vp8vp8l) for the fragment.
* An optional list of [unknown chunks](#unknown-chunks).
Note: The width and height of the fragment is obtained from the bitstream
subchunk.
The fragments of a frame SHOULD have the following properties:
* They collectively cover the whole frame.
* No pair of fragments have any overlapping region on the frame.
* No portion of any fragment should be located outside of the canvas.
#### Alpha #### Alpha
0 1 2 3 0 1 2 3
@ -600,8 +629,8 @@ Alpha bitstream: _Chunk Size_ - `1` bytes
: Encoded alpha bitstream. : Encoded alpha bitstream.
This optional chunk contains encoded alpha data for this frame. A frame This optional chunk contains encoded alpha data for this frame/fragment. A
containing a 'VP8L' chunk SHOULD NOT contain this chunk. frame/fragment containing a 'VP8L' chunk SHOULD NOT contain this chunk.
**Rationale**: The transparency information is already part of the 'VP8L' **Rationale**: The transparency information is already part of the 'VP8L'
chunk. chunk.
@ -632,15 +661,15 @@ compression method is '0') or compressed using the lossless format
#### Bitstream (VP8/VP8L) #### Bitstream (VP8/VP8L)
This chunk contains compressed bitstream data for a single frame. This chunk contains compressed bitstream data for a single frame/fragment.
A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
"VP8L" as its tag. "VP8L" as its tag.
The formats of VP8 and VP8L chunks are as described in sections The formats of VP8 and VP8L chunks are as described in sections
[Simple File Format (Lossy)](#simple-file-format-lossy) [Simple file format (lossy)](#simple-file-format-lossy)
and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively. and [Simple file format (lossless)](#simple-file-format-lossless) respectively.
#### Color profile #### Color profile
@ -688,6 +717,7 @@ EXIF Metadata: _Chunk Size_ bytes
: image metadata in EXIF format. : image metadata in EXIF format.
XMP chunk: XMP chunk:
0 1 2 3 0 1 2 3
@ -718,17 +748,47 @@ A file MAY contain unknown chunks:
* At the end of the file as described in [Extended WebP file * At the end of the file as described in [Extended WebP file
header](#extended_header) section. header](#extended_header) section.
* At the end of ANMF chunks as described in the * At the end of FRGM and ANMF chunks as described in [Fragments](#fragments)
[Animation](#animation) section. and [Animation](#animation) sections.
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks). original order (unless they specifically intend to modify these chunks).
### Assembling the Canvas from frames ### Assembling the Canvas from fragments/frames
Here we provide an overview of how a reader should assemble a canvas in the Here we provide an overview of how a reader should assemble a canvas in case
case of an animated image. The notation _VP8X.field_ means the field in the of a fragmented-image and in case of an animated image. The notation
'VP8X' chunk with the same description. _VP8X.field_ means the field in the 'VP8X' chunk with the same description.
Displaying a _fragmented image_ canvas MUST be equivalent to the following
pseudocode: _\[status: experimental\]_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert VP8X.flags.hasFragments
canvas ← new black image of size VP8X.canvasWidth x VP8X.canvasHeight.
frgm_params ← nil
for chunk in image_data:
assert chunk.tag is "FRGM"
frgm_params.fragmentX = Fragment X
frgm_params.fragmentY = Fragment Y
for subchunk in 'Fragment Data':
if subchunk.tag == "ALPH":
assert alpha subchunks not found in 'Fragment Data' earlier
frgm_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Fragment Data' earlier
frgm_params.bitstream = bitstream_data
frgm_params.fragmentWidth = Width extracted from bitstream subchunk
frgm_params.fragmentHeight = Height extracted from bitstream subchunk
assert VP8X.canvasWidth >=
frgm_params.fragmentX + frgm_params.fragmentWidth
assert VP8X.canvasHeight >=
frgm_params.fragmentY + frgm_params.fragmentHeight
assert fragment has the properties mentioned in "Image Fragments" section.
render fragment with frame_params.alpha and frame_params.bitstream on canvas
with top-left corner in (frgm_params.fragmentX, frgm_params.fragmentY).
canvas contains the decoded canvas.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Displaying an _animated image_ canvas MUST be equivalent to the following Displaying an _animated image_ canvas MUST be equivalent to the following
pseudocode: pseudocode:
@ -742,19 +802,22 @@ dispose_method ← ANIM.disposeMethod
if loop_count == 0: if loop_count == 0:
loop_count = ∞ loop_count = ∞
frame_params ← nil frame_params ← nil
for loop = 0, ..., loop_count - 1
assert next chunk in image_data is ANMF assert next chunk in image_data is ANMF
for loop = 0..loop_count - 1
clear canvas to ANIM.background_color or application defined color
until eof or non-ANMF chunk
frame_params.frameX = Frame X frame_params.frameX = Frame X
frame_params.frameY = Frame Y frame_params.frameY = Frame Y
frame_params.frameWidth = Frame Width Minus One + 1 frame_params.frameWidth = Frame Width Minus One + 1
frame_params.frameHeight = Frame Height Minus One + 1 frame_params.frameHeight = Frame Height Minus One + 1
frame_params.frameDuration = Frame Duration frame_params.frameDuration = Frame Duration
frame_right = frame_params.frameX + frame_params.frameWidth assert VP8X.canvasWidth >= frame_params.frameX + frame_params.frameWidth
frame_bottom = frame_params.frameY + frame_params.frameHeight assert VP8X.canvasHeight >= frame_params.frameY + frame_params.frameHeight
assert VP8X.canvasWidth >= frame_right if VP8X.flags.hasFragments and first subchunk in 'Frame Data' is FRGM
assert VP8X.canvasHeight >= frame_bottom // Fragmented frame.
frame_params.{bitstream,alpha} = canvas decoded from subchunks in
'Frame Data' as per the pseudocode for
_fragmented image_ above.
else
// Non-fragmented frame.
for subchunk in 'Frame Data': for subchunk in 'Frame Data':
if subchunk.tag == "ALPH": if subchunk.tag == "ALPH":
assert alpha subchunks not found in 'Frame Data' earlier assert alpha subchunks not found in 'Frame Data' earlier
@ -762,15 +825,14 @@ for loop = 0..loop_count - 1
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L": else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
assert bitstream subchunks not found in 'Frame Data' earlier assert bitstream subchunks not found in 'Frame Data' earlier
frame_params.bitstream = bitstream_data frame_params.bitstream = bitstream_data
render frame with frame_params.alpha and frame_params.bitstream on render frame with frame_params.alpha and frame_params.bitstream on canvas
canvas with top-left corner at (frame_params.frameX, with top-left corner in (frame_params.frameX, frame_params.frameY), using
frame_params.frameY), using dispose method dispose_method. dispose method dispose_method.
canvas contains the decoded image. Show the contents of the image for frame_params.frameDuration * 1ms.
Show the contents of the canvas for frame_params.frameDuration * 1ms. canvas contains the decoded canvas.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example file layouts
Example File Layouts
-------------------- --------------------
A lossy encoded image with alpha may look as follows: A lossy encoded image with alpha may look as follows:
@ -802,6 +864,17 @@ RIFF/WEBP
+- XMP (metadata) +- XMP (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A fragmented image may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
+- FRGM (fragment1 parameters + data)
+- FRGM (fragment2 parameters + data)
+- FRGM (fragment3 parameters + data)
+- FRGM (fragment4 parameters + data)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An animated image with EXIF metadata may look as follows: An animated image with EXIF metadata may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -816,8 +889,7 @@ RIFF/WEBP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[vp8spec]: http://tools.ietf.org/html/rfc6386 [vp8spec]: http://tools.ietf.org/html/rfc6386
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt [webpllspec]: https://gerrit.chromium.org/gerrit/gitweb?p=webm/libwebp.git;a=blob;f=doc/webp-lossless-bitstream-spec.txt;hb=master
[iccspec]: http://www.color.org/icc_specs2.xalter [iccspec]: http://www.color.org/icc_specs2.xalter
[metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf [metadata]: http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
[rfc 1166]: http://tools.ietf.org/html/rfc1166
[rfc 2119]: http://tools.ietf.org/html/rfc2119 [rfc 2119]: http://tools.ietf.org/html/rfc2119

View File

@ -14,7 +14,6 @@ Specification for WebP Lossless Bitstream
_Jyrki Alakuijala, Ph.D., Google, Inc., 2012-06-19_ _Jyrki Alakuijala, Ph.D., Google, Inc., 2012-06-19_
Paragraphs marked as \[AMENDED\] were amended on 2014-09-16.
Abstract Abstract
-------- --------
@ -173,8 +172,8 @@ It should be set to 0 when all alpha values are 255 in the picture, and
int alpha_is_used = ReadBits(1); int alpha_is_used = ReadBits(1);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The version_number is a 3 bit code that must be set to 0. Any other value The version_number is a 3 bit code that must be discarded by the decoder
should be treated as an error. \[AMENDED\] at this time. Complying encoders write a 3-bit value 0.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int version_number = ReadBits(3); int version_number = ReadBits(3);
@ -331,7 +330,7 @@ uint32 Select(uint32 L, uint32 T, uint32 TL) {
abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T)); abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T));
// Return either left or top, the one closer to the prediction. // Return either left or top, the one closer to the prediction.
if (pL < pT) { // \[AMENDED\] if (pL <= pT) {
return L; return L;
} else { } else {
return T; return T;
@ -429,11 +428,6 @@ int8 ColorTransformDelta(int8 t, int8 c) {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A conversion from the 8-bit unsigned representation (uint8) to the 8-bit
signed one (int8) is required before calling ColorTransformDelta().
It should be performed using 8-bit two's complement (that is: uint8 range
\[128-255\] is mapped to the \[-128, -1\] range of its converted int8 value).
The multiplication is to be done using more precision (with at least The multiplication is to be done using more precision (with at least
16-bit dynamics). The sign extension property of the shift operation 16-bit dynamics). The sign extension property of the shift operation
does not matter here: only the lowest 8 bits are used from the result, does not matter here: only the lowest 8 bits are used from the result,
@ -548,9 +542,6 @@ color.
argb = color_table[GREEN(argb)]; argb = color_table[GREEN(argb)];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the index is equal or larger than color_table_size, the argb color value
should be set to 0x00000000 (transparent black). \[AMENDED\]
When the color table is small (equal to or less than 16 colors), several When the color table is small (equal to or less than 16 colors), several
pixels are bundled into a single pixel. The pixel bundling packs several pixels are bundled into a single pixel. The pixel bundling packs several
(2, 4, or 8) pixels into a single pixel, reducing the image width (2, 4, or 8) pixels into a single pixel, reducing the image width

View File

@ -1,93 +0,0 @@
LOCAL_PATH := $(call my-dir)
################################################################################
# libexample_util
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
example_util.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_MODULE := example_util
include $(BUILD_STATIC_LIBRARY)
################################################################################
# cwebp
include $(CLEAR_VARS)
# Note: to enable jpeg/png encoding the sources from AOSP can be used with
# minor modification to their Android.mk files.
LOCAL_SRC_FILES := \
cwebp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpdemux webp
LOCAL_MODULE := cwebp
include $(BUILD_EXECUTABLE)
################################################################################
# dwebp
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
dwebp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webpdemux webp
LOCAL_MODULE := dwebp
include $(BUILD_EXECUTABLE)
################################################################################
# webpmux
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
webpmux.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp
LOCAL_MODULE := webpmux_example
include $(BUILD_EXECUTABLE)
################################################################################
# img2webp
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
img2webp.c \
LOCAL_CFLAGS := $(WEBP_CFLAGS)
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_STATIC_LIBRARIES := example_util imageio_util webp
LOCAL_MODULE := webpinfo_example
include $(BUILD_EXECUTABLE)

View File

@ -1,119 +1,52 @@
AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src AM_CPPFLAGS = -I$(top_srcdir)/src
bin_PROGRAMS = bin_PROGRAMS = dwebp cwebp
if BUILD_DEMUX
bin_PROGRAMS += dwebp cwebp
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
if BUILD_MUX
bin_PROGRAMS += webpmux
endif
if BUILD_VWEBP if BUILD_VWEBP
bin_PROGRAMS += vwebp bin_PROGRAMS += vwebp
endif endif
if BUILD_WEBPINFO if WANT_MUX
bin_PROGRAMS += webpinfo bin_PROGRAMS += webpmux
endif endif
noinst_LTLIBRARIES = libexample_util.la if BUILD_GIF2WEBP
bin_PROGRAMS += gif2webp
endif
libexample_util_la_SOURCES = example_util.c example_util.h noinst_LTLIBRARIES = libexampleutil.la
libexample_util_la_LIBADD = ../src/libwebp.la
anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h gifdec.c gifdec.h libexampleutil_la_SOURCES = example_util.c example_util.h
anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES)
anim_diff_LDADD =
anim_diff_LDADD += ../src/demux/libwebpdemux.la
anim_diff_LDADD += libexample_util.la
anim_diff_LDADD += ../imageio/libimageio_util.la
anim_diff_LDADD += $(GIF_LIBS) -lm
anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h gifdec.c gifdec.h
anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES)
anim_dump_CPPFLAGS += $(GIF_INCLUDES)
anim_dump_LDADD =
anim_dump_LDADD += ../src/demux/libwebpdemux.la
anim_dump_LDADD += libexample_util.la
anim_dump_LDADD += ../imageio/libimageio_util.la
anim_dump_LDADD += ../imageio/libimageenc.la
anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm
cwebp_SOURCES = cwebp.c stopwatch.h
cwebp_CPPFLAGS = $(AM_CPPFLAGS)
cwebp_LDADD =
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)
dwebp_SOURCES = dwebp.c stopwatch.h dwebp_SOURCES = dwebp.c stopwatch.h
dwebp_CPPFLAGS = $(AM_CPPFLAGS) dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES)
dwebp_LDADD = dwebp_LDADD = libexampleutil.la $(PNG_LIBS) $(JPEG_LIBS)
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 cwebp_SOURCES = cwebp.c metadata.c metadata.h stopwatch.h
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) cwebp_SOURCES += jpegdec.c jpegdec.h
gif2webp_LDADD = cwebp_SOURCES += pngdec.c pngdec.h
gif2webp_LDADD += libexample_util.la cwebp_SOURCES += tiffdec.c tiffdec.h
gif2webp_LDADD += ../imageio/libimageio_util.la cwebp_SOURCES += wicdec.c wicdec.h
gif2webp_LDADD += ../src/mux/libwebpmux.la cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE)
gif2webp_LDADD += ../src/libwebp.la cwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES)
cwebp_LDADD = ../src/libwebp.la $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS)
gif2webp_SOURCES = gif2webp.c
gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) $(GIF_INCLUDES)
gif2webp_LDADD = libexampleutil.la ../src/mux/libwebpmux.la ../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 dwebp_LDADD += ../src/libwebpdecoder.la
anim_dump_LDADD += ../src/libwebpdecoder.la
vwebp_LDADD += ../src/libwebpdecoder.la vwebp_LDADD += ../src/libwebpdecoder.la
else else
anim_diff_LDADD += ../src/libwebp.la dwebp_LDADD += ../src/libwebp.la
anim_dump_LDADD += ../src/libwebp.la
vwebp_LDADD += ../src/libwebp.la vwebp_LDADD += ../src/libwebp.la
endif endif

View File

@ -1,317 +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.
// -----------------------------------------------------------------------------
//
// Checks if given pair of animated GIF/WebP images are identical:
// That is: their reconstructed canvases match pixel-by-pixel and their other
// animation properties (loop count etc) also match.
//
// example: anim_diff foo.gif bar.webp
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h> // for 'strtod'.
#include <string.h> // for 'strcmp'.
#include "./anim_util.h"
#include "./example_util.h"
#include "./unicode.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
// Returns true if 'a + b' will overflow.
static int AdditionWillOverflow(int a, int b) {
return (b > 0) && (a > INT_MAX - b);
}
static int FramesAreEqual(const uint8_t* const rgba1,
const uint8_t* const rgba2, int width, int height) {
const int stride = width * 4; // Always true for 'DecodedFrame.rgba'.
return !memcmp(rgba1, rgba2, stride * height);
}
static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst,
int max_allowed_diff) {
const int src_a = (src >> 24) & 0xff;
const int src_r = (src >> 16) & 0xff;
const int src_g = (src >> 8) & 0xff;
const int src_b = (src >> 0) & 0xff;
const int dst_a = (dst >> 24) & 0xff;
const int dst_r = (dst >> 16) & 0xff;
const int dst_g = (dst >> 8) & 0xff;
const int dst_b = (dst >> 0) & 0xff;
return (abs(src_r * src_a - dst_r * dst_a) <= (max_allowed_diff * 255)) &&
(abs(src_g * src_a - dst_g * dst_a) <= (max_allowed_diff * 255)) &&
(abs(src_b * src_a - dst_b * dst_a) <= (max_allowed_diff * 255)) &&
(abs(src_a - dst_a) <= max_allowed_diff);
}
static int FramesAreSimilar(const uint8_t* const rgba1,
const uint8_t* const rgba2,
int width, int height, int max_allowed_diff) {
int i, j;
assert(max_allowed_diff > 0);
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
const int stride = width * 4;
const size_t offset = j * stride + i;
if (!PixelsAreSimilar(rgba1[offset], rgba2[offset], max_allowed_diff)) {
return 0;
}
}
}
return 1;
}
// Minimize number of frames by combining successive frames that have at max
// 'max_diff' difference per channel between corresponding pixels.
static void MinimizeAnimationFrames(AnimatedImage* const img, int max_diff) {
uint32_t i;
for (i = 1; i < img->num_frames; ++i) {
DecodedFrame* const frame1 = &img->frames[i - 1];
DecodedFrame* const frame2 = &img->frames[i];
const uint8_t* const rgba1 = frame1->rgba;
const uint8_t* const rgba2 = frame2->rgba;
int should_merge_frames = 0;
// If merging frames will result in integer overflow for 'duration',
// skip merging.
if (AdditionWillOverflow(frame1->duration, frame2->duration)) continue;
if (max_diff > 0) {
should_merge_frames = FramesAreSimilar(rgba1, rgba2, img->canvas_width,
img->canvas_height, max_diff);
} else {
should_merge_frames =
FramesAreEqual(rgba1, rgba2, img->canvas_width, img->canvas_height);
}
if (should_merge_frames) { // Merge 'i+1'th frame into 'i'th frame.
frame1->duration += frame2->duration;
if (i + 1 < img->num_frames) {
memmove(&img->frames[i], &img->frames[i + 1],
(img->num_frames - i - 1) * sizeof(*img->frames));
}
--img->num_frames;
--i;
}
}
}
static int CompareValues(uint32_t a, uint32_t b, const char* output_str) {
if (a != b) {
fprintf(stderr, "%s: %d vs %d\n", output_str, a, b);
return 0;
}
return 1;
}
static int CompareBackgroundColor(uint32_t bg1, uint32_t bg2, int premultiply) {
if (premultiply) {
const int alpha1 = (bg1 >> 24) & 0xff;
const int alpha2 = (bg2 >> 24) & 0xff;
if (alpha1 == 0 && alpha2 == 0) return 1;
}
if (bg1 != bg2) {
fprintf(stderr, "Background color mismatch: 0x%08x vs 0x%08x\n",
bg1, bg2);
return 0;
}
return 1;
}
// Note: As long as frame durations and reconstructed frames are identical, it
// is OK for other aspects like offsets, dispose/blend method to vary.
static int CompareAnimatedImagePair(const AnimatedImage* const img1,
const AnimatedImage* const img2,
int premultiply,
double min_psnr) {
int ok = 1;
const int is_multi_frame_image = (img1->num_frames > 1);
uint32_t i;
ok = CompareValues(img1->canvas_width, img2->canvas_width,
"Canvas width mismatch") && ok;
ok = CompareValues(img1->canvas_height, img2->canvas_height,
"Canvas height mismatch") && ok;
ok = CompareValues(img1->num_frames, img2->num_frames,
"Frame count mismatch") && ok;
if (!ok) return 0; // These are fatal failures, can't proceed.
if (is_multi_frame_image) { // Checks relevant for multi-frame images only.
int max_loop_count_workaround = 0;
// Transcodes to webp increase the gif loop count by 1 for compatibility.
// When the gif has the maximum value the webp value will be off by one.
if ((img1->format == ANIM_GIF && img1->loop_count == 65536 &&
img2->format == ANIM_WEBP && img2->loop_count == 65535) ||
(img1->format == ANIM_WEBP && img1->loop_count == 65535 &&
img2->format == ANIM_GIF && img2->loop_count == 65536)) {
max_loop_count_workaround = 1;
}
ok = (max_loop_count_workaround ||
CompareValues(img1->loop_count, img2->loop_count,
"Loop count mismatch")) && ok;
ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor,
premultiply) && ok;
}
for (i = 0; i < img1->num_frames; ++i) {
// Pixel-by-pixel comparison.
const uint8_t* const rgba1 = img1->frames[i].rgba;
const uint8_t* const rgba2 = img2->frames[i].rgba;
int max_diff;
double psnr;
if (is_multi_frame_image) { // Check relevant for multi-frame images only.
const char format[] = "Frame #%d, duration mismatch";
char tmp[sizeof(format) + 8];
ok = ok && (snprintf(tmp, sizeof(tmp), format, i) >= 0);
ok = ok && CompareValues(img1->frames[i].duration,
img2->frames[i].duration, tmp);
}
GetDiffAndPSNR(rgba1, rgba2, img1->canvas_width, img1->canvas_height,
premultiply, &max_diff, &psnr);
if (min_psnr > 0.) {
if (psnr < min_psnr) {
fprintf(stderr, "Frame #%d, psnr = %.2lf (min_psnr = %f)\n", i,
psnr, min_psnr);
ok = 0;
}
} else {
if (max_diff != 0) {
fprintf(stderr, "Frame #%d, max pixel diff: %d\n", i, max_diff);
ok = 0;
}
}
}
return ok;
}
static void Help(void) {
printf("Usage: anim_diff <image1> <image2> [options]\n");
printf("\nOptions:\n");
printf(" -dump_frames <folder> dump decoded frames in PAM format\n");
printf(" -min_psnr <float> ... minimum per-frame PSNR\n");
printf(" -raw_comparison ..... if this flag is not used, RGB is\n");
printf(" premultiplied before comparison\n");
printf(" -max_diff <int> ..... maximum allowed difference per channel\n"
" between corresponding pixels in subsequent\n"
" frames\n");
printf(" -h .................. this help\n");
printf(" -version ............ print version number and exit\n");
}
int main(int argc, const char* argv[]) {
int return_code = -1;
int dump_frames = 0;
const char* dump_folder = NULL;
double min_psnr = 0.;
int got_input1 = 0;
int got_input2 = 0;
int premultiply = 1;
int max_diff = 0;
int i, c;
const char* files[2] = { NULL, NULL };
AnimatedImage images[2];
INIT_WARGV(argc, argv);
for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-dump_frames")) {
if (c < argc - 1) {
dump_frames = 1;
dump_folder = (const char*)GET_WARGV(argv, ++c);
} else {
parse_error = 1;
}
} else if (!strcmp(argv[c], "-min_psnr")) {
if (c < argc - 1) {
min_psnr = ExUtilGetFloat(argv[++c], &parse_error);
} else {
parse_error = 1;
}
} else if (!strcmp(argv[c], "-raw_comparison")) {
premultiply = 0;
} else if (!strcmp(argv[c], "-max_diff")) {
if (c < argc - 1) {
max_diff = ExUtilGetInt(argv[++c], 0, &parse_error);
} else {
parse_error = 1;
}
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help();
FREE_WARGV_AND_RETURN(0);
} else if (!strcmp(argv[c], "-version")) {
int dec_version, demux_version;
GetAnimatedImageVersions(&dec_version, &demux_version);
printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n",
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
(dec_version >> 0) & 0xff,
(demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff,
(demux_version >> 0) & 0xff);
FREE_WARGV_AND_RETURN(0);
} else {
if (!got_input1) {
files[0] = (const char*)GET_WARGV(argv, c);
got_input1 = 1;
} else if (!got_input2) {
files[1] = (const char*)GET_WARGV(argv, c);
got_input2 = 1;
} else {
parse_error = 1;
}
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
}
}
if (argc < 3) {
Help();
FREE_WARGV_AND_RETURN(-1);
}
if (!got_input2) {
Help();
FREE_WARGV_AND_RETURN(-1);
}
if (dump_frames) {
WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder);
}
memset(images, 0, sizeof(images));
for (i = 0; i < 2; ++i) {
WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]);
if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) {
WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n",
(const W_CHAR*)files[i]);
return_code = -2;
goto End;
} else {
MinimizeAnimationFrames(&images[i], max_diff);
}
}
if (!CompareAnimatedImagePair(&images[0], &images[1],
premultiply, min_psnr)) {
WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0],
(const W_CHAR*)files[1]);
return_code = -3;
} else {
WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0],
(const W_CHAR*)files[1]);
return_code = 0;
}
End:
ClearAnimatedImage(&images[0]);
ClearAnimatedImage(&images[1]);
FREE_WARGV_AND_RETURN(return_code);
}

View File

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

View File

@ -1,779 +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.
// -----------------------------------------------------------------------------
//
// Utilities for animated images
#include "./anim_util.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#if defined(WEBP_HAVE_GIF)
#include <gif_lib.h>
#endif
#include "webp/format_constants.h"
#include "webp/decode.h"
#include "webp/demux.h"
#include "../imageio/imageio_util.h"
#include "./gifdec.h"
#include "./unicode.h"
#include "./unicode_gif.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
static const int kNumChannels = 4;
// -----------------------------------------------------------------------------
// Common utilities.
#if defined(WEBP_HAVE_GIF)
// Returns true if the frame covers the full canvas.
static int IsFullFrame(int width, int height,
int canvas_width, int canvas_height) {
return (width == canvas_width && height == canvas_height);
}
#endif // WEBP_HAVE_GIF
static int CheckSizeForOverflow(uint64_t size) {
return (size == (size_t)size);
}
static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) {
uint32_t i;
uint8_t* mem = NULL;
DecodedFrame* frames = NULL;
const uint64_t rgba_size =
(uint64_t)image->canvas_width * kNumChannels * image->canvas_height;
const uint64_t total_size = (uint64_t)num_frames * rgba_size * sizeof(*mem);
const uint64_t total_frame_size = (uint64_t)num_frames * sizeof(*frames);
if (!CheckSizeForOverflow(total_size) ||
!CheckSizeForOverflow(total_frame_size)) {
return 0;
}
mem = (uint8_t*)malloc((size_t)total_size);
frames = (DecodedFrame*)malloc((size_t)total_frame_size);
if (mem == NULL || frames == NULL) {
free(mem);
free(frames);
return 0;
}
free(image->raw_mem);
image->num_frames = num_frames;
image->frames = frames;
for (i = 0; i < num_frames; ++i) {
frames[i].rgba = mem + i * rgba_size;
frames[i].duration = 0;
frames[i].is_key_frame = 0;
}
image->raw_mem = mem;
return 1;
}
void ClearAnimatedImage(AnimatedImage* const image) {
if (image != NULL) {
free(image->raw_mem);
free(image->frames);
image->num_frames = 0;
image->frames = NULL;
image->raw_mem = NULL;
}
}
#if defined(WEBP_HAVE_GIF)
// Clear the canvas to transparent.
static void ZeroFillCanvas(uint8_t* rgba,
uint32_t canvas_width, uint32_t canvas_height) {
memset(rgba, 0, canvas_width * kNumChannels * canvas_height);
}
// Clear given frame rectangle to transparent.
static void ZeroFillFrameRect(uint8_t* rgba, int rgba_stride, int x_offset,
int y_offset, int width, int height) {
int j;
assert(width * kNumChannels <= rgba_stride);
rgba += y_offset * rgba_stride + x_offset * kNumChannels;
for (j = 0; j < height; ++j) {
memset(rgba, 0, width * kNumChannels);
rgba += rgba_stride;
}
}
// Copy width * height pixels from 'src' to 'dst'.
static void CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) {
assert(src != NULL && dst != NULL);
memcpy(dst, src, width * kNumChannels * height);
}
// Copy pixels in the given rectangle from 'src' to 'dst' honoring the 'stride'.
static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride,
int x_offset, int y_offset,
int width, int height) {
int j;
const int width_in_bytes = width * kNumChannels;
const size_t offset = y_offset * stride + x_offset * kNumChannels;
assert(width_in_bytes <= stride);
src += offset;
dst += offset;
for (j = 0; j < height; ++j) {
memcpy(dst, src, width_in_bytes);
src += stride;
dst += stride;
}
}
#endif // WEBP_HAVE_GIF
// Canonicalize all transparent pixels to transparent black to aid comparison.
static void CleanupTransparentPixels(uint32_t* rgba,
uint32_t width, uint32_t height) {
const uint32_t* const rgba_end = rgba + width * height;
while (rgba < rgba_end) {
const uint8_t alpha = (*rgba >> 24) & 0xff;
if (alpha == 0) {
*rgba = 0;
}
++rgba;
}
}
// Dump frame to a PAM file. Returns true on success.
static int DumpFrame(const char filename[], const char dump_folder[],
uint32_t frame_num, const uint8_t rgba[],
int canvas_width, int canvas_height) {
int ok = 0;
size_t max_len;
int y;
const W_CHAR* base_name = NULL;
W_CHAR* file_name = NULL;
FILE* f = NULL;
const char* row;
if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR(".");
base_name = WSTRRCHR(filename, '/');
base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1;
max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name)
+ strlen("_frame_") + strlen(".pam") + 8;
file_name = (W_CHAR*)malloc(max_len * sizeof(*file_name));
if (file_name == NULL) goto End;
if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam",
(const W_CHAR*)dump_folder, base_name, frame_num) < 0) {
fprintf(stderr, "Error while generating file name\n");
goto End;
}
f = WFOPEN(file_name, "wb");
if (f == NULL) {
WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name);
ok = 0;
goto End;
}
if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n"
"DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
canvas_width, canvas_height) < 0) {
WFPRINTF(stderr, "Write error for file %s\n", file_name);
goto End;
}
row = (const char*)rgba;
for (y = 0; y < canvas_height; ++y) {
if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) {
WFPRINTF(stderr, "Error writing to file: %s\n", file_name);
goto End;
}
row += canvas_width * kNumChannels;
}
ok = 1;
End:
if (f != NULL) fclose(f);
free(file_name);
return ok;
}
// -----------------------------------------------------------------------------
// WebP Decoding.
// Returns true if this is a valid WebP bitstream.
static int IsWebP(const WebPData* const webp_data) {
return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0);
}
// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct.
static int ReadAnimatedWebP(const char filename[],
const WebPData* const webp_data,
AnimatedImage* const image, int dump_frames,
const char dump_folder[]) {
int ok = 0;
int dump_ok = 1;
uint32_t frame_index = 0;
int prev_frame_timestamp = 0;
WebPAnimDecoder* dec;
WebPAnimInfo anim_info;
memset(image, 0, sizeof(*image));
dec = WebPAnimDecoderNew(webp_data, NULL);
if (dec == NULL) {
WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename);
goto End;
}
if (!WebPAnimDecoderGetInfo(dec, &anim_info)) {
fprintf(stderr, "Error getting global info about the animation\n");
goto End;
}
// Animation properties.
image->canvas_width = anim_info.canvas_width;
image->canvas_height = anim_info.canvas_height;
image->loop_count = anim_info.loop_count;
image->bgcolor = anim_info.bgcolor;
// Allocate frames.
if (!AllocateFrames(image, anim_info.frame_count)) return 0;
// Decode frames.
while (WebPAnimDecoderHasMoreFrames(dec)) {
DecodedFrame* curr_frame;
uint8_t* curr_rgba;
uint8_t* frame_rgba;
int timestamp;
if (!WebPAnimDecoderGetNext(dec, &frame_rgba, &timestamp)) {
fprintf(stderr, "Error decoding frame #%u\n", frame_index);
goto End;
}
assert(frame_index < anim_info.frame_count);
curr_frame = &image->frames[frame_index];
curr_rgba = curr_frame->rgba;
curr_frame->duration = timestamp - prev_frame_timestamp;
curr_frame->is_key_frame = 0; // Unused.
memcpy(curr_rgba, frame_rgba,
image->canvas_width * kNumChannels * image->canvas_height);
// Needed only because we may want to compare with GIF later.
CleanupTransparentPixels((uint32_t*)curr_rgba,
image->canvas_width, image->canvas_height);
if (dump_frames && dump_ok) {
dump_ok = DumpFrame(filename, dump_folder, frame_index, curr_rgba,
image->canvas_width, image->canvas_height);
if (!dump_ok) { // Print error once, but continue decode loop.
fprintf(stderr, "Error dumping frames to %s\n", dump_folder);
}
}
++frame_index;
prev_frame_timestamp = timestamp;
}
ok = dump_ok;
if (ok) image->format = ANIM_WEBP;
End:
WebPAnimDecoderDelete(dec);
return ok;
}
// -----------------------------------------------------------------------------
// GIF Decoding.
#if defined(WEBP_HAVE_GIF)
// Returns true if this is a valid GIF bitstream.
static int IsGIF(const WebPData* const data) {
return data->size > GIF_STAMP_LEN &&
(!memcmp(GIF_STAMP, data->bytes, GIF_STAMP_LEN) ||
!memcmp(GIF87_STAMP, data->bytes, GIF_STAMP_LEN) ||
!memcmp(GIF89_STAMP, data->bytes, GIF_STAMP_LEN));
}
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR)
# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR)
# define LOCAL_GIF_PREREQ(maj, min) \
(LOCAL_GIF_VERSION >= (((maj) << 8) | (min)))
#else
# define LOCAL_GIF_VERSION 0
# define LOCAL_GIF_PREREQ(maj, min) 0
#endif
#if !LOCAL_GIF_PREREQ(5, 0)
// Added in v5.0
typedef struct {
int DisposalMode;
#define DISPOSAL_UNSPECIFIED 0 // No disposal specified
#define DISPOSE_DO_NOT 1 // Leave image in place
#define DISPOSE_BACKGROUND 2 // Set area to background color
#define DISPOSE_PREVIOUS 3 // Restore to previous content
int UserInputFlag; // User confirmation required before disposal
int DelayTime; // Pre-display delay in 0.01sec units
int TransparentColor; // Palette index for transparency, -1 if none
#define NO_TRANSPARENT_COLOR -1
} GraphicsControlBlock;
static int DGifExtensionToGCB(const size_t GifExtensionLength,
const GifByteType* GifExtension,
GraphicsControlBlock* gcb) {
if (GifExtensionLength != 4) {
return GIF_ERROR;
}
gcb->DisposalMode = (GifExtension[0] >> 2) & 0x07;
gcb->UserInputFlag = (GifExtension[0] & 0x02) != 0;
gcb->DelayTime = GifExtension[1] | (GifExtension[2] << 8);
if (GifExtension[0] & 0x01) {
gcb->TransparentColor = (int)GifExtension[3];
} else {
gcb->TransparentColor = NO_TRANSPARENT_COLOR;
}
return GIF_OK;
}
static int DGifSavedExtensionToGCB(GifFileType* GifFile, int ImageIndex,
GraphicsControlBlock* gcb) {
int i;
if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) {
return GIF_ERROR;
}
gcb->DisposalMode = DISPOSAL_UNSPECIFIED;
gcb->UserInputFlag = 0;
gcb->DelayTime = 0;
gcb->TransparentColor = NO_TRANSPARENT_COLOR;
for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {
ExtensionBlock* ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
return DGifExtensionToGCB(
ep->ByteCount, (const GifByteType*)ep->Bytes, gcb);
}
}
return GIF_ERROR;
}
#define CONTINUE_EXT_FUNC_CODE 0x00
// Signature was changed in v5.0
#define DGifOpenFileName(a, b) DGifOpenFileName(a)
#endif // !LOCAL_GIF_PREREQ(5, 0)
// Signature changed in v5.1
#if !LOCAL_GIF_PREREQ(5, 1)
#define DGifCloseFile(a, b) DGifCloseFile(a)
#endif
static int IsKeyFrameGIF(const GifImageDesc* prev_desc, int prev_dispose,
const DecodedFrame* const prev_frame,
int canvas_width, int canvas_height) {
if (prev_frame == NULL) return 1;
if (prev_dispose == DISPOSE_BACKGROUND) {
if (IsFullFrame(prev_desc->Width, prev_desc->Height,
canvas_width, canvas_height)) {
return 1;
}
if (prev_frame->is_key_frame) return 1;
}
return 0;
}
static int GetTransparentIndexGIF(GifFileType* gif) {
GraphicsControlBlock first_gcb;
memset(&first_gcb, 0, sizeof(first_gcb));
DGifSavedExtensionToGCB(gif, 0, &first_gcb);
return first_gcb.TransparentColor;
}
static uint32_t GetBackgroundColorGIF(GifFileType* gif) {
const int transparent_index = GetTransparentIndexGIF(gif);
const ColorMapObject* const color_map = gif->SColorMap;
if (transparent_index != NO_TRANSPARENT_COLOR &&
gif->SBackGroundColor == transparent_index) {
return 0x00000000; // Special case: transparent black.
} else if (color_map == NULL || color_map->Colors == NULL
|| gif->SBackGroundColor >= color_map->ColorCount) {
return 0xffffffff; // Invalid: assume white.
} else {
const GifColorType color = color_map->Colors[gif->SBackGroundColor];
return (0xff << 24) |
(color.Red << 16) |
(color.Green << 8) |
(color.Blue << 0);
}
}
// Find appropriate app extension and get loop count from the next extension.
// We use Chrome's interpretation of the 'loop_count' semantics:
// if not present -> loop once
// if present and loop_count == 0, return 0 ('infinite').
// if present and loop_count != 0, it's the number of *extra* loops
// so we need to return loop_count + 1 as total loop number.
static uint32_t GetLoopCountGIF(const GifFileType* const gif) {
int i;
for (i = 0; i < gif->ImageCount; ++i) {
const SavedImage* const image = &gif->SavedImages[i];
int j;
for (j = 0; (j + 1) < image->ExtensionBlockCount; ++j) {
const ExtensionBlock* const eb1 = image->ExtensionBlocks + j;
const ExtensionBlock* const eb2 = image->ExtensionBlocks + j + 1;
const char* const signature = (const char*)eb1->Bytes;
const int signature_is_ok =
(eb1->Function == APPLICATION_EXT_FUNC_CODE) &&
(eb1->ByteCount == 11) &&
(!memcmp(signature, "NETSCAPE2.0", 11) ||
!memcmp(signature, "ANIMEXTS1.0", 11));
if (signature_is_ok &&
eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 &&
eb2->Bytes[0] == 1) {
const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) +
((uint32_t)(eb2->Bytes[1]) << 0);
return (extra_loop > 0) ? extra_loop + 1 : 0;
}
}
}
return 1; // Default.
}
// Get duration of 'n'th frame in milliseconds.
static int GetFrameDurationGIF(GifFileType* gif, int n) {
GraphicsControlBlock gcb;
memset(&gcb, 0, sizeof(gcb));
DGifSavedExtensionToGCB(gif, n, &gcb);
return gcb.DelayTime * 10;
}
// Returns true if frame 'target' completely covers 'covered'.
static int CoversFrameGIF(const GifImageDesc* const target,
const GifImageDesc* const covered) {
return target->Left <= covered->Left &&
covered->Left + covered->Width <= target->Left + target->Width &&
target->Top <= covered->Top &&
covered->Top + covered->Height <= target->Top + target->Height;
}
static void RemapPixelsGIF(const uint8_t* const src,
const ColorMapObject* const cmap,
int transparent_color, int len, uint8_t* dst) {
int i;
for (i = 0; i < len; ++i) {
if (src[i] != transparent_color) {
// If a pixel in the current frame is transparent, we don't modify it, so
// that we can see-through the corresponding pixel from an earlier frame.
const GifColorType c = cmap->Colors[src[i]];
dst[4 * i + 0] = c.Red;
dst[4 * i + 1] = c.Green;
dst[4 * i + 2] = c.Blue;
dst[4 * i + 3] = 0xff;
}
}
}
static int ReadFrameGIF(const SavedImage* const gif_image,
const ColorMapObject* cmap, int transparent_color,
int out_stride, uint8_t* const dst) {
const GifImageDesc* image_desc = &gif_image->ImageDesc;
const uint8_t* in;
uint8_t* out;
int j;
if (image_desc->ColorMap) cmap = image_desc->ColorMap;
if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
fprintf(stderr, "Potentially corrupt color map.\n");
return 0;
}
in = (const uint8_t*)gif_image->RasterBits;
out = dst + image_desc->Top * out_stride + image_desc->Left * kNumChannels;
for (j = 0; j < image_desc->Height; ++j) {
RemapPixelsGIF(in, cmap, transparent_color, image_desc->Width, out);
in += image_desc->Width;
out += out_stride;
}
return 1;
}
// Read animated GIF bitstream from 'filename' into 'AnimatedImage' struct.
static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
int dump_frames, const char dump_folder[]) {
uint32_t frame_count;
uint32_t canvas_width, canvas_height;
uint32_t i;
int gif_error;
GifFileType* gif;
gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL);
if (gif == NULL) {
WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename);
return 0;
}
gif_error = DGifSlurp(gif);
if (gif_error != GIF_OK) {
WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename);
GIFDisplayError(gif, gif_error);
DGifCloseFile(gif, NULL);
return 0;
}
// Animation properties.
image->canvas_width = (uint32_t)gif->SWidth;
image->canvas_height = (uint32_t)gif->SHeight;
if (image->canvas_width > MAX_CANVAS_SIZE ||
image->canvas_height > MAX_CANVAS_SIZE) {
fprintf(stderr, "Invalid canvas dimension: %d x %d\n",
image->canvas_width, image->canvas_height);
DGifCloseFile(gif, NULL);
return 0;
}
image->loop_count = GetLoopCountGIF(gif);
image->bgcolor = GetBackgroundColorGIF(gif);
frame_count = (uint32_t)gif->ImageCount;
if (frame_count == 0) {
DGifCloseFile(gif, NULL);
return 0;
}
if (image->canvas_width == 0 || image->canvas_height == 0) {
image->canvas_width = gif->SavedImages[0].ImageDesc.Width;
image->canvas_height = gif->SavedImages[0].ImageDesc.Height;
gif->SavedImages[0].ImageDesc.Left = 0;
gif->SavedImages[0].ImageDesc.Top = 0;
if (image->canvas_width == 0 || image->canvas_height == 0) {
fprintf(stderr, "Invalid canvas size in GIF.\n");
DGifCloseFile(gif, NULL);
return 0;
}
}
// Allocate frames.
AllocateFrames(image, frame_count);
canvas_width = image->canvas_width;
canvas_height = image->canvas_height;
// Decode and reconstruct frames.
for (i = 0; i < frame_count; ++i) {
const int canvas_width_in_bytes = canvas_width * kNumChannels;
const SavedImage* const curr_gif_image = &gif->SavedImages[i];
GraphicsControlBlock curr_gcb;
DecodedFrame* curr_frame;
uint8_t* curr_rgba;
memset(&curr_gcb, 0, sizeof(curr_gcb));
DGifSavedExtensionToGCB(gif, i, &curr_gcb);
curr_frame = &image->frames[i];
curr_rgba = curr_frame->rgba;
curr_frame->duration = GetFrameDurationGIF(gif, i);
// Force frames with a small or no duration to 100ms to be consistent
// with web browsers and other transcoding tools (like gif2webp itself).
if (curr_frame->duration <= 10) curr_frame->duration = 100;
if (i == 0) { // Initialize as transparent.
curr_frame->is_key_frame = 1;
ZeroFillCanvas(curr_rgba, canvas_width, canvas_height);
} else {
DecodedFrame* const prev_frame = &image->frames[i - 1];
const GifImageDesc* const prev_desc = &gif->SavedImages[i - 1].ImageDesc;
GraphicsControlBlock prev_gcb;
memset(&prev_gcb, 0, sizeof(prev_gcb));
DGifSavedExtensionToGCB(gif, i - 1, &prev_gcb);
curr_frame->is_key_frame =
IsKeyFrameGIF(prev_desc, prev_gcb.DisposalMode, prev_frame,
canvas_width, canvas_height);
if (curr_frame->is_key_frame) { // Initialize as transparent.
ZeroFillCanvas(curr_rgba, canvas_width, canvas_height);
} else {
int prev_frame_disposed, curr_frame_opaque;
int prev_frame_completely_covered;
// Initialize with previous canvas.
uint8_t* const prev_rgba = image->frames[i - 1].rgba;
CopyCanvas(prev_rgba, curr_rgba, canvas_width, canvas_height);
// Dispose previous frame rectangle.
prev_frame_disposed =
(prev_gcb.DisposalMode == DISPOSE_BACKGROUND ||
prev_gcb.DisposalMode == DISPOSE_PREVIOUS);
curr_frame_opaque =
(curr_gcb.TransparentColor == NO_TRANSPARENT_COLOR);
prev_frame_completely_covered =
curr_frame_opaque &&
CoversFrameGIF(&curr_gif_image->ImageDesc, prev_desc);
if (prev_frame_disposed && !prev_frame_completely_covered) {
switch (prev_gcb.DisposalMode) {
case DISPOSE_BACKGROUND: {
ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes,
prev_desc->Left, prev_desc->Top,
prev_desc->Width, prev_desc->Height);
break;
}
case DISPOSE_PREVIOUS: {
int src_frame_num = i - 2;
while (src_frame_num >= 0) {
GraphicsControlBlock src_frame_gcb;
memset(&src_frame_gcb, 0, sizeof(src_frame_gcb));
DGifSavedExtensionToGCB(gif, src_frame_num, &src_frame_gcb);
if (src_frame_gcb.DisposalMode != DISPOSE_PREVIOUS) break;
--src_frame_num;
}
if (src_frame_num >= 0) {
// Restore pixels inside previous frame rectangle to
// corresponding pixels in source canvas.
uint8_t* const src_frame_rgba =
image->frames[src_frame_num].rgba;
CopyFrameRectangle(src_frame_rgba, curr_rgba,
canvas_width_in_bytes,
prev_desc->Left, prev_desc->Top,
prev_desc->Width, prev_desc->Height);
} else {
// Source canvas doesn't exist. So clear previous frame
// rectangle to background.
ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes,
prev_desc->Left, prev_desc->Top,
prev_desc->Width, prev_desc->Height);
}
break;
}
default:
break; // Nothing to do.
}
}
}
}
// Decode current frame.
if (!ReadFrameGIF(curr_gif_image, gif->SColorMap, curr_gcb.TransparentColor,
canvas_width_in_bytes, curr_rgba)) {
DGifCloseFile(gif, NULL);
return 0;
}
if (dump_frames) {
if (!DumpFrame(filename, dump_folder, i, curr_rgba,
canvas_width, canvas_height)) {
DGifCloseFile(gif, NULL);
return 0;
}
}
}
image->format = ANIM_GIF;
DGifCloseFile(gif, NULL);
return 1;
}
#else
static int IsGIF(const WebPData* const data) {
(void)data;
return 0;
}
static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image,
int dump_frames, const char dump_folder[]) {
(void)filename;
(void)image;
(void)dump_frames;
(void)dump_folder;
fprintf(stderr, "GIF support not compiled. Please install the libgif-dev "
"package before building.\n");
return 0;
}
#endif // WEBP_HAVE_GIF
// -----------------------------------------------------------------------------
int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
int dump_frames, const char dump_folder[]) {
int ok = 0;
WebPData webp_data;
WebPDataInit(&webp_data);
memset(image, 0, sizeof(*image));
if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) {
WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename);
return 0;
}
if (IsWebP(&webp_data)) {
ok = ReadAnimatedWebP(filename, &webp_data, image, dump_frames,
dump_folder);
} else if (IsGIF(&webp_data)) {
ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder);
} else {
WFPRINTF(stderr,
"Unknown file type: %s. Supported file types are WebP and GIF\n",
(const W_CHAR*)filename);
ok = 0;
}
if (!ok) ClearAnimatedImage(image);
WebPDataClear(&webp_data);
return ok;
}
static void Accumulate(double v1, double v2, double* const max_diff,
double* const sse) {
const double diff = fabs(v1 - v2);
if (diff > *max_diff) *max_diff = diff;
*sse += diff * diff;
}
void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
uint32_t width, uint32_t height, int premultiply,
int* const max_diff, double* const psnr) {
const uint32_t stride = width * kNumChannels;
const int kAlphaChannel = kNumChannels - 1;
double f_max_diff = 0.;
double sse = 0.;
uint32_t x, y;
for (y = 0; y < height; ++y) {
for (x = 0; x < stride; x += kNumChannels) {
int k;
const size_t offset = (size_t)y * stride + x;
const int alpha1 = rgba1[offset + kAlphaChannel];
const int alpha2 = rgba2[offset + kAlphaChannel];
Accumulate(alpha1, alpha2, &f_max_diff, &sse);
if (!premultiply) {
for (k = 0; k < kAlphaChannel; ++k) {
Accumulate(rgba1[offset + k], rgba2[offset + k], &f_max_diff, &sse);
}
} else {
// premultiply R/G/B channels with alpha value
for (k = 0; k < kAlphaChannel; ++k) {
Accumulate(rgba1[offset + k] * alpha1 / 255.,
rgba2[offset + k] * alpha2 / 255.,
&f_max_diff, &sse);
}
}
}
}
*max_diff = (int)f_max_diff;
if (*max_diff == 0) {
*psnr = 99.; // PSNR when images are identical.
} else {
sse /= stride * height;
*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

@ -1,73 +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.
// -----------------------------------------------------------------------------
//
// Utilities for animated images
#ifndef WEBP_EXAMPLES_ANIM_UTIL_H_
#define WEBP_EXAMPLES_ANIM_UTIL_H_
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "webp/types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ANIM_GIF,
ANIM_WEBP
} AnimatedFileFormat;
typedef struct {
uint8_t* rgba; // Decoded and reconstructed full frame.
int duration; // Frame duration in milliseconds.
int is_key_frame; // True if this frame is a key-frame.
} DecodedFrame;
typedef struct {
AnimatedFileFormat format;
uint32_t canvas_width;
uint32_t canvas_height;
uint32_t bgcolor;
uint32_t loop_count;
DecodedFrame* frames;
uint32_t num_frames;
void* raw_mem;
} AnimatedImage;
// Deallocate everything in 'image' (but not the object itself).
void ClearAnimatedImage(AnimatedImage* const image);
// Read animated image file into 'AnimatedImage' struct.
// If 'dump_frames' is true, dump frames to 'dump_folder'.
// Previous content of 'image' is obliterated.
// Upon successful return, content of 'image' must be deleted by
// calling 'ClearAnimatedImage'.
int ReadAnimatedImage(const char filename[], AnimatedImage* const image,
int dump_frames, const char dump_folder[]);
// Given two RGBA buffers, calculate max pixel difference and PSNR.
// If 'premultiply' is true, R/G/B values will be pre-multiplied by the
// transparency before comparison.
void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
uint32_t width, uint32_t height, int premultiply,
int* const max_diff, double* const psnr);
// Return library versions used by anim_util.
void GetAnimatedImageVersions(int* const decoder_version,
int* const demux_version);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_ANIM_UTIL_H_

File diff suppressed because it is too large Load Diff

View File

@ -17,195 +17,380 @@
#include <string.h> #include <string.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "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" #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 <shlwapi.h>
#include <windows.h>
#include <wincodec.h>
#endif
#include "webp/decode.h"
#include "./example_util.h"
#include "./stopwatch.h" #include "./stopwatch.h"
#include "./unicode.h"
static int verbose = 0; static int verbose = 0;
static int quiet = 0;
#ifndef WEBP_DLL #ifndef WEBP_DLL
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
extern void* VP8GetCPUInfo; // opaque forward declaration. extern void* VP8GetCPUInfo; // opaque forward declaration.
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_DLL #endif // WEBP_DLL
//------------------------------------------------------------------------------
static int SaveOutput(const WebPDecBuffer* const buffer, // Output types
WebPOutputFileFormat format, const char* const out_file) { typedef enum {
const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-"); PNG = 0,
PAM,
PPM,
PGM,
YUV,
ALPHA_PLANE_ONLY // this is for experimenting only
} 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, IStream** stream) {
HRESULT hr = S_OK;
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, REFGUID container_guid,
unsigned char* 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, &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 (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,
const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
unsigned char* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = (buffer->colorspace == MODE_BGRA);
return SUCCEEDED(WriteUsingWIC(out_file_name,
MAKE_REFGUID(GUID_ContainerFormatPng),
rgb, stride, width, height, has_alpha));
}
#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H
static void PNGAPI error_function(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;
unsigned char* const rgb = buffer->u.RGBA.rgba;
const int stride = buffer->u.RGBA.stride;
const int has_alpha = (buffer->colorspace == MODE_RGBA);
png_structp png;
png_infop info;
png_uint_32 y;
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, error_function, NULL);
if (png == NULL) {
return 0;
}
info = png_create_info_struct(png);
if (info == NULL) {
png_destroy_write_struct(&png, NULL);
return 0;
}
if (setjmp(png_jmpbuf(png))) {
png_destroy_write_struct(&png, &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, &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 unsigned char* 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 %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
"TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
} else {
fprintf(fout, "P6\n%d %d\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;
}
static int WriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width;
const uint32_t height = buffer->height;
const unsigned char* 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%d %d\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=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 ok = 1;
Stopwatch stop_watch; int y;
const int pad = (format == YUV) ? 0 : 1;
if (verbose) { const int uv_width = (width + 1) / 2;
StopwatchReset(&stop_watch); 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);
} }
ok = WebPSaveImage(buffer, format, out_file); for (y = 0; ok && y < height; ++y) {
ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
if (ok) { if (format == PGM) {
if (!quiet) { if (width & 1) fputc(0, fout); // padding byte
if (use_stdout) {
fprintf(stderr, "Saved to stdout\n");
} else {
WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file);
} }
} }
if (verbose) { if (format == PGM) { // IMC4 layout
const double write_time = StopwatchReadAndReset(&stop_watch); for (y = 0; ok && y < uv_height; ++y) {
fprintf(stderr, "Time to write output: %.3fs\n", write_time); 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 { } else {
if (use_stdout) { for (y = 0; ok && y < uv_height; ++y) {
fprintf(stderr, "Error writing to stdout !!\n"); ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
} else { }
WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file); 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; return ok;
} }
static void SaveOutput(const WebPDecBuffer* const buffer,
OutputFileFormat format, const char* const out_file) {
FILE* fout = NULL;
int needs_open_file = 1;
int ok = 1;
Stopwatch stop_watch;
if (verbose)
StopwatchReadAndReset(&stop_watch);
#ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG);
#endif
if (needs_open_file) {
fout = fopen(out_file, "wb");
if (!fout) {
fprintf(stderr, "Error opening output file %s\n", out_file);
return;
}
}
if (format == PNG) {
#ifdef HAVE_WINCODEC_H
ok &= WritePNG(out_file, buffer);
#else
ok &= WritePNG(fout, buffer);
#endif
} else if (format == PAM) {
ok &= WritePPM(fout, buffer, 1);
} else if (format == PPM) {
ok &= WritePPM(fout, buffer, 0);
} else if (format == PGM || format == YUV) {
ok &= WritePGMOrYUV(fout, buffer, format);
} else if (format == ALPHA_PLANE_ONLY) {
ok &= WriteAlphaPlane(fout, buffer);
}
if (fout) {
fclose(fout);
}
if (ok) {
printf("Saved file %s\n", out_file);
if (verbose) {
const double write_time = StopwatchReadAndReset(&stop_watch);
printf("Time to write output: %.3fs\n", write_time);
}
} else {
fprintf(stderr, "Error writing file %s !!\n", out_file);
}
}
static void Help(void) { static void Help(void) {
printf("Usage: dwebp in_file [options] [-o out_file]\n\n" printf("Usage: dwebp in_file [options] [-o out_file]\n\n"
"Decodes the WebP image file to PNG format [Default]\n" "Decodes the WebP image file to PNG format [Default]\n"
"Use following options to convert into alternate image formats:\n" "Use following options to convert into alternate image formats:\n"
" -pam ......... save the raw RGBA samples as a color PAM\n" " -pam ......... save the raw RGBA samples as a color PAM\n"
" -ppm ......... save the raw RGB samples as a color PPM\n" " -ppm ......... save the raw RGB samples as a color PPM\n"
" -bmp ......... save as uncompressed BMP format\n"
" -tiff ........ save as uncompressed TIFF format\n"
" -pgm ......... save the raw YUV samples as a grayscale PGM\n" " -pgm ......... save the raw YUV samples as a grayscale PGM\n"
" file with IMC4 layout\n" " file with IMC4 layout.\n"
" -yuv ......... save the raw YUV samples in flat layout\n" " -yuv ......... save the raw YUV samples in flat layout.\n"
"\n" "\n"
" Other options are:\n" " Other options are:\n"
" -version ..... print version number and exit\n" " -version .... print version number and exit.\n"
" -nofancy ..... don't use the fancy YUV420 upscaler\n" " -nofancy ..... don't use the fancy YUV420 upscaler.\n"
" -nofilter .... disable in-loop filtering\n" " -nofilter .... disable in-loop filtering.\n"
" -nodither .... disable dithering\n"
" -dither <d> .. dithering strength (in 0..100)\n"
" -alpha_dither use alpha-plane dithering if needed\n"
" -mt .......... use multi-threading\n" " -mt .......... use multi-threading\n"
" -crop <x> <y> <w> <h> ... crop output with the given rectangle\n" " -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
" -resize <w> <h> ......... scale the output (*after* any cropping)\n" " -scale <w> <h> .......... scale the output (*after* any cropping)\n"
" -flip ........ flip the output vertically\n" " -alpha ....... only save the alpha plane.\n"
" -alpha ....... only save the alpha plane\n" " -h ....... this help message.\n"
" -incremental . use incremental decoding (useful for tests)\n" " -v ....... verbose (e.g. print encoding/decoding times)\n"
" -h ........... this help message\n"
" -v ........... verbose (e.g. print encoding/decoding times)\n"
" -quiet ....... quiet mode, don't print anything\n"
#ifndef WEBP_DLL #ifndef WEBP_DLL
" -noasm ....... disable all assembly optimizations\n" " -noasm ....... disable all assembly optimizations.\n"
#endif #endif
); );
} }
static const char* const kFormatType[] = { static const char* const kStatusMessages[] = {
"unspecified", "lossy", "lossless" "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
"UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
}; };
static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config,
WebPOutputFileFormat format,
int use_external_memory) {
uint8_t* external_buffer = NULL;
WebPDecBuffer* const output_buffer = &config->output;
int w = config->input.width;
int h = config->input.height;
if (config->options.use_scaling) {
w = config->options.scaled_width;
h = config->options.scaled_height;
} else if (config->options.use_cropping) {
w = config->options.crop_width;
h = config->options.crop_height;
}
if (format >= RGB && format <= rgbA_4444) {
const int bpp = (format == RGB || format == BGR) ? 3
: (format == RGBA_4444 || format == rgbA_4444 ||
format == RGB_565) ? 2
: 4;
uint32_t stride = bpp * w + 7; // <- just for exercising
external_buffer = (uint8_t*)malloc(stride * h);
if (external_buffer == NULL) return NULL;
output_buffer->u.RGBA.stride = stride;
output_buffer->u.RGBA.size = stride * h;
output_buffer->u.RGBA.rgba = external_buffer;
} else { // YUV and YUVA
const int has_alpha = WebPIsAlphaMode(output_buffer->colorspace);
uint8_t* tmp;
uint32_t stride = w + 3;
uint32_t uv_stride = (w + 1) / 2 + 13;
uint32_t total_size = stride * h * (has_alpha ? 2 : 1)
+ 2 * uv_stride * (h + 1) / 2;
assert(format >= YUV && format <= YUVA);
external_buffer = (uint8_t*)malloc(total_size);
if (external_buffer == NULL) return NULL;
tmp = external_buffer;
output_buffer->u.YUVA.y = tmp;
output_buffer->u.YUVA.y_stride = stride;
output_buffer->u.YUVA.y_size = stride * h;
tmp += output_buffer->u.YUVA.y_size;
if (has_alpha) {
output_buffer->u.YUVA.a = tmp;
output_buffer->u.YUVA.a_stride = stride;
output_buffer->u.YUVA.a_size = stride * h;
tmp += output_buffer->u.YUVA.a_size;
} else {
output_buffer->u.YUVA.a = NULL;
output_buffer->u.YUVA.a_stride = 0;
}
output_buffer->u.YUVA.u = tmp;
output_buffer->u.YUVA.u_stride = uv_stride;
output_buffer->u.YUVA.u_size = uv_stride * (h + 1) / 2;
tmp += output_buffer->u.YUVA.u_size;
output_buffer->u.YUVA.v = tmp;
output_buffer->u.YUVA.v_stride = uv_stride;
output_buffer->u.YUVA.v_size = uv_stride * (h + 1) / 2;
tmp += output_buffer->u.YUVA.v_size;
assert(tmp <= external_buffer + total_size);
}
output_buffer->is_external_memory = use_external_memory;
return external_buffer;
}
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
int ok = 0;
const char *in_file = NULL; const char *in_file = NULL;
const char *out_file = NULL; const char *out_file = NULL;
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;
int use_external_memory = 0;
const uint8_t* data = NULL;
int incremental = 0;
int c; int c;
INIT_WARGV(argc, argv);
if (!WebPInitDecoderConfig(&config)) { if (!WebPInitDecoderConfig(&config)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-o") && c < argc - 1) { } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = (const char*)GET_WARGV(argv, ++c); out_file = argv[++c];
} else if (!strcmp(argv[c], "-alpha")) { } else if (!strcmp(argv[c], "-alpha")) {
format = ALPHA_PLANE_ONLY; format = ALPHA_PLANE_ONLY;
} else if (!strcmp(argv[c], "-nofancy")) { } else if (!strcmp(argv[c], "-nofancy")) {
@ -216,106 +401,70 @@ int main(int argc, const char *argv[]) {
format = PAM; format = PAM;
} else if (!strcmp(argv[c], "-ppm")) { } else if (!strcmp(argv[c], "-ppm")) {
format = PPM; format = PPM;
} else if (!strcmp(argv[c], "-bmp")) {
format = BMP;
} else if (!strcmp(argv[c], "-tiff")) {
format = TIFF;
} else if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
} else if (!strcmp(argv[c], "-version")) { } else if (!strcmp(argv[c], "-version")) {
const int version = WebPGetDecoderVersion(); const int version = WebPGetDecoderVersion();
printf("%d.%d.%d\n", printf("%d.%d.%d\n",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-pgm")) { } else if (!strcmp(argv[c], "-pgm")) {
format = PGM; format = PGM;
} else if (!strcmp(argv[c], "-yuv")) { } else if (!strcmp(argv[c], "-yuv")) {
format = RAW_YUV; format = YUV;
} else if (!strcmp(argv[c], "-pixel_format") && c < argc - 1) {
const char* const fmt = argv[++c];
if (!strcmp(fmt, "RGB")) format = RGB;
else if (!strcmp(fmt, "RGBA")) format = RGBA;
else if (!strcmp(fmt, "BGR")) format = BGR;
else if (!strcmp(fmt, "BGRA")) format = BGRA;
else if (!strcmp(fmt, "ARGB")) format = ARGB;
else if (!strcmp(fmt, "RGBA_4444")) format = RGBA_4444;
else if (!strcmp(fmt, "RGB_565")) format = RGB_565;
else if (!strcmp(fmt, "rgbA")) format = rgbA;
else if (!strcmp(fmt, "bgrA")) format = bgrA;
else if (!strcmp(fmt, "Argb")) format = Argb;
else if (!strcmp(fmt, "rgbA_4444")) format = rgbA_4444;
else if (!strcmp(fmt, "YUV")) format = YUV;
else if (!strcmp(fmt, "YUVA")) format = YUVA;
else {
fprintf(stderr, "Can't parse pixel_format %s\n", fmt);
parse_error = 1;
}
} else if (!strcmp(argv[c], "-external_memory") && c < argc - 1) {
use_external_memory = ExUtilGetInt(argv[++c], 0, &parse_error);
parse_error |= (use_external_memory > 2 || use_external_memory < 0);
if (parse_error) {
fprintf(stderr, "Can't parse 'external_memory' value %s\n", argv[c]);
}
} else if (!strcmp(argv[c], "-mt")) { } else if (!strcmp(argv[c], "-mt")) {
config.options.use_threads = 1; config.options.use_threads = 1;
} else if (!strcmp(argv[c], "-alpha_dither")) {
config.options.alpha_dithering_strength = 100;
} else if (!strcmp(argv[c], "-nodither")) {
config.options.dithering_strength = 0;
} else if (!strcmp(argv[c], "-dither") && c < argc - 1) {
config.options.dithering_strength =
ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) { } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
config.options.use_cropping = 1; config.options.use_cropping = 1;
config.options.crop_left = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.crop_left = strtol(argv[++c], NULL, 0);
config.options.crop_top = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.crop_top = strtol(argv[++c], NULL, 0);
config.options.crop_width = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.crop_width = strtol(argv[++c], NULL, 0);
config.options.crop_height = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.crop_height = strtol(argv[++c], NULL, 0);
} else if ((!strcmp(argv[c], "-scale") || !strcmp(argv[c], "-resize")) && } else if (!strcmp(argv[c], "-scale") && c < argc - 2) {
c < argc - 2) { // '-scale' is left for compatibility
config.options.use_scaling = 1; config.options.use_scaling = 1;
config.options.scaled_width = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.scaled_width = strtol(argv[++c], NULL, 0);
config.options.scaled_height = ExUtilGetInt(argv[++c], 0, &parse_error); config.options.scaled_height = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-flip")) {
config.options.flip = 1;
} else if (!strcmp(argv[c], "-v")) { } else if (!strcmp(argv[c], "-v")) {
verbose = 1; verbose = 1;
#ifndef WEBP_DLL #ifndef WEBP_DLL
} else if (!strcmp(argv[c], "-noasm")) { } else if (!strcmp(argv[c], "-noasm")) {
VP8GetCPUInfo = NULL; VP8GetCPUInfo = NULL;
#endif #endif
} else if (!strcmp(argv[c], "-incremental")) {
incremental = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c);
break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
fprintf(stderr, "Unknown option '%s'\n", argv[c]); fprintf(stderr, "Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
in_file = (const char*)GET_WARGV(argv, c); in_file = argv[c];
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
} }
} }
if (in_file == NULL) { if (in_file == NULL) {
fprintf(stderr, "missing input file!!\n"); fprintf(stderr, "missing input file!!\n");
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
if (quiet) verbose = 0;
{ {
Stopwatch stop_watch;
VP8StatusCode status = VP8_STATUS_OK; VP8StatusCode status = VP8_STATUS_OK;
int ok;
size_t data_size = 0; size_t data_size = 0;
if (!LoadWebP(in_file, &data, &data_size, bitstream)) { const uint8_t* data = NULL;
FREE_WARGV_AND_RETURN(-1);
if (!ExUtilReadFile(in_file, &data, &data_size)) return -1;
if (verbose)
StopwatchReadAndReset(&stop_watch);
status = WebPGetFeatures(data, data_size, bitstream);
if (status != VP8_STATUS_OK) {
goto end;
}
if (bitstream->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");
} }
switch (format) { switch (format) {
@ -332,89 +481,47 @@ int main(int argc, const char *argv[]) {
case PPM: case PPM:
output_buffer->colorspace = MODE_RGB; // drops alpha for PPM output_buffer->colorspace = MODE_RGB; // drops alpha for PPM
break; break;
case BMP:
output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
break;
case TIFF:
output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
break;
case PGM: case PGM:
case RAW_YUV: case YUV:
output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV; output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV;
break; break;
case ALPHA_PLANE_ONLY: case ALPHA_PLANE_ONLY:
output_buffer->colorspace = MODE_YUVA; output_buffer->colorspace = MODE_YUVA;
break; break;
// forced modes: default:
case RGB: output_buffer->colorspace = MODE_RGB; break; free((void*)data);
case RGBA: output_buffer->colorspace = MODE_RGBA; break; return -1;
case BGR: output_buffer->colorspace = MODE_BGR; break;
case BGRA: output_buffer->colorspace = MODE_BGRA; break;
case ARGB: output_buffer->colorspace = MODE_ARGB; break;
case RGBA_4444: output_buffer->colorspace = MODE_RGBA_4444; break;
case RGB_565: output_buffer->colorspace = MODE_RGB_565; break;
case rgbA: output_buffer->colorspace = MODE_rgbA; break;
case bgrA: output_buffer->colorspace = MODE_bgrA; break;
case Argb: output_buffer->colorspace = MODE_Argb; break;
case rgbA_4444: output_buffer->colorspace = MODE_rgbA_4444; break;
case YUV: output_buffer->colorspace = MODE_YUV; break;
case YUVA: output_buffer->colorspace = MODE_YUVA; break;
default: goto Exit;
} }
status = WebPDecode(data, data_size, &config);
if (use_external_memory > 0 && format >= RGB) {
external_buffer = AllocateExternalBuffer(&config, format,
use_external_memory);
if (external_buffer == NULL) goto Exit;
}
{
Stopwatch stop_watch;
if (verbose) StopwatchReset(&stop_watch);
if (incremental) {
status = DecodeWebPIncremental(data, data_size, &config);
} else {
status = DecodeWebP(data, data_size, &config);
}
if (verbose) { if (verbose) {
const double decode_time = StopwatchReadAndReset(&stop_watch); const double decode_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time); printf("Time to decode picture: %.3fs\n", decode_time);
} }
} end:
free((void*)data);
ok = (status == VP8_STATUS_OK); ok = (status == VP8_STATUS_OK);
if (!ok) { if (!ok) {
PrintWebPError(in_file, status); fprintf(stderr, "Decoding of %s failed.\n", in_file);
goto Exit; fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]);
return -1;
} }
} }
if (out_file != NULL) { if (out_file) {
if (!quiet) { printf("Decoded %s. Dimensions: %d x %d%s. Now saving...\n", in_file,
WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file);
fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n",
output_buffer->width, output_buffer->height, output_buffer->width, output_buffer->height,
bitstream->has_alpha ? " (with alpha)" : "", bitstream->has_alpha ? " (with alpha)" : "");
kFormatType[bitstream->format]); SaveOutput(output_buffer, format, out_file);
}
ok = SaveOutput(output_buffer, format, out_file);
} else { } else {
if (!quiet) { printf("File %s can be decoded (dimensions: %d x %d)%s.\n",
WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file); in_file, output_buffer->width, output_buffer->height,
fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n", bitstream->has_alpha ? " (with alpha)" : "");
output_buffer->width, output_buffer->height, printf("Nothing written; use -o flag to save the result as e.g. PNG.\n");
bitstream->has_alpha ? " (with alpha)" : "",
kFormatType[bitstream->format]);
fprintf(stderr, "Nothing written; "
"use -o flag to save the result as e.g. PNG.\n");
} }
}
Exit:
WebPFreeDecBuffer(output_buffer); WebPFreeDecBuffer(output_buffer);
free((void*)external_buffer);
free((void*)data); return 0;
FREE_WARGV_AND_RETURN(ok ? 0 : -1);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -11,125 +11,69 @@
// //
#include "./example_util.h" #include "./example_util.h"
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "webp/mux_types.h" #if defined(__cplusplus) || defined(c_plusplus)
#include "../imageio/imageio_util.h" extern "C" {
//------------------------------------------------------------------------------
// String parsing
uint32_t ExUtilGetUInt(const char* const v, int base, int* const error) {
char* end = NULL;
const uint32_t n = (v != NULL) ? (uint32_t)strtoul(v, &end, base) : 0u;
if (end == v && error != NULL && !*error) {
*error = 1;
fprintf(stderr, "Error! '%s' is not an integer.\n",
(v != NULL) ? v : "(null)");
}
return n;
}
int ExUtilGetInt(const char* const v, int base, int* const 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) {
char* end = NULL;
const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f;
if (end == v && error != NULL && !*error) {
*error = 1;
fprintf(stderr, "Error! '%s' is not a floating point number.\n",
(v != NULL) ? v : "(null)");
}
return f;
}
//------------------------------------------------------------------------------
static void ResetCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args) {
assert(args != NULL);
args->argc_ = argc;
args->argv_ = argv;
args->own_argv_ = 0;
WebPDataInit(&args->argv_data_);
}
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) {
if (args != NULL) {
if (args->own_argv_) {
free((void*)args->argv_);
WebPDataClear(&args->argv_data_);
}
ResetCommandLineArguments(0, NULL, args);
}
}
#define MAX_ARGC 16384
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args) {
if (args == NULL || argv == NULL) return 0;
ResetCommandLineArguments(argc, argv, args);
if (argc == 1 && argv[0][0] != '-') {
char* cur;
const char sep[] = " \t\r\n\f\v";
#if defined(_WIN32) && defined(_UNICODE)
fprintf(stderr,
"Error: Reading arguments from a file is a feature unavailable "
"with Unicode binaries.\n");
return 0;
#endif #endif
if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) { // -----------------------------------------------------------------------------
return 0; // File I/O
}
args->own_argv_ = 1;
args->argv_ = (const char**)malloc(MAX_ARGC * sizeof(*args->argv_));
if (args->argv_ == NULL) return 0;
argc = 0; int ExUtilReadFile(const char* const file_name,
for (cur = strtok((char*)args->argv_data_.bytes, sep); const uint8_t** data, size_t* data_size) {
cur != NULL; int ok;
cur = strtok(NULL, sep)) { void* file_data;
if (argc == MAX_ARGC) { size_t file_size;
fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC); FILE* in;
if (file_name == NULL || 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; return 0;
} }
assert(strlen(cur) != 0); fseek(in, 0, SEEK_END);
args->argv_[argc++] = cur; file_size = ftell(in);
} fseek(in, 0, SEEK_SET);
args->argc_ = argc; 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; return 1;
} }
//------------------------------------------------------------------------------ int ExUtilWriteFile(const char* const file_name,
const uint8_t* data, size_t data_size) {
int ok;
FILE* out;
int ExUtilReadFileToWebPData(const char* const filename, if (file_name == NULL || data == NULL) {
WebPData* const webp_data) { return 0;
const uint8_t* data;
size_t size;
if (webp_data == NULL) return 0;
if (!ImgIoUtilReadFile(filename, &data, &size)) return 0;
webp_data->bytes = data;
webp_data->size = size;
return 1;
} }
out = 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);
fclose(out);
return ok;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -14,56 +14,22 @@
#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_ #define WEBP_EXAMPLES_EXAMPLE_UTIL_H_
#include "webp/types.h" #include "webp/types.h"
#include "webp/mux_types.h"
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
//------------------------------------------------------------------------------ // Allocates storage for entire file 'file_name' and returns contents and size
// String parsing // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should
// be deleted using free().
int ExUtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size);
// Parses 'v' using strto(ul|l|d)(). If error is non-NULL, '*error' is set to // Write a data segment into a file named 'file_name'. Returns true if ok.
// true on failure while on success it is left unmodified to allow chaining of int ExUtilWriteFile(const char* const file_name,
// calls. An error is only printed on the first occurrence. const uint8_t* data, size_t data_size);
uint32_t ExUtilGetUInt(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);
// This variant of ExUtilGetInt() will parse multiple integers from a #if defined(__cplusplus) || defined(c_plusplus)
// comma-separated list. Up to 'max_output' integers are parsed.
// 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
// webp_data is overwritten. Returns false in case of error.
int ExUtilReadFileToWebPData(const char* const filename,
WebPData* const webp_data);
//------------------------------------------------------------------------------
// Command-line arguments
typedef struct {
int argc_;
const char** argv_;
WebPData argv_data_;
int own_argv_;
} CommandLineArguments;
// Initializes the structure from the command-line parameters. If there is
// only one parameter and it does not start with a '-', then it is assumed to
// be a file name. This file will be read and tokenized into command-line
// arguments. The content of 'args' is overwritten.
// Returns false in case of error (memory allocation failure, non
// existing file, too many arguments, ...).
int ExUtilInitCommandLineArguments(int argc, const char* argv[],
CommandLineArguments* const args);
// Deallocate all memory and reset 'args'.
void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args);
#ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -18,33 +18,140 @@
#include <string.h> #include <string.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "config.h"
#endif
#ifdef WEBP_HAVE_GIF
#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H
#include <unistd.h>
#endif #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 "./unicode.h"
#include "./unicode_gif.h"
#if !defined(STDIN_FILENO) #define GIF_TRANSPARENT_MASK 0x01
#define STDIN_FILENO 0 #define GIF_DISPOSE_MASK 0x07
#endif #define GIF_DISPOSE_SHIFT 2
#define TRANSPARENT_COLOR 0x00ffffff
#define WHITE_COLOR 0xffffffff
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static int transparent_index = GIF_INDEX_INVALID; // Opaque by default. static int transparent_index = -1; // No transparency by default.
static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { static void ClearPicture(WebPPicture* const picture, uint32_t color) {
int x, y;
for (y = 0; y < picture->height; ++y) {
uint32_t* const dst = picture->argb + y * picture->argb_stride;
for (x = 0; x < picture->width; ++x) dst[x] = color;
}
}
static void Remap(const uint8_t* const src, const GifFileType* const gif,
uint32_t* dst, int len) {
int i;
const GifColorType* colors;
const ColorMapObject* const cmap =
gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
if (cmap == NULL) return;
colors = cmap->Colors;
for (i = 0; i < len; ++i) {
const GifColorType c = colors[src[i]];
dst[i] = (src[i] == transparent_index) ? TRANSPARENT_COLOR
: c.Blue | (c.Green << 8) | (c.Red << 16) | (0xff << 24);
}
}
static int ReadSubImage(GifFileType* gif, WebPPicture* pic, WebPPicture* view) {
const GifImageDesc image_desc = gif->Image;
const int offset_x = image_desc.Left;
const int offset_y = image_desc.Top;
const int sub_w = image_desc.Width;
const int sub_h = image_desc.Height;
uint32_t* dst = NULL;
uint8_t* tmp = NULL;
int ok = 0;
// Use a view for the sub-picture:
if (!WebPPictureView(pic, offset_x, offset_y, sub_w, sub_h, view)) {
fprintf(stderr, "Sub-image %dx%d at position %d,%d is invalid!\n",
sub_w, sub_h, offset_x, offset_y);
goto End;
}
dst = view->argb;
tmp = (uint8_t*)malloc(sub_w * sizeof(*tmp));
if (tmp == NULL) goto End;
if (image_desc.Interlace) { // Interlaced image.
// We need 4 passes, with the following offsets and jumps.
const int interlace_offsets[] = { 0, 4, 2, 1 };
const int interlace_jumps[] = { 8, 8, 4, 2 };
int pass;
for (pass = 0; pass < 4; ++pass) {
int y;
for (y = interlace_offsets[pass]; y < sub_h; y += interlace_jumps[pass]) {
if (DGifGetLine(gif, tmp, sub_w) == GIF_ERROR) goto End;
Remap(tmp, gif, dst + y * view->argb_stride, sub_w);
}
}
} else { // Non-interlaced image.
int y;
for (y = 0; y < sub_h; ++y) {
if (DGifGetLine(gif, tmp, sub_w) == GIF_ERROR) goto End;
Remap(tmp, gif, dst + y * view->argb_stride, sub_w);
}
}
// re-align the view with even offset (and adjust dimensions if needed).
WebPPictureView(pic, offset_x & ~1, offset_y & ~1,
sub_w + (offset_x & 1), sub_h + (offset_y & 1), view);
ok = 1;
End:
free(tmp);
return ok;
}
static int GetBackgroundColor(const ColorMapObject* const color_map,
GifWord bgcolor_idx, uint32_t* const bgcolor) {
if (transparent_index != -1 && bgcolor_idx == transparent_index) {
*bgcolor = TRANSPARENT_COLOR; // Special case.
return 1;
} else if (color_map == NULL || color_map->Colors == NULL
|| bgcolor_idx >= color_map->ColorCount) {
return 0; // Invalid color map or index.
} else {
const GifColorType color = color_map->Colors[bgcolor_idx];
*bgcolor = (0xff << 24)
| (color.Red << 16)
| (color.Green << 8)
| (color.Blue << 0);
return 1;
}
}
static void DisplayGifError(const GifFileType* const gif, int gif_error) {
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
// libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \
((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
#if GIFLIB_MAJOR >= 5
// Static string actually, hence the const char* cast.
const char* error_str = (const char*)GifErrorString(
(gif == NULL) ? gif_error : gif->Error);
#else
const char* error_str = (const char*)GifErrorString();
(void)gif;
#endif
if (error_str == NULL) error_str = "Unknown error";
fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str);
#else
(void)gif;
fprintf(stderr, "GIFLib Error %d: ", gif_error);
PrintGifError();
fprintf(stderr, "\n");
#endif
}
static const char* const kErrorMessages[] = {
"WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA",
"WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA"
}; };
@ -54,43 +161,21 @@ static const char* ErrorString(WebPMuxError err) {
return kErrorMessages[-err]; return kErrorMessages[-err];
} }
enum {
METADATA_ICC = (1 << 0),
METADATA_XMP = (1 << 1),
METADATA_ALL = METADATA_ICC | METADATA_XMP
};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void Help(void) { static void Help(void) {
printf("Usage:\n"); printf("Usage:\n");
printf(" gif2webp [options] gif_file -o webp_file\n"); printf(" gif2webp [options] gif_file -o webp_file\n");
printf("Options:\n"); printf("options:\n");
printf(" -h / -help ............. this help\n"); printf(" -h / -help ............ this help\n");
printf(" -lossy ................. encode image using lossy compression\n"); printf(" -lossy ................. Encode image using lossy compression.\n");
printf(" -mixed ................. for each frame in the image, pick lossy\n"
" or lossless compression heuristically\n");
printf(" -q <float> ............. quality factor (0:small..100:big)\n"); printf(" -q <float> ............. quality factor (0:small..100:big)\n");
printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n"); printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
printf(" -min_size .............. minimize output size (default:off)\n"
" lossless compression by default; can be\n"
" combined with -q, -m, -lossy or -mixed\n"
" options\n");
printf(" -kmin <int> ............ min distance between key frames\n");
printf(" -kmax <int> ............ max distance between key frames\n");
printf(" -f <int> ............... filter strength (0=off..100)\n"); printf(" -f <int> ............... filter strength (0=off..100)\n");
printf(" -metadata <string> ..... comma separated list of metadata to\n");
printf(" ");
printf("copy from the input to the output if present\n");
printf(" ");
printf("Valid values: all, none, icc, xmp (default)\n");
printf(" -loop_compatibility .... use compatibility mode for Chrome\n");
printf(" version prior to M62 (inclusive)\n");
printf(" -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");
printf(" -v ..................... verbose\n"); printf(" -v ..................... verbose.\n");
printf(" -quiet ................. don't print anything\n"); printf(" -quiet ................. don't print anything.\n");
printf("\n"); printf("\n");
} }
@ -101,127 +186,52 @@ int main(int argc, const char *argv[]) {
int gif_error = GIF_ERROR; int gif_error = GIF_ERROR;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int ok = 0; int ok = 0;
const W_CHAR *in_file = NULL, *out_file = NULL; const char *in_file = NULL, *out_file = NULL;
FILE* out = NULL;
GifFileType* gif = NULL; GifFileType* gif = NULL;
int frame_duration = 0; WebPPicture picture;
int frame_timestamp = 0; WebPMuxFrameInfo frame;
GIFDisposeMethod orig_dispose = GIF_DISPOSE_NONE; WebPMuxAnimParams anim = { WHITE_COLOR, 0 };
WebPPicture frame; // Frame rectangle only (not disposed). int is_first_frame = 1;
WebPPicture curr_canvas; // Not disposed.
WebPPicture prev_canvas; // Disposed.
WebPAnimEncoder* enc = NULL;
WebPAnimEncoderOptions enc_options;
WebPConfig config;
int frame_number = 0; // Whether we are processing the first frame.
int done; int done;
int c; int c;
int quiet = 0; int quiet = 0;
WebPData webp_data; WebPConfig config;
int keep_metadata = METADATA_XMP; // ICC not output by default.
WebPData icc_data;
int stored_icc = 0; // Whether we have already stored an ICC profile.
WebPData xmp_data;
int stored_xmp = 0; // Whether we have already stored an XMP profile.
int loop_count = 0; // default: infinite
int stored_loop_count = 0; // Whether we have found an explicit loop count.
int loop_compatibility = 0;
WebPMux* mux = NULL; WebPMux* mux = NULL;
WebPData webp_data = { NULL, 0 };
int stored_icc = 0; // Whether we have already stored an ICC profile.
int stored_xmp = 0;
int default_kmin = 1; // Whether to use default kmin value. memset(&frame, 0, sizeof(frame));
int default_kmax = 1; frame.id = WEBP_CHUNK_ANMF;
frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
INIT_WARGV(argc, argv); if (!WebPConfigInit(&config) || !WebPPictureInit(&picture)) {
if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) ||
!WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) ||
!WebPPictureInit(&prev_canvas)) {
fprintf(stderr, "Error! Version mismatch!\n"); fprintf(stderr, "Error! Version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
config.lossless = 1; // Use lossless compression by default. config.lossless = 1; // Use lossless compression by default.
WebPDataInit(&webp_data);
WebPDataInit(&icc_data);
WebPDataInit(&xmp_data);
if (argc == 1) { if (argc == 1) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} }
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-o") && c < argc - 1) { } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
out_file = GET_WARGV(argv, ++c); out_file = argv[++c];
} else if (!strcmp(argv[c], "-lossy")) { } else if (!strcmp(argv[c], "-lossy")) {
config.lossless = 0; config.lossless = 0;
} else if (!strcmp(argv[c], "-mixed")) {
enc_options.allow_mixed = 1;
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 = (float)strtod(argv[++c], NULL);
} else if (!strcmp(argv[c], "-m") && c < argc - 1) { } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
config.method = ExUtilGetInt(argv[++c], 0, &parse_error); config.method = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-min_size")) {
enc_options.minimize_size = 1;
} else if (!strcmp(argv[c], "-kmax") && c < argc - 1) {
enc_options.kmax = ExUtilGetInt(argv[++c], 0, &parse_error);
default_kmax = 0;
} else if (!strcmp(argv[c], "-kmin") && c < argc - 1) {
enc_options.kmin = ExUtilGetInt(argv[++c], 0, &parse_error);
default_kmin = 0;
} else if (!strcmp(argv[c], "-f") && c < argc - 1) { } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); config.filter_strength = strtol(argv[++c], NULL, 0);
} else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
static const struct {
const char* option;
int flag;
} kTokens[] = {
{ "all", METADATA_ALL },
{ "none", 0 },
{ "icc", METADATA_ICC },
{ "xmp", METADATA_XMP },
};
const size_t kNumTokens = sizeof(kTokens) / sizeof(*kTokens);
const char* start = argv[++c];
const char* const end = start + strlen(start);
keep_metadata = 0;
while (start < end) {
size_t i;
const char* token = strchr(start, ',');
if (token == NULL) token = end;
for (i = 0; i < kNumTokens; ++i) {
if ((size_t)(token - start) == strlen(kTokens[i].option) &&
!strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) {
if (kTokens[i].flag != 0) {
keep_metadata |= kTokens[i].flag;
} else {
keep_metadata = 0;
}
break;
}
}
if (i == kNumTokens) {
fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
(int)(token - start), start);
Help();
FREE_WARGV_AND_RETURN(-1);
}
start = token + 1;
}
} else if (!strcmp(argv[c], "-mt")) {
++config.thread_level;
} else if (!strcmp(argv[c], "-version")) { } else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion(); const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion(); const int mux_version = WebPGetMuxVersion();
@ -229,38 +239,19 @@ int main(int argc, const char *argv[]) {
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff, enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff); (mux_version >> 8) & 0xff, mux_version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-quiet")) { } else if (!strcmp(argv[c], "-quiet")) {
quiet = 1; quiet = 1;
enc_options.verbose = 0;
} else if (!strcmp(argv[c], "-v")) { } else if (!strcmp(argv[c], "-v")) {
verbose = 1; verbose = 1;
enc_options.verbose = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) in_file = GET_WARGV(argv, ++c);
break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
in_file = GET_WARGV(argv, c); in_file = argv[c];
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
} }
} }
// Appropriate default kmin, kmax values for lossy and lossless.
if (default_kmin) {
enc_options.kmin = config.lossless ? 9 : 3;
}
if (default_kmax) {
enc_options.kmax = config.lossless ? 17 : 5;
}
if (!WebPValidateConfig(&config)) { if (!WebPValidateConfig(&config)) {
fprintf(stderr, "Error! Invalid configuration.\n"); fprintf(stderr, "Error! Invalid configuration.\n");
goto End; goto End;
@ -273,9 +264,26 @@ int main(int argc, const char *argv[]) {
} }
// Start the decoder object // Start the decoder object
gif = DGifOpenFileUnicode(in_file, &gif_error); #if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
// There was an API change in version 5.0.0.
gif = DGifOpenFileName(in_file, &gif_error);
#else
gif = DGifOpenFileName(in_file);
#endif
if (gif == NULL) goto End; if (gif == NULL) goto End;
// Allocate picture buffer
picture.width = gif->SWidth;
picture.height = gif->SHeight;
picture.use_argb = 1;
if (!WebPPictureAlloc(&picture)) goto End;
mux = WebPMuxNew();
if (mux == NULL) {
fprintf(stderr, "ERROR: could not create a mux object.\n");
goto End;
}
// Loop over GIF images // Loop over GIF images
done = 0; done = 0;
do { do {
@ -284,97 +292,59 @@ int main(int argc, const char *argv[]) {
switch (type) { switch (type) {
case IMAGE_DESC_RECORD_TYPE: { case IMAGE_DESC_RECORD_TYPE: {
GIFFrameRect gif_rect; WebPPicture sub_image;
GifImageDesc* const image_desc = &gif->Image; WebPMemoryWriter memory;
if (frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
ClearPicture(&picture, anim.bgcolor);
}
if (!DGifGetImageDesc(gif)) goto End; if (!DGifGetImageDesc(gif)) goto End;
if (!ReadSubImage(gif, &picture, &sub_image)) goto End;
if (frame_number == 0) { if (!config.lossless) {
if (verbose) { // We need to call BGRA variant because of the way we do Remap(). Note
printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight); // that 'sub_image' will no longer be a view and own some memory.
} WebPPictureImportBGRA(
// Fix some broken GIF global headers that report &sub_image, (uint8_t*)sub_image.argb,
// 0 x 0 screen dimension. sub_image.argb_stride * sizeof(*sub_image.argb));
if (gif->SWidth == 0 || gif->SHeight == 0) { sub_image.use_argb = 0;
image_desc->Left = 0;
image_desc->Top = 0;
gif->SWidth = image_desc->Width;
gif->SHeight = image_desc->Height;
if (gif->SWidth <= 0 || gif->SHeight <= 0) {
goto End;
}
if (verbose) {
printf("Fixed canvas screen dimension to: %d x %d\n",
gif->SWidth, gif->SHeight);
}
}
// Allocate current buffer.
frame.width = gif->SWidth;
frame.height = gif->SHeight;
frame.use_argb = 1;
if (!WebPPictureAlloc(&frame)) goto End;
GIFClearPic(&frame, NULL);
WebPPictureCopy(&frame, &curr_canvas);
WebPPictureCopy(&frame, &prev_canvas);
// Background color.
GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
transparent_index,
&enc_options.anim_params.bgcolor);
// Initialize encoder.
enc = WebPAnimEncoderNew(curr_canvas.width, curr_canvas.height,
&enc_options);
if (enc == NULL) {
fprintf(stderr,
"Error! Could not create encoder object. Possibly due to "
"a memory error.\n");
goto End;
}
}
// Some even more broken GIF can have sub-rect with zero width/height.
if (image_desc->Width == 0 || image_desc->Height == 0) {
image_desc->Width = gif->SWidth;
image_desc->Height = gif->SHeight;
}
if (!GIFReadFrame(gif, transparent_index, &gif_rect, &frame)) {
goto End;
}
// Blend frame rectangle with previous canvas to compose full canvas.
// Note that 'curr_canvas' is same as 'prev_canvas' at this point.
GIFBlendFrames(&frame, &gif_rect, &curr_canvas);
if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) {
fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number,
WebPAnimEncoderGetError(enc));
goto End;
} else { } else {
++frame_number; sub_image.use_argb = 1;
} }
// Update canvases. sub_image.writer = WebPMemoryWrite;
GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas); sub_image.custom_ptr = &memory;
GIFCopyPixels(&curr_canvas, &prev_canvas); WebPMemoryWriterInit(&memory);
if (!WebPEncode(&config, &sub_image)) {
// Force frames with a small or no duration to 100ms to be consistent fprintf(stderr, "Error! Cannot encode picture as WebP\n");
// with web browsers and other transcoding tools. This also avoids fprintf(stderr, "Error code: %d\n", sub_image.error_code);
// incorrect durations between frames when padding frames are goto End;
// discarded.
if (frame_duration <= 10) {
frame_duration = 100;
} }
// Update timestamp (for next frame). // Now we have all the info about the frame, as a Graphic Control
frame_timestamp += frame_duration; // Extension Block always appears before the Image Descriptor Block.
// So add the frame to mux.
// In GIF, graphic control extensions are optional for a frame, so we frame.x_offset = gif->Image.Left & ~1;
// may not get one before reading the next frame. To handle this case, frame.y_offset = gif->Image.Top & ~1;
// we reset frame properties to reasonable defaults for the next frame. frame.bitstream.bytes = memory.mem;
orig_dispose = GIF_DISPOSE_NONE; frame.bitstream.size = memory.size;
frame_duration = 0; err = WebPMuxPushFrame(mux, &frame, 1);
transparent_index = GIF_INDEX_INVALID; if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not add animation frame.\n",
ErrorString(err));
goto End;
}
if (verbose) {
printf("Added frame %dx%d (offset:%d,%d duration:%d) ",
sub_image.width, sub_image.height,
frame.x_offset, frame.y_offset,
frame.duration);
printf("dispose:%d transparent index:%d\n",
frame.dispose_method, transparent_index);
}
WebPDataClear(&frame.bitstream);
WebPPictureFree(&sub_image);
break; break;
} }
case EXTENSION_RECORD_TYPE: { case EXTENSION_RECORD_TYPE: {
@ -383,16 +353,35 @@ int main(int argc, const char *argv[]) {
if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) { if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) {
goto End; goto End;
} }
if (data == NULL) continue;
switch (extension) { switch (extension) {
case COMMENT_EXT_FUNC_CODE: { case COMMENT_EXT_FUNC_CODE: {
break; // Do nothing for now. break; // Do nothing for now.
} }
case GRAPHICS_EXT_FUNC_CODE: { case GRAPHICS_EXT_FUNC_CODE: {
if (!GIFReadGraphicsExtension(data, &frame_duration, &orig_dispose, const int flags = data[1];
&transparent_index)) { const int dispose = (flags >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
goto End; const int delay = data[2] | (data[3] << 8); // In 10 ms units.
if (data[0] != 4) goto End;
frame.duration = delay * 10; // Duration is in 1 ms units for WebP.
if (dispose == 3) {
fprintf(stderr, "WARNING: GIF_DISPOSE_RESTORE not supported.");
// failsafe. TODO(urvang): emulate the correct behaviour by
// recoding the whole frame.
frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
} else {
frame.dispose_method =
(dispose == 2) ? WEBP_MUX_DISPOSE_BACKGROUND
: WEBP_MUX_DISPOSE_NONE;
}
transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1;
if (is_first_frame) {
if (!GetBackgroundColor(gif->SColorMap, gif->SBackGroundColor,
&anim.bgcolor)) {
fprintf(stderr, "GIF decode warning: invalid background color "
"index. Assuming white background.\n");
}
ClearPicture(&picture, anim.bgcolor);
is_first_frame = 0;
} }
break; break;
} }
@ -401,27 +390,69 @@ int main(int argc, const char *argv[]) {
} }
case APPLICATION_EXT_FUNC_CODE: { case APPLICATION_EXT_FUNC_CODE: {
if (data[0] != 11) break; // Chunk is too short if (data[0] != 11) break; // Chunk is too short
if (!memcmp(data + 1, "NETSCAPE2.0", 11) || if (!memcmp(data + 1, "NETSCAPE2.0", 11)) {
!memcmp(data + 1, "ANIMEXTS1.0", 11)) { // Recognize and parse Netscape2.0 NAB extension for loop count.
if (!GIFReadLoopCount(gif, &data, &loop_count)) { if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) goto End;
if (data == NULL) goto End; // Loop count sub-block missing.
if (data[0] != 3 && data[1] != 1) break; // wrong size/marker
anim.loop_count = data[2] | (data[3] << 8);
if (verbose) printf("Loop count: %d\n", anim.loop_count);
} else { // An extension containing metadata.
// We only store the first encountered chunk of each type.
const int is_xmp =
!stored_xmp && !memcmp(data + 1, "XMP DataXMP", 11);
const int is_icc =
!stored_icc && !memcmp(data + 1, "ICCRGBG1012", 11);
if (is_xmp || is_icc) {
const char* const fourccs[2] = { "XMP " , "ICCP" };
const char* const features[2] = { "XMP" , "ICC" };
WebPData metadata = { NULL, 0 };
// Construct metadata from sub-blocks.
// Usual case (including ICC profile): In each sub-block, the
// first byte specifies its size in bytes (0 to 255) and the
// rest of the bytes contain the data.
// Special case for XMP data: In each sub-block, the first byte
// is also part of the XMP payload. XMP in GIF also has a 257
// byte padding data. See the XMP specification for details.
while (1) {
WebPData prev_metadata = metadata;
WebPData subblock;
if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) {
WebPDataClear(&metadata);
goto End; goto End;
} }
if (verbose) { if (data == NULL) break; // Finished.
fprintf(stderr, "Loop count: %d\n", loop_count); subblock.size = is_xmp ? data[0] + 1 : data[0];
assert(subblock.size > 0);
subblock.bytes = is_xmp ? data : data + 1;
metadata.bytes =
(uint8_t*)realloc((void*)metadata.bytes,
prev_metadata.size + subblock.size);
if (metadata.bytes == NULL) {
WebPDataClear(&prev_metadata);
goto End;
} }
stored_loop_count = loop_compatibility ? (loop_count != 0) : 1; metadata.size += subblock.size;
} else { // An extension containing metadata. memcpy((void*)(metadata.bytes + prev_metadata.size),
// We only store the first encountered chunk of each type, and subblock.bytes, subblock.size);
// only if requested by the user. }
const int is_xmp = (keep_metadata & METADATA_XMP) && if (is_xmp) {
!stored_xmp && // XMP padding data is 0x01, 0xff, 0xfe ... 0x01, 0x00.
!memcmp(data + 1, "XMP DataXMP", 11); const size_t xmp_pading_size = 257;
const int is_icc = (keep_metadata & METADATA_ICC) && if (metadata.size > xmp_pading_size) {
!stored_icc && metadata.size -= xmp_pading_size;
!memcmp(data + 1, "ICCRGBG1012", 11); }
if (is_xmp || is_icc) { }
if (!GIFReadMetadata(gif, &data,
is_xmp ? &xmp_data : &icc_data)) { // Add metadata chunk.
err = WebPMuxSetChunk(mux, fourccs[is_icc], &metadata, 1);
if (verbose) {
printf("%s size: %d\n", features[is_icc], (int)metadata.size);
}
WebPDataClear(&metadata);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not set %s chunk.\n",
ErrorString(err), features[is_icc]);
goto End; goto End;
} }
if (is_icc) { if (is_icc) {
@ -455,111 +486,30 @@ int main(int argc, const char *argv[]) {
} }
} while (!done); } while (!done);
// Last NULL frame. // Finish muxing
if (!WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL)) { err = WebPMuxSetAnimationParams(mux, &anim);
fprintf(stderr, "Error flushing WebP muxer.\n");
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
}
if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
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) {
// Re-mux to add loop count and/or metadata as needed.
mux = WebPMuxCreate(&webp_data, 1);
if (mux == NULL) {
fprintf(stderr, "ERROR: Could not re-mux to add loop count/metadata.\n");
goto End;
}
WebPDataClear(&webp_data);
if (stored_loop_count) { // Update loop count.
WebPMuxAnimParams new_params;
err = WebPMuxGetAnimationParams(mux, &new_params);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not fetch loop count.\n", fprintf(stderr, "ERROR (%s): Could not set animation parameters.\n",
ErrorString(err)); ErrorString(err));
goto End; goto End;
} }
new_params.loop_count = loop_count;
err = WebPMuxSetAnimationParams(mux, &new_params);
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not update loop count.\n",
ErrorString(err));
goto End;
}
}
if (stored_icc) { // Add ICCP chunk.
err = WebPMuxSetChunk(mux, "ICCP", &icc_data, 1);
if (verbose) {
fprintf(stderr, "ICC size: %d\n", (int)icc_data.size);
}
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not set ICC chunk.\n",
ErrorString(err));
goto End;
}
}
if (stored_xmp) { // Add XMP chunk.
err = WebPMuxSetChunk(mux, "XMP ", &xmp_data, 1);
if (verbose) {
fprintf(stderr, "XMP size: %d\n", (int)xmp_data.size);
}
if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not set XMP chunk.\n",
ErrorString(err));
goto End;
}
}
err = WebPMuxAssemble(mux, &webp_data); err = WebPMuxAssemble(mux, &webp_data);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
fprintf(stderr, "ERROR (%s): Could not assemble when re-muxing to add " fprintf(stderr, "ERROR (%s) assembling the WebP file.\n", ErrorString(err));
"loop count/metadata.\n", ErrorString(err));
goto End; goto End;
} }
}
if (out_file != NULL) { if (out_file != NULL) {
if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes, if (!ExUtilWriteFile(out_file, webp_data.bytes, webp_data.size)) {
webp_data.size)) { fprintf(stderr, "Error writing output file: %s\n", out_file);
WFPRINTF(stderr, "Error writing output file: %s\n", out_file);
goto End; goto End;
} }
if (!quiet) { if (!quiet) {
if (!WSTRCMP(out_file, "-")) { printf("Saved output file: %s\n", out_file);
fprintf(stderr, "Saved %d bytes to STDIO\n",
(int)webp_data.size);
} else {
WFPRINTF(stderr, "Saved output file (%d bytes): %s\n",
(int)webp_data.size, out_file);
}
} }
} else { } else {
if (!quiet) { if (!quiet) {
fprintf(stderr, "Nothing written; use -o flag to save the result " printf("Nothing written; use -o flag to save the result.\n");
"(%d bytes).\n", (int)webp_data.size);
} }
} }
@ -568,37 +518,19 @@ int main(int argc, const char *argv[]) {
gif_error = GIF_OK; gif_error = GIF_OK;
End: End:
WebPDataClear(&icc_data);
WebPDataClear(&xmp_data);
WebPMuxDelete(mux);
WebPDataClear(&webp_data); WebPDataClear(&webp_data);
WebPPictureFree(&frame); WebPMuxDelete(mux);
WebPPictureFree(&curr_canvas); WebPPictureFree(&picture);
WebPPictureFree(&prev_canvas); if (out != NULL && out_file != NULL) fclose(out);
WebPAnimEncoderDelete(enc);
if (gif_error != GIF_OK) { if (gif_error != GIF_OK) {
GIFDisplayError(gif, gif_error); DisplayGifError(gif, gif_error);
} }
if (gif != NULL) { if (gif != NULL) {
#if LOCAL_GIF_PREREQ(5,1)
DGifCloseFile(gif, &gif_error);
#else
DGifCloseFile(gif); DGifCloseFile(gif);
#endif
} }
FREE_WARGV_AND_RETURN(!ok); return !ok;
} }
#else // !WEBP_HAVE_GIF
int main(int argc, const char *argv[]) {
fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
}
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -1,416 +0,0 @@
// Copyright 2012 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.
// -----------------------------------------------------------------------------
//
// GIF decode.
#include "./gifdec.h"
#include <stdio.h>
#ifdef WEBP_HAVE_GIF
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h"
#include "webp/mux_types.h"
#define GIF_TRANSPARENT_COLOR 0x00000000u
#define GIF_WHITE_COLOR 0xffffffffu
#define GIF_TRANSPARENT_MASK 0x01
#define GIF_DISPOSE_MASK 0x07
#define GIF_DISPOSE_SHIFT 2
// from utils/utils.h
#ifdef __cplusplus
extern "C" {
#endif
extern void WebPCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride,
int width, int height);
extern void WebPCopyPixels(const WebPPicture* const src,
WebPPicture* const dst);
#ifdef __cplusplus
}
#endif
void GIFGetBackgroundColor(const ColorMapObject* const color_map,
int bgcolor_index, int transparent_index,
uint32_t* const bgcolor) {
if (transparent_index != GIF_INDEX_INVALID &&
bgcolor_index == transparent_index) {
*bgcolor = GIF_TRANSPARENT_COLOR; // Special case.
} else if (color_map == NULL || color_map->Colors == NULL
|| bgcolor_index >= color_map->ColorCount) {
*bgcolor = GIF_WHITE_COLOR;
fprintf(stderr,
"GIF decode warning: invalid background color index. Assuming "
"white background.\n");
} else {
const GifColorType color = color_map->Colors[bgcolor_index];
*bgcolor = (0xffu << 24)
| (color.Red << 16)
| (color.Green << 8)
| (color.Blue << 0);
}
}
int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration,
GIFDisposeMethod* const dispose,
int* const transparent_index) {
const int flags = buf[1];
const int dispose_raw = (flags >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
const int duration_raw = buf[2] | (buf[3] << 8); // In 10 ms units.
if (buf[0] != 4) return 0;
*duration = duration_raw * 10; // Duration is in 1 ms units.
switch (dispose_raw) {
case 3:
*dispose = GIF_DISPOSE_RESTORE_PREVIOUS;
break;
case 2:
*dispose = GIF_DISPOSE_BACKGROUND;
break;
case 1:
case 0:
default:
*dispose = GIF_DISPOSE_NONE;
break;
}
*transparent_index =
(flags & GIF_TRANSPARENT_MASK) ? buf[4] : GIF_INDEX_INVALID;
return 1;
}
static int Remap(const GifFileType* const gif, const uint8_t* const src,
int len, int transparent_index, uint32_t* dst) {
int i;
const GifColorType* colors;
const ColorMapObject* const cmap =
gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
if (cmap == NULL) return 1;
if (cmap->Colors == NULL || cmap->ColorCount <= 0) return 0;
colors = cmap->Colors;
for (i = 0; i < len; ++i) {
if (src[i] == transparent_index) {
dst[i] = GIF_TRANSPARENT_COLOR;
} else if (src[i] < cmap->ColorCount) {
const GifColorType c = colors[src[i]];
dst[i] = c.Blue | (c.Green << 8) | (c.Red << 16) | (0xffu << 24);
} else {
return 0;
}
}
return 1;
}
int GIFReadFrame(GifFileType* const gif, int transparent_index,
GIFFrameRect* const gif_rect, WebPPicture* const picture) {
WebPPicture sub_image;
const GifImageDesc* const image_desc = &gif->Image;
uint32_t* dst = NULL;
uint8_t* tmp = NULL;
const GIFFrameRect rect = {
image_desc->Left, image_desc->Top, image_desc->Width, image_desc->Height
};
const uint64_t memory_needed = 4 * rect.width * (uint64_t)rect.height;
int ok = 0;
*gif_rect = rect;
if (memory_needed != (size_t)memory_needed || memory_needed > (4ULL << 32)) {
fprintf(stderr, "Image is too large (%d x %d).", rect.width, rect.height);
return 0;
}
// Use a view for the sub-picture:
if (!WebPPictureView(picture, rect.x_offset, rect.y_offset,
rect.width, rect.height, &sub_image)) {
fprintf(stderr, "Sub-image %dx%d at position %d,%d is invalid!\n",
rect.width, rect.height, rect.x_offset, rect.y_offset);
return 0;
}
dst = sub_image.argb;
tmp = (uint8_t*)malloc(rect.width * sizeof(*tmp));
if (tmp == NULL) goto End;
if (image_desc->Interlace) { // Interlaced image.
// We need 4 passes, with the following offsets and jumps.
const int interlace_offsets[] = { 0, 4, 2, 1 };
const int interlace_jumps[] = { 8, 8, 4, 2 };
int pass;
for (pass = 0; pass < 4; ++pass) {
const size_t stride = (size_t)sub_image.argb_stride;
int y = interlace_offsets[pass];
uint32_t* row = dst + y * stride;
const size_t jump = interlace_jumps[pass] * stride;
for (; y < rect.height; y += interlace_jumps[pass], row += jump) {
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
if (!Remap(gif, tmp, rect.width, transparent_index, row)) goto End;
}
}
} else { // Non-interlaced image.
int y;
uint32_t* ptr = dst;
for (y = 0; y < rect.height; ++y, ptr += sub_image.argb_stride) {
if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End;
if (!Remap(gif, tmp, rect.width, transparent_index, ptr)) goto End;
}
}
ok = 1;
End:
if (!ok) picture->error_code = sub_image.error_code;
WebPPictureFree(&sub_image);
free(tmp);
return ok;
}
int GIFReadLoopCount(GifFileType* const gif, GifByteType** const buf,
int* const loop_count) {
assert(!memcmp(*buf + 1, "NETSCAPE2.0", 11) ||
!memcmp(*buf + 1, "ANIMEXTS1.0", 11));
if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) {
return 0;
}
if (*buf == NULL) {
return 0; // Loop count sub-block missing.
}
if ((*buf)[0] < 3 || (*buf)[1] != 1) {
return 0; // wrong size/marker
}
*loop_count = (*buf)[2] | ((*buf)[3] << 8);
return 1;
}
int GIFReadMetadata(GifFileType* const gif, GifByteType** const buf,
WebPData* const metadata) {
const int is_xmp = !memcmp(*buf + 1, "XMP DataXMP", 11);
const int is_icc = !memcmp(*buf + 1, "ICCRGBG1012", 11);
assert(is_xmp || is_icc);
(void)is_icc; // silence unused warning.
// Construct metadata from sub-blocks.
// Usual case (including ICC profile): In each sub-block, the
// first byte specifies its size in bytes (0 to 255) and the
// rest of the bytes contain the data.
// Special case for XMP data: In each sub-block, the first byte
// is also part of the XMP payload. XMP in GIF also has a 257
// byte padding data. See the XMP specification for details.
while (1) {
WebPData subblock;
const uint8_t* tmp;
if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) {
return 0;
}
if (*buf == NULL) break; // Finished.
subblock.size = is_xmp ? (*buf)[0] + 1 : (*buf)[0];
assert(subblock.size > 0);
subblock.bytes = is_xmp ? *buf : *buf + 1;
// Note: We store returned value in 'tmp' first, to avoid
// leaking old memory in metadata->bytes on error.
tmp = (uint8_t*)realloc((void*)metadata->bytes,
metadata->size + subblock.size);
if (tmp == NULL) {
return 0;
}
memcpy((void*)(tmp + metadata->size),
subblock.bytes, subblock.size);
metadata->bytes = tmp;
metadata->size += subblock.size;
}
if (is_xmp) {
// XMP padding data is 0x01, 0xff, 0xfe ... 0x01, 0x00.
const size_t xmp_pading_size = 257;
if (metadata->size > xmp_pading_size) {
metadata->size -= xmp_pading_size;
}
}
return 1;
}
static void ClearRectangle(WebPPicture* const picture,
int left, int top, int width, int height) {
int i, j;
const size_t stride = picture->argb_stride;
uint32_t* dst = picture->argb + top * stride + left;
for (j = 0; j < height; ++j, dst += stride) {
for (i = 0; i < width; ++i) dst[i] = GIF_TRANSPARENT_COLOR;
}
}
void GIFClearPic(WebPPicture* const pic, const GIFFrameRect* const rect) {
if (rect != NULL) {
ClearRectangle(pic, rect->x_offset, rect->y_offset,
rect->width, rect->height);
} else {
ClearRectangle(pic, 0, 0, pic->width, pic->height);
}
}
void GIFCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
WebPCopyPixels(src, dst);
}
void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect,
const WebPPicture* const prev_canvas,
WebPPicture* const curr_canvas) {
assert(rect != NULL);
if (dispose == GIF_DISPOSE_BACKGROUND) {
GIFClearPic(curr_canvas, rect);
} else if (dispose == GIF_DISPOSE_RESTORE_PREVIOUS) {
const size_t src_stride = prev_canvas->argb_stride;
const uint32_t* const src = prev_canvas->argb + rect->x_offset
+ rect->y_offset * src_stride;
const size_t dst_stride = curr_canvas->argb_stride;
uint32_t* const dst = curr_canvas->argb + rect->x_offset
+ rect->y_offset * dst_stride;
assert(prev_canvas != NULL);
WebPCopyPlane((uint8_t*)src, (int)(4 * src_stride),
(uint8_t*)dst, (int)(4 * dst_stride),
4 * rect->width, rect->height);
}
}
void GIFBlendFrames(const WebPPicture* const src,
const GIFFrameRect* const rect, WebPPicture* const dst) {
int i, j;
const size_t src_stride = src->argb_stride;
const size_t dst_stride = dst->argb_stride;
assert(src->width == dst->width && src->height == dst->height);
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) {
const uint32_t src_pixel = src->argb[j * src_stride + i];
const int src_alpha = src_pixel >> 24;
if (src_alpha != 0) {
dst->argb[j * dst_stride + i] = src_pixel;
}
}
}
}
void GIFDisplayError(const GifFileType* const gif, int gif_error) {
// libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
#if LOCAL_GIF_PREREQ(4,2)
#if LOCAL_GIF_PREREQ(5,0)
// Static string actually, hence the const char* cast.
const char* error_str = (const char*)GifErrorString(
(gif == NULL) ? gif_error : gif->Error);
#else
const char* error_str = (const char*)GifErrorString();
(void)gif;
#endif
if (error_str == NULL) error_str = "Unknown error";
fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str);
#else
(void)gif;
fprintf(stderr, "GIFLib Error %d: ", gif_error);
PrintGifError();
fprintf(stderr, "\n");
#endif
}
#else // !WEBP_HAVE_GIF
static void ErrorGIFNotAvailable() {
fprintf(stderr, "GIF support not compiled. Please install the libgif-dev "
"package before building.\n");
}
void GIFGetBackgroundColor(const struct ColorMapObject* const color_map,
int bgcolor_index, int transparent_index,
uint32_t* const bgcolor) {
(void)color_map;
(void)bgcolor_index;
(void)transparent_index;
(void)bgcolor;
ErrorGIFNotAvailable();
}
int GIFReadGraphicsExtension(const GifByteType* const data, int* const duration,
GIFDisposeMethod* const dispose,
int* const transparent_index) {
(void)data;
(void)duration;
(void)dispose;
(void)transparent_index;
ErrorGIFNotAvailable();
return 0;
}
int GIFReadFrame(struct GifFileType* const gif, int transparent_index,
GIFFrameRect* const gif_rect,
struct WebPPicture* const picture) {
(void)gif;
(void)transparent_index;
(void)gif_rect;
(void)picture;
ErrorGIFNotAvailable();
return 0;
}
int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf,
int* const loop_count) {
(void)gif;
(void)buf;
(void)loop_count;
ErrorGIFNotAvailable();
return 0;
}
int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf,
struct WebPData* const metadata) {
(void)gif;
(void)buf;
(void)metadata;
ErrorGIFNotAvailable();
return 0;
}
void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect,
const struct WebPPicture* const prev_canvas,
struct WebPPicture* const curr_canvas) {
(void)dispose;
(void)rect;
(void)prev_canvas;
(void)curr_canvas;
ErrorGIFNotAvailable();
}
void GIFBlendFrames(const struct WebPPicture* const src,
const GIFFrameRect* const rect,
struct WebPPicture* const dst) {
(void)src;
(void)rect;
(void)dst;
ErrorGIFNotAvailable();
}
void GIFDisplayError(const struct GifFileType* const gif, int gif_error) {
(void)gif;
(void)gif_error;
ErrorGIFNotAvailable();
}
void GIFClearPic(struct WebPPicture* const pic,
const GIFFrameRect* const rect) {
(void)pic;
(void)rect;
ErrorGIFNotAvailable();
}
void GIFCopyPixels(const struct WebPPicture* const src,
struct WebPPicture* const dst) {
(void)src;
(void)dst;
ErrorGIFNotAvailable();
}
#endif // WEBP_HAVE_GIF
// -----------------------------------------------------------------------------

View File

@ -1,116 +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.
// -----------------------------------------------------------------------------
//
// GIF decode.
#ifndef WEBP_EXAMPLES_GIFDEC_H_
#define WEBP_EXAMPLES_GIFDEC_H_
#include <stdio.h>
#include "webp/types.h"
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#ifdef WEBP_HAVE_GIF
#include <gif_lib.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR)
# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR)
# define LOCAL_GIF_PREREQ(maj, min) \
(LOCAL_GIF_VERSION >= (((maj) << 8) | (min)))
#else
# define LOCAL_GIF_VERSION 0
# define LOCAL_GIF_PREREQ(maj, min) 0
#endif
#define GIF_INDEX_INVALID (-1)
typedef enum GIFDisposeMethod {
GIF_DISPOSE_NONE,
GIF_DISPOSE_BACKGROUND,
GIF_DISPOSE_RESTORE_PREVIOUS
} GIFDisposeMethod;
typedef struct {
int x_offset, y_offset, width, height;
} GIFFrameRect;
struct WebPData;
struct WebPPicture;
#ifndef WEBP_HAVE_GIF
struct ColorMapObject;
struct GifFileType;
typedef unsigned char GifByteType;
#endif
// Given the index of background color and transparent color, returns the
// corresponding background color (in BGRA format) in 'bgcolor'.
void GIFGetBackgroundColor(const struct ColorMapObject* const color_map,
int bgcolor_index, int transparent_index,
uint32_t* const bgcolor);
// Parses the given graphics extension data to get frame duration (in 1ms
// units), dispose method and transparent color index.
// Returns true on success.
int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration,
GIFDisposeMethod* const dispose,
int* const transparent_index);
// Reads the next GIF frame from 'gif' into 'picture'. Also, returns the GIF
// frame dimensions and offsets in 'rect'.
// Returns true on success.
int GIFReadFrame(struct GifFileType* const gif, int transparent_index,
GIFFrameRect* const gif_rect,
struct WebPPicture* const picture);
// Parses loop count from the given Netscape extension data.
int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf,
int* const loop_count);
// Parses the given ICC or XMP extension data and stores it into 'metadata'.
// Returns true on success.
int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf,
struct WebPData* const metadata);
// Dispose the pixels within 'rect' of 'curr_canvas' based on 'dispose' method
// and 'prev_canvas'.
void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect,
const struct WebPPicture* const prev_canvas,
struct WebPPicture* const curr_canvas);
// Given 'src' picture and its frame rectangle 'rect', blend it into 'dst'.
void GIFBlendFrames(const struct WebPPicture* const src,
const GIFFrameRect* const rect,
struct WebPPicture* const dst);
// Prints an error string based on 'gif_error'.
void GIFDisplayError(const struct GifFileType* const gif, int gif_error);
// In the given 'pic', clear the pixels in 'rect' to transparent color.
void GIFClearPic(struct WebPPicture* const pic, const GIFFrameRect* const rect);
// Copy pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are assumed
// to be already allocated.
void GIFCopyPixels(const struct WebPPicture* const src,
struct WebPPicture* const dst);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_EXAMPLES_GIFDEC_H_

View File

@ -1,324 +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 "./unicode.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");
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 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;
INIT_WARGV(argc, argv);
ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args);
if (!ok) FREE_WARGV_AND_RETURN(1);
argc = cmd_args.argc_;
argv = cmd_args.argv_;
WebPDataInit(&webp_data);
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 = (const char*)GET_WARGV_SHIFTED(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((const char*)GET_WARGV_SHIFTED(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) {
WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n",
pic_num, timestamp_ms, GET_WARGV_SHIFTED(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) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)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);
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
}

View File

@ -12,20 +12,18 @@
#include "./jpegdec.h" #include "./jpegdec.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "config.h"
#endif #endif
#include <stdio.h> #include <stdio.h>
#ifdef WEBP_HAVE_JPEG #ifdef WEBP_HAVE_JPEG
#include <jpeglib.h> #include <jpeglib.h>
#include <jerror.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h"
#include "./metadata.h" #include "./metadata.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -206,94 +204,38 @@ struct my_error_mgr {
static void my_error_exit(j_common_ptr dinfo) { static void my_error_exit(j_common_ptr dinfo) {
struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err; struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
fprintf(stderr, "libjpeg error: ");
dinfo->err->output_message(dinfo); dinfo->err->output_message(dinfo);
longjmp(myerr->setjmp_buffer, 1); longjmp(myerr->setjmp_buffer, 1);
} }
typedef struct { int ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) {
struct jpeg_source_mgr pub; int ok = 0;
const uint8_t* data; int stride, width, height;
size_t data_size; struct jpeg_decompress_struct dinfo;
} JPEGReadContext;
static void ContextInit(j_decompress_ptr cinfo) {
JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
ctx->pub.next_input_byte = ctx->data;
ctx->pub.bytes_in_buffer = ctx->data_size;
}
static boolean ContextFill(j_decompress_ptr cinfo) {
// we shouldn't get here.
ERREXIT(cinfo, JERR_FILE_READ);
return FALSE;
}
static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
size_t jump = (size_t)jump_size;
if (jump > ctx->pub.bytes_in_buffer) { // Don't overflow the buffer.
jump = ctx->pub.bytes_in_buffer;
}
ctx->pub.bytes_in_buffer -= jump;
ctx->pub.next_input_byte += jump;
}
static void ContextTerm(j_decompress_ptr cinfo) {
(void)cinfo;
}
static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo,
JPEGReadContext* const ctx) {
cinfo->src = (struct jpeg_source_mgr*)ctx;
ctx->pub.init_source = ContextInit;
ctx->pub.fill_input_buffer = ContextFill;
ctx->pub.skip_input_data = ContextSkip;
ctx->pub.resync_to_restart = jpeg_resync_to_restart;
ctx->pub.term_source = ContextTerm;
ctx->pub.bytes_in_buffer = 0;
ctx->pub.next_input_byte = NULL;
}
int ReadJPEG(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
volatile int ok = 0;
int width, height;
int64_t stride;
volatile struct jpeg_decompress_struct dinfo;
struct my_error_mgr jerr; struct my_error_mgr jerr;
uint8_t* volatile rgb = NULL; uint8_t* rgb = NULL;
JSAMPROW buffer[1]; JSAMPROW buffer[1];
JPEGReadContext ctx;
if (data == NULL || data_size == 0 || pic == NULL) return 0;
(void)keep_alpha;
memset(&ctx, 0, sizeof(ctx));
ctx.data = data;
ctx.data_size = data_size;
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
dinfo.err = jpeg_std_error(&jerr.pub); dinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit; jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) { if (setjmp(jerr.setjmp_buffer)) {
Error: Error:
MetadataFree(metadata); MetadataFree(metadata);
jpeg_destroy_decompress((j_decompress_ptr)&dinfo); jpeg_destroy_decompress(&dinfo);
goto End; goto End;
} }
jpeg_create_decompress((j_decompress_ptr)&dinfo); jpeg_create_decompress(&dinfo);
ContextSetup(&dinfo, &ctx); jpeg_stdio_src(&dinfo, in_file);
if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo); if (metadata != NULL) SaveMetadataMarkers(&dinfo);
jpeg_read_header((j_decompress_ptr)&dinfo, TRUE); jpeg_read_header(&dinfo, TRUE);
dinfo.out_color_space = JCS_RGB; dinfo.out_color_space = JCS_RGB;
dinfo.dct_method = JDCT_IFAST;
dinfo.do_fancy_upsampling = TRUE; dinfo.do_fancy_upsampling = TRUE;
jpeg_start_decompress((j_decompress_ptr)&dinfo); jpeg_start_decompress(&dinfo);
if (dinfo.output_components != 3) { if (dinfo.output_components != 3) {
goto Error; goto Error;
@ -301,41 +243,36 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
width = dinfo.output_width; width = dinfo.output_width;
height = dinfo.output_height; height = dinfo.output_height;
stride = (int64_t)dinfo.output_width * dinfo.output_components * sizeof(*rgb); stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
if (stride != (int)stride || rgb = (uint8_t*)malloc(stride * height);
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error;
}
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(&dinfo, buffer, 1) != 1) {
goto Error; goto End;
} }
buffer[0] += stride; buffer[0] += stride;
} }
if (metadata != NULL) { if (metadata != NULL) {
ok = ExtractMetadataFromJPEG((j_decompress_ptr)&dinfo, metadata); ok = ExtractMetadataFromJPEG(&dinfo, metadata);
if (!ok) { if (!ok) {
fprintf(stderr, "Error extracting JPEG metadata!\n"); fprintf(stderr, "Error extracting JPEG metadata!\n");
goto Error; goto Error;
} }
} }
jpeg_finish_decompress((j_decompress_ptr)&dinfo); jpeg_finish_decompress(&dinfo);
jpeg_destroy_decompress((j_decompress_ptr)&dinfo); jpeg_destroy_decompress(&dinfo);
// WebP conversion. // WebP conversion.
pic->width = width; pic->width = width;
pic->height = height; pic->height = height;
ok = WebPPictureImportRGB(pic, rgb, (int)stride); ok = WebPPictureImportRGB(pic, rgb, stride);
if (!ok) goto Error; if (!ok) goto Error;
End: End:
@ -343,13 +280,10 @@ int ReadJPEG(const uint8_t* const data, size_t data_size,
return ok; return ok;
} }
#else // !WEBP_HAVE_JPEG #else // !WEBP_HAVE_JPEG
int ReadJPEG(const uint8_t* const data, size_t data_size, int ReadJPEG(FILE* in_file, struct WebPPicture* const pic,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) { struct Metadata* const metadata) {
(void)data; (void)in_file;
(void)data_size;
(void)pic; (void)pic;
(void)keep_alpha;
(void)metadata; (void)metadata;
fprintf(stderr, "JPEG support not compiled. Please install the libjpeg " fprintf(stderr, "JPEG support not compiled. Please install the libjpeg "
"development package before building.\n"); "development package before building.\n");

View File

@ -9,29 +9,27 @@
// //
// 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 #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
struct Metadata; struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads a JPEG from 'data', returning the decoded output in 'pic'. // Reads a JPEG from 'in_file', returning the decoded output in 'pic'.
// The output is RGB or YUV depending on pic->use_argb value. // The output is RGB.
// Returns true on success. // Returns true on success.
// 'keep_alpha' has no effect, but is kept for coherence with other signatures int ReadJPEG(FILE* in_file, struct WebPPicture* const pic,
// for image readers.
int ReadJPEG(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata); struct Metadata* const metadata);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_JPEGDEC_H_ #endif // WEBP_EXAMPLES_JPEGDEC_H_

View File

@ -10,12 +10,12 @@
// 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"
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
@ -40,8 +40,8 @@ void MetadataFree(Metadata* const metadata);
int MetadataCopy(const char* metadata, size_t metadata_len, int MetadataCopy(const char* metadata, size_t metadata_len,
MetadataPayload* const payload); MetadataPayload* const payload);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_METADATA_H_ #endif // WEBP_EXAMPLES_METADATA_H_

View File

@ -12,51 +12,24 @@
#include "./pngdec.h" #include "./pngdec.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "config.h"
#endif #endif
#include <stdio.h> #include <stdio.h>
#ifdef WEBP_HAVE_PNG #ifdef WEBP_HAVE_PNG
#ifndef PNG_USER_MEM_SUPPORTED
#define PNG_USER_MEM_SUPPORTED // for png_create_read_struct_2
#endif
#include <png.h> #include <png.h>
#include <setjmp.h> // note: this must be included *after* png.h #include <setjmp.h> // note: this must be included *after* png.h
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./imageio_util.h"
#include "./metadata.h" #include "./metadata.h"
#define LOCAL_PNG_VERSION ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR) static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
#define LOCAL_PNG_PREREQ(maj, min) \ (void)dummy; // remove variable-unused warning
(LOCAL_PNG_VERSION >= (((maj) << 8) | (min)))
static void PNGAPI error_function(png_structp png, png_const_charp error) {
if (error != NULL) fprintf(stderr, "libpng error: %s\n", error);
longjmp(png_jmpbuf(png), 1); longjmp(png_jmpbuf(png), 1);
} }
#if LOCAL_PNG_PREREQ(1,4)
typedef png_alloc_size_t LocalPngAllocSize;
#else
typedef png_size_t LocalPngAllocSize;
#endif
static png_voidp MallocFunc(png_structp png_ptr, LocalPngAllocSize size) {
(void)png_ptr;
if (size != (size_t)size) return NULL;
if (!ImgIoUtilCheckSizeArgumentsOverflow(size, 1)) return NULL;
return (png_voidp)malloc((size_t)size);
}
static void FreeFunc(png_structp png_ptr, png_voidp ptr) {
(void)png_ptr;
free(ptr);
}
// Converts the NULL terminated 'hexstring' which contains 2-byte character // Converts the NULL terminated 'hexstring' which contains 2-byte character
// representations of hex values to raw data. // representations of hex values to raw data.
// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, // 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs,
@ -157,8 +130,8 @@ static int ExtractMetadataFromPNG(png_structp png,
for (p = 0; p < 2; ++p) { for (p = 0; p < 2; ++p) {
png_infop const info = (p == 0) ? head_info : end_info; png_infop const info = (p == 0) ? head_info : end_info;
png_textp text = NULL; png_textp text = NULL;
const png_uint_32 num = png_get_text(png, info, &text, NULL); const int num = png_get_text(png, info, &text, NULL);
png_uint_32 i; int i;
// Look for EXIF / XMP metadata. // Look for EXIF / XMP metadata.
for (i = 0; i < num; ++i, ++text) { for (i = 0; i < num; ++i, ++text) {
int j; int j;
@ -196,10 +169,11 @@ static int ExtractMetadataFromPNG(png_structp png,
{ {
png_charp name; png_charp name;
int comp_type; int comp_type;
#if LOCAL_PNG_PREREQ(1,5) #if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \
png_bytep profile; ((1 << 8) | (5 << 0))
#else
png_charp profile; png_charp profile;
#else // >= libpng 1.5.0
png_bytep profile;
#endif #endif
png_uint_32 len; png_uint_32 len;
@ -209,53 +183,34 @@ static int ExtractMetadataFromPNG(png_structp png,
} }
} }
} }
return 1; return 1;
} }
typedef struct { int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
const uint8_t* data; Metadata* const metadata) {
size_t data_size; png_structp png;
png_size_t offset; png_infop info = NULL;
} PNGReadContext; png_infop end_info = NULL;
static void ReadFunc(png_structp png_ptr, png_bytep data, png_size_t length) {
PNGReadContext* const ctx = (PNGReadContext*)png_get_io_ptr(png_ptr);
if (ctx->data_size - ctx->offset < length) {
png_error(png_ptr, "ReadFunc: invalid read length (overflow)!");
}
memcpy(data, ctx->data + ctx->offset, length);
ctx->offset += length;
}
int ReadPNG(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata) {
volatile png_structp png = NULL;
volatile png_infop info = NULL;
volatile png_infop end_info = NULL;
PNGReadContext context = { NULL, 0, 0 };
int color_type, bit_depth, interlaced; int color_type, bit_depth, interlaced;
int has_alpha; int has_alpha;
int num_passes; int num_passes;
int p; int p;
volatile int ok = 0; int ok = 0;
png_uint_32 width, height, y; png_uint_32 width, height, y;
int64_t stride; int stride;
uint8_t* volatile rgb = NULL; uint8_t* rgb = NULL;
if (data == NULL || data_size == 0 || pic == NULL) return 0; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png == NULL) {
context.data = data; goto End;
context.data_size = data_size; }
png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
NULL, MallocFunc, FreeFunc);
if (png == NULL) goto End;
png_set_error_fn(png, 0, error_function, NULL); png_set_error_fn(png, 0, error_function, NULL);
if (setjmp(png_jmpbuf(png))) { if (setjmp(png_jmpbuf(png))) {
Error: Error:
MetadataFree(metadata); MetadataFree(metadata);
png_destroy_read_struct(&png, &info, &end_info);
goto End; goto End;
} }
@ -264,7 +219,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
end_info = png_create_info_struct(png); end_info = png_create_info_struct(png);
if (end_info == NULL) goto Error; if (end_info == NULL) goto Error;
png_set_read_fn(png, &context, ReadFunc); png_init_io(png, in_file);
png_read_info(png, info); png_read_info(png, info);
if (!png_get_IHDR(png, info, if (!png_get_IHDR(png, info,
&width, &height, &bit_depth, &color_type, &interlaced, &width, &height, &bit_depth, &color_type, &interlaced,
@ -272,9 +227,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
png_set_strip_16(png); png_set_strip_16(png);
png_set_packing(png); png_set_packing(png);
if (color_type == PNG_COLOR_TYPE_PALETTE) { if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
png_set_palette_to_rgb(png);
}
if (color_type == PNG_COLOR_TYPE_GRAY || if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
if (bit_depth < 8) { if (bit_depth < 8) {
@ -289,16 +242,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;
@ -306,20 +249,13 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
num_passes = png_set_interlace_handling(png); num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info); png_read_update_info(png, info);
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height);
if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error;
}
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 = 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);
@ -330,29 +266,25 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
goto Error; goto Error;
} }
pic->width = (int)width; png_destroy_read_struct(&png, &info, &end_info);
pic->height = (int)height;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride) pic->width = width;
: WebPPictureImportRGB(pic, rgb, (int)stride); pic->height = height;
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
: WebPPictureImportRGB(pic, rgb, stride);
if (!ok) { if (!ok) {
goto Error; goto Error;
} }
End: End:
if (png != NULL) {
png_destroy_read_struct((png_structpp)&png,
(png_infopp)&info, (png_infopp)&end_info);
}
free(rgb); free(rgb);
return ok; return ok;
} }
#else // !WEBP_HAVE_PNG #else // !WEBP_HAVE_PNG
int ReadPNG(const uint8_t* const data, size_t data_size, int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha,
struct WebPPicture* const pic, struct Metadata* const metadata) {
int keep_alpha, struct Metadata* const metadata) { (void)in_file;
(void)data;
(void)data_size;
(void)pic; (void)pic;
(void)keep_alpha; (void)keep_alpha;
(void)metadata; (void)metadata;

View File

@ -9,29 +9,27 @@
// //
// 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 <stdio.h>
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
struct Metadata; struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads a PNG from 'data', returning the decoded output in 'pic'. // Reads a PNG 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 PNG has an alpha channel, the output is RGBA // If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // otherwise it will be RGB.
// Returns true on success. // Returns true on success.
int ReadPNG(const uint8_t* const data, size_t data_size, int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha,
struct WebPPicture* const pic, struct Metadata* const metadata);
int keep_alpha, struct Metadata* const metadata);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_PNGDEC_H_ #endif // WEBP_EXAMPLES_PNGDEC_H_

View File

@ -14,17 +14,11 @@
#ifndef WEBP_EXAMPLES_STOPWATCH_H_ #ifndef WEBP_EXAMPLES_STOPWATCH_H_
#define WEBP_EXAMPLES_STOPWATCH_H_ #define WEBP_EXAMPLES_STOPWATCH_H_
#include "webp/types.h"
#if defined _WIN32 && !defined __GNUC__ #if defined _WIN32 && !defined __GNUC__
#include <windows.h> #include <windows.h>
typedef LARGE_INTEGER Stopwatch; typedef LARGE_INTEGER Stopwatch;
static WEBP_INLINE void StopwatchReset(Stopwatch* watch) {
QueryPerformanceCounter(watch);
}
static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
const LARGE_INTEGER old_value = *watch; const LARGE_INTEGER old_value = *watch;
LARGE_INTEGER freq; LARGE_INTEGER freq;
@ -39,25 +33,17 @@ static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
#else /* !_WIN32 */ #else /* !_WIN32 */
#include <string.h> // memcpy
#include <sys/time.h> #include <sys/time.h>
typedef struct timeval Stopwatch; typedef struct timeval Stopwatch;
static WEBP_INLINE void StopwatchReset(Stopwatch* watch) {
gettimeofday(watch, NULL);
}
static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) {
struct timeval old_value; const struct timeval old_value = *watch;
double delta_sec, delta_usec;
memcpy(&old_value, watch, sizeof(old_value));
gettimeofday(watch, NULL); gettimeofday(watch, NULL);
delta_sec = (double)watch->tv_sec - old_value.tv_sec; return watch->tv_sec - old_value.tv_sec +
delta_usec = (double)watch->tv_usec - old_value.tv_usec; (watch->tv_usec - old_value.tv_usec) / 1000000.0;
return delta_sec + delta_usec / 1000000.0;
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif // WEBP_EXAMPLES_STOPWATCH_H_ #endif /* WEBP_EXAMPLES_STOPWATCH_H_ */

140
examples/tiffdec.c Normal file
View File

@ -0,0 +1,140 @@
// Copyright 2012 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.
// -----------------------------------------------------------------------------
//
// TIFF decode.
#include "./tiffdec.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef WEBP_HAVE_TIFF
#include <tiffio.h>
#include "webp/encode.h"
#include "./metadata.h"
static const struct {
ttag_t tag;
size_t storage_offset;
} kTIFFMetadataMap[] = {
{ TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) },
{ TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) },
{ 0, 0 },
};
// Returns true on success. The caller must use MetadataFree() on 'metadata' in
// all cases.
static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
int i;
toff_t exif_ifd_offset;
for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) {
MetadataPayload* const payload =
(MetadataPayload*)((uint8_t*)metadata +
kTIFFMetadataMap[i].storage_offset);
void* tag_data;
uint32 tag_data_len;
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
return 0;
}
}
// TODO(jzern): To extract the raw EXIF directory some parsing of it would be
// necessary to determine the overall size. In addition, value offsets in
// individual directory entries may need to be updated as, depending on the
// type, they are file based.
// Exif 2.2 Section 4.6.2 Tag Structure
// TIFF Revision 6.0 Part 1 Section 2 TIFF Structure #Image File Directory
if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &exif_ifd_offset)) {
fprintf(stderr, "Warning: EXIF extraction from TIFF is unsupported.\n");
}
return 1;
}
int ReadTIFF(const char* const filename,
WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
TIFF* const tif = TIFFOpen(filename, "r");
uint32 width, height;
uint32* raster;
int ok = 0;
tdir_t dircount;
if (tif == NULL) {
fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
return 0;
}
dircount = TIFFNumberOfDirectories(tif);
if (dircount > 1) {
fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
"Only the first will be used, %d will be ignored.\n",
dircount - 1);
}
if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
return 0;
}
raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
ORIENTATION_TOPLEFT, 1)) {
const int stride = width * sizeof(*raster);
pic->width = width;
pic->height = height;
// TIFF data is ABGR
#ifdef __BIG_ENDIAN__
TIFFSwabArrayOfLong(raster, width * height);
#endif
ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
}
_TIFFfree(raster);
} else {
fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
}
if (ok) {
if (metadata != NULL) {
ok = ExtractMetadataFromTIFF(tif, metadata);
if (!ok) {
fprintf(stderr, "Error extracting TIFF metadata!\n");
MetadataFree(metadata);
WebPPictureFree(pic);
}
}
}
TIFFClose(tif);
return ok;
}
#else // !WEBP_HAVE_TIFF
int ReadTIFF(const char* const filename,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)filename;
(void)pic;
(void)keep_alpha;
(void)metadata;
fprintf(stderr, "TIFF support not compiled. Please install the libtiff "
"development package before building.\n");
return 0;
}
#endif // WEBP_HAVE_TIFF
// -----------------------------------------------------------------------------

View File

@ -9,29 +9,26 @@
// //
// 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" #if defined(__cplusplus) || defined(c_plusplus)
#ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct Metadata; struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads a TIFF from 'data', returning the decoded output in 'pic'. // Reads a TIFF from 'filename', returning the decoded output in 'pic'.
// Output is RGBA or YUVA, depending on pic->use_argb value.
// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA // If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA
// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // otherwise it will be RGB.
// Returns true on success. // Returns true on success.
int ReadTIFF(const uint8_t* const data, size_t data_size, int ReadTIFF(const char* const filename,
struct WebPPicture* const pic, int keep_alpha, struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata); struct Metadata* const metadata);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_IMAGEIO_TIFFDEC_H_ #endif // WEBP_EXAMPLES_TIFFDEC_H_

View File

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

View File

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

View File

@ -11,19 +11,13 @@
// //
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "config.h"
#endif
#if defined(__unix__) || defined(__CYGWIN__)
#define _POSIX_C_SOURCE 200112L // for setenv
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if defined(WEBP_HAVE_GL)
#if defined(HAVE_GLUT_GLUT_H) #if defined(HAVE_GLUT_GLUT_H)
#include <GLUT/glut.h> #include <GLUT/glut.h>
#else #else
@ -40,14 +34,14 @@
#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"
#include "./unicode.h"
#if defined(_MSC_VER) && _MSC_VER < 1900 #ifdef _MSC_VER
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
static void Help(void);
// Unfortunate global variables. Gathered into a struct for comfort. // Unfortunate global variables. Gathered into a struct for comfort.
static struct { static struct {
int has_animation; int has_animation;
@ -55,9 +49,7 @@ 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 draw_anim_background_color;
int canvas_width, canvas_height; int canvas_width, canvas_height;
int loop_count; int loop_count;
@ -65,13 +57,16 @@ static struct {
const char* file_name; const char* file_name;
WebPData data; WebPData data;
WebPDecoderConfig config; WebPDecoderConfig* config;
const WebPDecBuffer* pic; const WebPDecBuffer* pic;
WebPDemuxer* dmux; WebPDemuxer* dmux;
WebPIterator curr_frame; WebPIterator frameiter;
WebPIterator prev_frame; struct {
int width, height;
int x_offset, y_offset;
enum WebPMuxAnimDispose dispose_method;
} prev_frame;
WebPChunkIterator iccp; WebPChunkIterator iccp;
int viewport_width, viewport_height;
} kParams; } kParams;
static void ClearPreviousPic(void) { static void ClearPreviousPic(void) {
@ -82,23 +77,12 @@ static void ClearPreviousPic(void) {
static void ClearParams(void) { static void ClearParams(void) {
ClearPreviousPic(); ClearPreviousPic();
WebPDataClear(&kParams.data); WebPDataClear(&kParams.data);
WebPDemuxReleaseIterator(&kParams.curr_frame); WebPDemuxReleaseIterator(&kParams.frameiter);
WebPDemuxReleaseIterator(&kParams.prev_frame);
WebPDemuxReleaseChunkIterator(&kParams.iccp); WebPDemuxReleaseChunkIterator(&kParams.iccp);
WebPDemuxDelete(kParams.dmux); WebPDemuxDelete(kParams.dmux);
kParams.dmux = NULL; kParams.dmux = NULL;
} }
// Sets the previous frame to the dimensions of the canvas and has it dispose
// to background to cause the canvas to be cleared.
static void ClearPreviousFrame(void) {
WebPIterator* const prev = &kParams.prev_frame;
prev->width = kParams.canvas_width;
prev->height = kParams.canvas_height;
prev->x_offset = prev->y_offset = 0;
prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Color profile handling // Color profile handling
static int ApplyColorProfile(const WebPData* const profile, static int ApplyColorProfile(const WebPData* const profile,
@ -163,25 +147,25 @@ static int ApplyColorProfile(const WebPData* const profile,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// File decoding // File decoding
static int Decode(void) { // Fills kParams.curr_frame static int Decode(void) { // Fills kParams.frameiter
const WebPIterator* const curr = &kParams.curr_frame; const WebPIterator* const iter = &kParams.frameiter;
WebPDecoderConfig* const config = &kParams.config; WebPDecoderConfig* const config = kParams.config;
WebPDecBuffer* const output_buffer = &config->output; WebPDecBuffer* const output_buffer = &config->output;
int ok = 0; int ok = 0;
ClearPreviousPic(); ClearPreviousPic();
output_buffer->colorspace = MODE_RGBA; output_buffer->colorspace = MODE_RGBA;
ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size, ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size,
config) == VP8_STATUS_OK); config) == VP8_STATUS_OK);
if (!ok) { if (!ok) {
fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num); fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num);
} else { } else {
kParams.pic = output_buffer; kParams.pic = output_buffer;
if (kParams.use_color_profile) { if (kParams.use_color_profile) {
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer); ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
if (!ok) { if (!ok) {
fprintf(stderr, "Applying color profile to frame #%d failed!\n", fprintf(stderr, "Applying color profile to frame #%d failed!\n",
curr->frame_num); iter->frame_num);
} }
} }
} }
@ -192,26 +176,19 @@ static void decode_callback(int what) {
if (what == 0 && !kParams.done) { if (what == 0 && !kParams.done) {
int duration = 0; int duration = 0;
if (kParams.dmux != NULL) { if (kParams.dmux != NULL) {
WebPIterator* const curr = &kParams.curr_frame; WebPIterator* const iter = &kParams.frameiter;
if (!WebPDemuxNextFrame(curr)) { if (!WebPDemuxNextFrame(iter)) {
WebPDemuxReleaseIterator(curr); WebPDemuxReleaseIterator(iter);
if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) {
--kParams.loop_count; --kParams.loop_count;
kParams.done = (kParams.loop_count == 0); kParams.done = (kParams.loop_count == 0);
if (kParams.done) return;
ClearPreviousFrame();
} else { } else {
kParams.decoding_error = 1; kParams.decoding_error = 1;
kParams.done = 1; kParams.done = 1;
return; return;
} }
} }
duration = curr->duration; duration = iter->duration;
// Behavior copied from Chrome, cf:
// https://cs.chromium.org/chromium/src/third_party/WebKit/Source/
// platform/graphics/DeferredImageDecoder.cpp?
// rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246
if (duration <= 10) duration = 100;
} }
if (!Decode()) { if (!Decode()) {
kParams.decoding_error = 1; kParams.decoding_error = 1;
@ -227,9 +204,6 @@ static void decode_callback(int what) {
// Callbacks // Callbacks
static void HandleKey(unsigned char key, int pos_x, int pos_y) { static void HandleKey(unsigned char key, int pos_x, int pos_y) {
// Note: rescaling the window or toggling some features during an animation
// generates visual artifacts. This is not fixed because refreshing the frame
// may require rendering the whole animation from start till current frame.
(void)pos_x; (void)pos_x;
(void)pos_y; (void)pos_y;
if (key == 'q' || key == 'Q' || key == 27 /* Esc */) { if (key == 'q' || key == 'Q' || key == 27 /* Esc */) {
@ -257,31 +231,20 @@ static void HandleKey(unsigned char key, int pos_x, int pos_y) {
glutPostRedisplay(); glutPostRedisplay();
} }
} }
} else if (key == 'b') {
kParams.draw_anim_background_color = 1 - kParams.draw_anim_background_color;
if (!kParams.has_animation) ClearPreviousFrame();
glutPostRedisplay();
} else if (key == 'i') { } else if (key == 'i') {
kParams.print_info = 1 - kParams.print_info; kParams.print_info = 1 - kParams.print_info;
if (!kParams.has_animation) ClearPreviousFrame();
glutPostRedisplay();
} else if (key == 'd') {
kParams.only_deltas = 1 - kParams.only_deltas;
glutPostRedisplay(); 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): proper handling of resize, esp. for large pictures.
// be handling larger-than-screen pictures incorrectly. // + key control of the zoom.
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
kParams.viewport_width = width;
kParams.viewport_height = height;
if (!kParams.has_animation) ClearPreviousFrame();
} }
static void PrintString(const char* const text) { static void PrintString(const char* const text) {
@ -293,7 +256,7 @@ static void PrintString(const char* const text) {
} }
static float GetColorf(uint32_t color, int shift) { static float GetColorf(uint32_t color, int shift) {
return ((color >> shift) & 0xff) / 255.f; return (color >> shift) / 255.f;
} }
static void DrawCheckerBoard(void) { static void DrawCheckerBoard(void) {
@ -316,77 +279,42 @@ static void DrawCheckerBoard(void) {
glPopMatrix(); glPopMatrix();
} }
static void DrawBackground(void) {
// Whole window cleared with clear color, checkerboard rendered on top of it.
glClear(GL_COLOR_BUFFER_BIT);
DrawCheckerBoard();
// ANIM background color rendered (blend) on top. Default is white for still
// images (without ANIM chunk). glClear() can't be used for that (no blend).
if (kParams.draw_anim_background_color) {
glPushMatrix();
glLoadIdentity();
glColor4f(GetColorf(kParams.bg_color, 16), // BGRA from spec
GetColorf(kParams.bg_color, 8),
GetColorf(kParams.bg_color, 0),
GetColorf(kParams.bg_color, 24));
glRecti(-1, -1, +1, +1);
glPopMatrix();
}
}
// Draw background in a scissored rectangle.
static void DrawBackgroundScissored(int window_x, int window_y, int frame_w,
int frame_h) {
// Only update the requested area, not the whole canvas.
window_x = window_x * kParams.viewport_width / kParams.canvas_width;
window_y = window_y * kParams.viewport_height / kParams.canvas_height;
frame_w = frame_w * kParams.viewport_width / kParams.canvas_width;
frame_h = frame_h * kParams.viewport_height / kParams.canvas_height;
// glScissor() takes window coordinates (0,0 at bottom left).
window_y = kParams.viewport_height - window_y - frame_h;
glEnable(GL_SCISSOR_TEST);
glScissor(window_x, window_y, frame_w, frame_h);
DrawBackground();
glDisable(GL_SCISSOR_TEST);
}
static void HandleDisplay(void) { static void HandleDisplay(void) {
const WebPDecBuffer* const pic = kParams.pic; const WebPDecBuffer* const pic = kParams.pic;
const WebPIterator* const curr = &kParams.curr_frame; const WebPIterator* const iter = &kParams.frameiter;
WebPIterator* const prev = &kParams.prev_frame;
GLfloat xoff, yoff; GLfloat xoff, yoff;
if (pic == NULL) return; if (pic == NULL) return;
glPushMatrix(); glPushMatrix();
glPixelZoom((GLfloat)(+1. / kParams.canvas_width * kParams.viewport_width), glPixelZoom(1, -1);
(GLfloat)(-1. / kParams.canvas_height * kParams.viewport_height)); xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width);
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width); yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height);
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
glRasterPos2f(-1.f + xoff, 1.f - yoff); glRasterPos2f(-1.f + xoff, 1.f - yoff);
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 (kParams.prev_frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
DrawBackground(); // TODO(later): these offsets and those above should factor in window size.
} else { // they will be incorrect if the window is resized.
// The rectangle of the previous frame might be different than the current // glScissor() takes window coordinates (0,0 at bottom left).
// frame, so we may need to DrawBackgroundScissored for both. const int window_x = kParams.prev_frame.x_offset;
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { const int window_y = kParams.canvas_height -
// Clear the previous frame rectangle. kParams.prev_frame.y_offset -
DrawBackgroundScissored(prev->x_offset, prev->y_offset, prev->width, kParams.prev_frame.height;
prev->height); glEnable(GL_SCISSOR_TEST);
} // Only updated the requested area, not the whole canvas.
if (curr->blend_method == WEBP_MUX_NO_BLEND) { glScissor(window_x, window_y,
// We simulate no-blending behavior by first clearing the current frame kParams.prev_frame.width, kParams.prev_frame.height);
// rectangle and then alpha-blending against it.
DrawBackgroundScissored(curr->x_offset, curr->y_offset, curr->width,
curr->height);
}
}
*prev = *curr; glClear(GL_COLOR_BUFFER_BIT); // use clear color
DrawCheckerBoard();
glDisable(GL_SCISSOR_TEST);
}
kParams.prev_frame.width = iter->width;
kParams.prev_frame.height = iter->height;
kParams.prev_frame.x_offset = iter->x_offset;
kParams.prev_frame.y_offset = iter->y_offset;
kParams.prev_frame.dispose_method = iter->dispose_method;
glDrawPixels(pic->width, pic->height, glDrawPixels(pic->width, pic->height,
GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, GL_UNSIGNED_BYTE,
@ -402,118 +330,80 @@ static void HandleDisplay(void) {
glColor4f(0.90f, 0.0f, 0.90f, 1.0f); glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.80f); glRasterPos2f(-0.95f, 0.80f);
PrintString(tmp); PrintString(tmp);
if (curr->x_offset != 0 || curr->y_offset != 0) { if (iter->x_offset != 0 || iter->y_offset != 0) {
snprintf(tmp, sizeof(tmp), " (offset:%d,%d)", snprintf(tmp, sizeof(tmp), " (offset:%d,%d)",
curr->x_offset, curr->y_offset); iter->x_offset, iter->y_offset);
glRasterPos2f(-0.95f, 0.70f); glRasterPos2f(-0.95f, 0.70f);
PrintString(tmp); PrintString(tmp);
} }
} }
glPopMatrix(); glPopMatrix();
#if defined(__APPLE__) || defined(_WIN32)
glFlush(); glFlush();
#else
glutSwapBuffers();
#endif
} }
static void StartDisplay(void) { static void StartDisplay(void) {
int width = kParams.canvas_width; const int width = kParams.canvas_width;
int height = kParams.canvas_height; const int height = kParams.canvas_height;
int screen_width, screen_height;
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
// partially displayed with animated webp + alpha.
#if defined(__APPLE__) || defined(_WIN32)
glutInitDisplayMode(GLUT_RGBA); glutInitDisplayMode(GLUT_RGBA);
#else
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
#endif
screen_width = glutGet(GLUT_SCREEN_WIDTH);
screen_height = glutGet(GLUT_SCREEN_HEIGHT);
if (width > screen_width || height > screen_height) {
if (width > screen_width) {
height = (height * screen_width + width - 1) / width;
width = screen_width;
}
if (height > screen_height) {
width = (width * screen_height + height - 1) / height;
height = screen_height;
}
}
glutInitWindowSize(width, height); glutInitWindowSize(width, height);
glutCreateWindow("WebP viewer"); glutCreateWindow("WebP viewer");
glutDisplayFunc(HandleDisplay); glutDisplayFunc(HandleDisplay);
glutReshapeFunc(HandleReshape);
glutIdleFunc(NULL); glutIdleFunc(NULL);
glutKeyboardFunc(HandleKey); glutKeyboardFunc(HandleKey);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glClearColor(0, 0, 0, 0); // window will be cleared to black (no blend) glClearColor(GetColorf(kParams.bg_color, 0),
DrawBackground(); GetColorf(kParams.bg_color, 8),
GetColorf(kParams.bg_color, 16),
GetColorf(kParams.bg_color, 24));
HandleReshape(width, height);
glClear(GL_COLOR_BUFFER_BIT);
DrawCheckerBoard();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main // Main
static void Help(void) { static void Help(void) {
printf( printf("Usage: vwebp in_file [options]\n\n"
"Usage: vwebp in_file [options]\n\n"
"Decodes the WebP image file and visualize it using OpenGL\n" "Decodes the WebP image file and visualize it using OpenGL\n"
"Options are:\n" "Options are:\n"
" -version ..... print version number and exit\n" " -version .... print version number and exit.\n"
" -noicc ....... don't use the icc profile if present\n" " -noicc ....... don't use the icc profile if present.\n"
" -nofancy ..... don't use the fancy YUV420 upscaler\n" " -nofancy ..... don't use the fancy YUV420 upscaler.\n"
" -nofilter .... disable in-loop filtering\n" " -nofilter .... disable in-loop filtering.\n"
" -dither <int> dithering strength (0..100), default=50\n" " -mt .......... use multi-threading.\n"
" -noalphadither disable alpha plane dithering\n" " -info ........ print info.\n"
" -usebgcolor .. display background color\n" " -h ....... this help message.\n"
" -mt .......... use multi-threading\n"
" -info ........ print info\n"
" -h ........... this help message\n"
"\n" "\n"
"Keyboard shortcuts:\n" "Keyboard shortcuts:\n"
" 'c' ................ toggle use of color profile\n" " 'c' ................ toggle use of color profile.\n"
" 'b' ................ toggle background color display\n" " 'i' ................ overlay file information.\n"
" 'i' ................ overlay file information\n" " 'q' / 'Q' / ESC .... quit.\n"
" 'd' ................ disable blending & disposal (debug)\n" );
" 'q' / 'Q' / ESC .... quit\n");
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
WebPDecoderConfig config;
int c; int c;
WebPDecoderConfig* const config = &kParams.config;
WebPIterator* const curr = &kParams.curr_frame;
INIT_WARGV(argc, argv); if (!WebPInitDecoderConfig(&config)) {
if (!WebPInitDecoderConfig(config)) {
fprintf(stderr, "Library version mismatch!\n"); fprintf(stderr, "Library version mismatch!\n");
FREE_WARGV_AND_RETURN(-1); return -1;
} }
config->options.dithering_strength = 50; kParams.config = &config;
config->options.alpha_dithering_strength = 100;
kParams.use_color_profile = 1; kParams.use_color_profile = 1;
// Background color hidden by default to see transparent areas.
kParams.draw_anim_background_color = 0;
for (c = 1; c < argc; ++c) { for (c = 1; c < argc; ++c) {
int parse_error = 0;
if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
Help(); Help();
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-noicc")) { } else if (!strcmp(argv[c], "-noicc")) {
kParams.use_color_profile = 0; kParams.use_color_profile = 0;
} else if (!strcmp(argv[c], "-nofancy")) { } else if (!strcmp(argv[c], "-nofancy")) {
config->options.no_fancy_upsampling = 1; config.options.no_fancy_upsampling = 1;
} else if (!strcmp(argv[c], "-nofilter")) { } else if (!strcmp(argv[c], "-nofilter")) {
config->options.bypass_filtering = 1; config.options.bypass_filtering = 1;
} else if (!strcmp(argv[c], "-noalphadither")) {
config->options.alpha_dithering_strength = 0;
} else if (!strcmp(argv[c], "-usebgcolor")) {
kParams.draw_anim_background_color = 1;
} else if (!strcmp(argv[c], "-dither") && c + 1 < argc) {
config->options.dithering_strength =
ExUtilGetInt(argv[++c], 0, &parse_error);
} else if (!strcmp(argv[c], "-info")) { } else if (!strcmp(argv[c], "-info")) {
kParams.print_info = 1; kParams.print_info = 1;
} else if (!strcmp(argv[c], "-version")) { } else if (!strcmp(argv[c], "-version")) {
@ -523,33 +413,25 @@ int main(int argc, char *argv[]) {
(dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff,
dec_version & 0xff, (dmux_version >> 16) & 0xff, dec_version & 0xff, (dmux_version >> 16) & 0xff,
(dmux_version >> 8) & 0xff, dmux_version & 0xff); (dmux_version >> 8) & 0xff, dmux_version & 0xff);
FREE_WARGV_AND_RETURN(0); return 0;
} else if (!strcmp(argv[c], "-mt")) { } else if (!strcmp(argv[c], "-mt")) {
config->options.use_threads = 1; config.options.use_threads = 1;
} else if (!strcmp(argv[c], "--")) {
if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c);
break;
} else if (argv[c][0] == '-') { } else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]); printf("Unknown option '%s'\n", argv[c]);
Help(); Help();
FREE_WARGV_AND_RETURN(-1); return -1;
} else { } else {
kParams.file_name = (const char*)GET_WARGV(argv, c); kParams.file_name = argv[c];
}
if (parse_error) {
Help();
FREE_WARGV_AND_RETURN(-1);
} }
} }
if (kParams.file_name == NULL) { if (kParams.file_name == NULL) {
printf("missing input file!!\n"); printf("missing input file!!\n");
Help(); Help();
FREE_WARGV_AND_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;
} }
@ -565,13 +447,20 @@ 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) {
printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height);
} }
ClearPreviousFrame(); kParams.prev_frame.width = kParams.canvas_width;
kParams.prev_frame.height = kParams.canvas_height;
kParams.prev_frame.x_offset = kParams.prev_frame.y_offset = 0;
kParams.prev_frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
memset(&kParams.iccp, 0, sizeof(kParams.iccp)); memset(&kParams.iccp, 0, sizeof(kParams.iccp));
kParams.has_color_profile = kParams.has_color_profile =
@ -587,28 +476,22 @@ int main(int argc, char *argv[]) {
#endif #endif
} }
if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error; if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error;
kParams.has_animation = (curr->num_frames > 1); kParams.has_animation = (kParams.frameiter.num_frames > 1);
kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT); kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT);
kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR); kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR);
printf("VP8X: Found %d images in file (loop count = %d)\n", printf("VP8X: Found %d images in file (loop count = %d)\n",
curr->num_frames, kParams.loop_count); kParams.frameiter.num_frames, kParams.loop_count);
// Decode first frame // Decode first frame
if (!Decode()) goto Error; if (!Decode()) goto Error;
// Position iterator to last frame. Next call to HandleDisplay will wrap over. // Position iterator to last frame. Next call to HandleDisplay will wrap over.
// We take this into account by bumping up loop_count. // We take this into account by bumping up loop_count.
WebPDemuxGetFrame(kParams.dmux, 0, curr); WebPDemuxGetFrame(kParams.dmux, 0, &kParams.frameiter);
if (kParams.loop_count) ++kParams.loop_count; if (kParams.loop_count) ++kParams.loop_count;
#if defined(__unix__) || defined(__CYGWIN__)
// Work around GLUT compositor bug.
// https://bugs.launchpad.net/ubuntu/+source/freeglut/+bug/369891
setenv("XLIB_SKIP_ARGB_VISUALS", "1", 1);
#endif
// Start display (and timer) // Start display (and timer)
glutInit(&argc, argv); glutInit(&argc, argv);
#ifdef FREEGLUT #ifdef FREEGLUT
@ -621,21 +504,11 @@ int main(int argc, char *argv[]) {
// Should only be reached when using FREEGLUT: // Should only be reached when using FREEGLUT:
ClearParams(); ClearParams();
FREE_WARGV_AND_RETURN(0); return 0;
Error: Error:
ClearParams(); ClearParams();
FREE_WARGV_AND_RETURN(-1); return -1;
} }
#else // !WEBP_HAVE_GL
int main(int argc, const char *argv[]) {
fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]);
(void)argc;
return 0;
}
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,12 +12,10 @@
#include "./wicdec.h" #include "./wicdec.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "webp/config.h" #include "config.h"
#endif #endif
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
#ifdef __MINGW32__ #ifdef __MINGW32__
@ -27,16 +25,12 @@
#define COBJMACROS #define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ #define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS. // code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h> #include <shlwapi.h>
#include <tchar.h>
#include <windows.h> #include <windows.h>
#include <wincodec.h> #include <wincodec.h>
#include "../examples/unicode.h"
#include "./imageio_util.h"
#include "./metadata.h"
#include "webp/encode.h" #include "webp/encode.h"
#include "./metadata.h"
#define IFS(fn) \ #define IFS(fn) \
do { \ do { \
@ -78,44 +72,12 @@ WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_, WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
0xf5c7ad2d, 0x6a8d, 0x43dd, 0xf5c7ad2d, 0x6a8d, 0x43dd,
0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppBGRA_,
0x1562ff7c, 0xd352, 0x46f9,
0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
0x6fddc324, 0x4e03, 0x4bfe,
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
static HRESULT OpenInputStream(const char* filename, IStream** stream) { static HRESULT OpenInputStream(const char* filename, IStream** stream) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!WSTRCMP(filename, "-")) { IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
const uint8_t* data = NULL;
size_t data_size = 0;
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
if (ok) {
HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
if (image != NULL) {
void* const image_mem = GlobalLock(image);
if (image_mem != NULL) {
memcpy(image_mem, data, data_size);
GlobalUnlock(image);
IFS(CreateStreamOnHGlobal(image, TRUE, stream));
} else {
hr = E_FAIL;
}
} else {
hr = E_OUTOFMEMORY;
}
free((void*)data);
} else {
hr = E_FAIL;
}
} else {
IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream));
}
if (FAILED(hr)) { if (FAILED(hr)) {
_ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"), fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
(const LPTSTR)filename, hr);
} }
return hr; return hr;
} }
@ -147,7 +109,6 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, IFS(IWICBitmapFrameDecode_GetColorContexts(frame,
count, color_contexts, count, color_contexts,
&num_color_contexts)); &num_color_contexts));
assert(FAILED(hr) || num_color_contexts <= count);
for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) { for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
WICColorContextType type; WICColorContextType type;
IFS(IWICColorContext_GetType(color_contexts[i], &type)); IFS(IWICColorContext_GetType(color_contexts[i], &type));
@ -155,7 +116,7 @@ static HRESULT ExtractICCP(IWICImagingFactory* const factory,
UINT size; UINT size;
IFS(IWICColorContext_GetProfileBytes(color_contexts[i], IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
0, NULL, &size)); 0, NULL, &size));
if (SUCCEEDED(hr) && size > 0) { if (size > 0) {
iccp->bytes = (uint8_t*)malloc(size); iccp->bytes = (uint8_t*)malloc(size);
if (iccp->bytes == NULL) { if (iccp->bytes == NULL) {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
@ -233,11 +194,7 @@ static int HasAlpha(IWICImagingFactory* const factory,
has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format), has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) || MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format), IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)) || MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_));
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat64bppRGBA_)) ||
IsEqualGUID(MAKE_REFGUID(pixel_format),
MAKE_REFGUID(GUID_WICPixelFormat64bppBGRA_));
} }
return has_alpha; return has_alpha;
} }
@ -277,9 +234,7 @@ int ReadPictureWithWIC(const char* const filename,
NULL NULL
}; };
int has_alpha = 0; int has_alpha = 0;
int64_t stride; int 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,
@ -306,7 +261,7 @@ int ReadPictureWithWIC(const char* const filename,
IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format)); IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format)); IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format));
if (SUCCEEDED(hr) && keep_alpha) { if (keep_alpha) {
const GUID** guid; const GUID** guid;
for (guid = kAlphaContainers; *guid != NULL; ++guid) { for (guid = kAlphaContainers; *guid != NULL; ++guid) {
if (IsEqualGUID(MAKE_REFGUID(src_container_format), if (IsEqualGUID(MAKE_REFGUID(src_container_format),
@ -339,27 +294,21 @@ int ReadPictureWithWIC(const char* const filename,
// Decode. // Decode.
IFS(IWICFormatConverter_GetSize(converter, &width, &height)); IFS(IWICFormatConverter_GetSize(converter, &width, &height));
stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb); stride = importer->bytes_per_pixel * width * sizeof(*rgb);
if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
hr = E_FAIL;
}
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
rgb = (BYTE*)malloc((size_t)stride * height); rgb = (BYTE*)malloc(stride * height);
if (rgb == NULL) if (rgb == NULL)
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
} }
IFS(IWICFormatConverter_CopyPixels(converter, NULL, IFS(IWICFormatConverter_CopyPixels(converter, NULL,
(UINT)stride, (UINT)stride * height, rgb)); stride, stride * height, rgb));
// WebP conversion. // WebP conversion.
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
int ok; int ok;
pic->width = width; pic->width = width;
pic->height = height; pic->height = height;
pic->use_argb = 1; // For WIC, we always force to argb ok = importer->import(pic, rgb, stride);
ok = importer->import(pic, rgb, (int)stride);
if (!ok) hr = E_FAIL; if (!ok) hr = E_FAIL;
} }
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {

View File

@ -9,10 +9,10 @@
// //
// 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 #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
@ -21,14 +21,14 @@ struct WebPPicture;
// Reads an image from 'filename', returning the decoded output in 'pic'. // Reads an image from 'filename', returning the decoded output in 'pic'.
// If 'keep_alpha' is true and the image has an alpha channel, the output is // If 'keep_alpha' is true and the image has an alpha channel, the output is
// RGBA otherwise it will be RGB. pic->use_argb is always forced to true. // RGBA otherwise it will be RGB.
// Returns true on success. // Returns true on success.
int ReadPictureWithWIC(const char* const filename, int ReadPictureWithWIC(const char* const filename,
struct WebPPicture* const pic, int keep_alpha, struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata); struct Metadata* const metadata);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // 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 BUILD_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,146 +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.
// -----------------------------------------------------------------------------
//
// Additional WebP utilities.
//
#include "extras/extras.h"
#include "webp/format_constants.h"
#include <assert.h>
#include <string.h>
#define XTRA_MAJ_VERSION 1
#define XTRA_MIN_VERSION 0
#define XTRA_REV_VERSION 3
//------------------------------------------------------------------------------
int WebPGetExtrasVersion(void) {
return (XTRA_MAJ_VERSION << 16) | (XTRA_MIN_VERSION << 8) | XTRA_REV_VERSION;
}
//------------------------------------------------------------------------------
int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) {
int y, width, uv_width;
if (pic == NULL || gray_data == NULL) return 0;
pic->colorspace = WEBP_YUV420;
if (!WebPPictureAlloc(pic)) return 0;
width = pic->width;
uv_width = (width + 1) >> 1;
for (y = 0; y < pic->height; ++y) {
memcpy(pic->y + y * pic->y_stride, gray_data, width);
gray_data += width; // <- we could use some 'data_stride' here if needed
if ((y & 1) == 0) {
memset(pic->u + (y >> 1) * pic->uv_stride, 128, uv_width);
memset(pic->v + (y >> 1) * pic->uv_stride, 128, uv_width);
}
}
return 1;
}
int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) {
int x, y;
uint32_t* dst;
if (pic == NULL || rgb565 == NULL) return 0;
pic->colorspace = WEBP_YUV420;
pic->use_argb = 1;
if (!WebPPictureAlloc(pic)) return 0;
dst = pic->argb;
for (y = 0; y < pic->height; ++y) {
const int width = pic->width;
for (x = 0; x < width; ++x) {
#ifdef WEBP_SWAP_16BIT_CSP
const uint32_t rg = rgb565[2 * x + 1];
const uint32_t gb = rgb565[2 * x + 0];
#else
const uint32_t rg = rgb565[2 * x + 0];
const uint32_t gb = rgb565[2 * x + 1];
#endif
uint32_t r = rg & 0xf8;
uint32_t g = ((rg << 5) | (gb >> 3)) & 0xfc;
uint32_t b = (gb << 5);
// dithering
r = r | (r >> 5);
g = g | (g >> 6);
b = b | (b >> 5);
dst[x] = (0xffu << 24) | (r << 16) | (g << 8) | b;
}
rgb565 += 2 * width;
dst += pic->argb_stride;
}
return 1;
}
int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) {
int x, y;
uint32_t* dst;
if (pic == NULL || rgb4444 == NULL) return 0;
pic->colorspace = WEBP_YUV420;
pic->use_argb = 1;
if (!WebPPictureAlloc(pic)) return 0;
dst = pic->argb;
for (y = 0; y < pic->height; ++y) {
const int width = pic->width;
for (x = 0; x < width; ++x) {
#ifdef WEBP_SWAP_16BIT_CSP
const uint32_t rg = rgb4444[2 * x + 1];
const uint32_t ba = rgb4444[2 * x + 0];
#else
const uint32_t rg = rgb4444[2 * x + 0];
const uint32_t ba = rgb4444[2 * x + 1];
#endif
uint32_t r = rg & 0xf0;
uint32_t g = (rg << 4);
uint32_t b = (ba & 0xf0);
uint32_t a = (ba << 4);
// dithering
r = r | (r >> 4);
g = g | (g >> 4);
b = b | (b >> 4);
a = a | (a >> 4);
dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
}
rgb4444 += 2 * width;
dst += pic->argb_stride;
}
return 1;
}
int WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride,
const uint32_t palette[], int palette_size,
WebPPicture* pic) {
int x, y;
uint32_t* dst;
// 256 as the input buffer is uint8_t.
assert(MAX_PALETTE_SIZE <= 256);
if (pic == NULL || indexed == NULL || indexed_stride < pic->width ||
palette == NULL || palette_size > MAX_PALETTE_SIZE || palette_size <= 0) {
return 0;
}
pic->use_argb = 1;
if (!WebPPictureAlloc(pic)) return 0;
dst = pic->argb;
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) {
// Make sure we are within the palette.
if (indexed[x] >= palette_size) {
WebPPictureFree(pic);
return 0;
}
dst[x] = palette[indexed[x]];
}
indexed += indexed_stride;
dst += pic->argb_stride;
}
return 1;
}
//------------------------------------------------------------------------------

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

View File

@ -1,54 +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"
#include "../examples/unicode.h"
int main(int argc, const char *argv[]) {
int c;
int quiet = 0;
int ok = 1;
INIT_WARGV(argc, argv);
for (c = 1; ok && c < argc; ++c) {
if (!strcmp(argv[c], "-quiet")) {
quiet = 1;
} else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) {
printf("webp_quality [-h][-quiet] webp_files...\n");
FREE_WARGV_AND_RETURN(0);
} else {
const char* const filename = (const char*)GET_WARGV(argv, c);
const uint8_t* data = NULL;
size_t data_size = 0;
int q;
ok = ImgIoUtilReadFile(filename, &data, &data_size);
if (!ok) break;
q = VP8EstimateQuality(data, data_size);
if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename);
if (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);
}
}
FREE_WARGV_AND_RETURN(ok ? 0 : 1);
}

View File

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

View File

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

View File

@ -1,14 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Versions for gradle
BUILD_TOOLS_VERSION=23.0.3
COMPILE_SDK_VERSION=23
ANDROID_GRADLE_PLUGIN_VERSION=1.5.0
GRADLE_DOWNLOAD_TASK_VERSION=2.1.0

Binary file not shown.

View File

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

164
gradlew vendored
View File

@ -1,164 +0,0 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored
View File

@ -1,90 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

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 BUILD_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,66 +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.
// -----------------------------------------------------------------------------
//
// Generic image-type guessing.
#include "./image_dec.h"
static WEBP_INLINE uint32_t GetBE32(const uint8_t buf[]) {
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
size_t data_size) {
WebPInputFileFormat format = WEBP_UNSUPPORTED_FORMAT;
if (data != NULL && data_size >= 12) {
const uint32_t magic1 = GetBE32(data + 0);
const uint32_t magic2 = GetBE32(data + 8);
if (magic1 == 0x89504E47U) {
format = WEBP_PNG_FORMAT;
} else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) {
format = WEBP_JPEG_FORMAT;
} else if (magic1 == 0x49492A00 || magic1 == 0x4D4D002A) {
format = WEBP_TIFF_FORMAT;
} else if (magic1 == 0x52494646 && magic2 == 0x57454250) {
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;
}
static int FailReader(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata) {
(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_JPEG_FORMAT: return ReadJPEG;
case WEBP_TIFF_FORMAT: return ReadTIFF;
case WEBP_WEBP_FORMAT: return ReadWebP;
case WEBP_PNM_FORMAT: return ReadPNM;
default: return FailReader;
}
}
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
size_t data_size) {
return WebPGetImageReader(WebPGuessImageType(data, data_size));
}

View File

@ -1,67 +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 decode PNG/JPEG/WebP/TIFF/WIC input images.
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_
#define WEBP_IMAGEIO_IMAGE_DEC_H_
#include "webp/types.h"
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include "./metadata.h"
#include "./jpegdec.h"
#include "./pngdec.h"
#include "./pnmdec.h"
#include "./tiffdec.h"
#include "./webpdec.h"
#include "./wicdec.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
WEBP_PNG_FORMAT = 0,
WEBP_JPEG_FORMAT,
WEBP_TIFF_FORMAT,
WEBP_WEBP_FORMAT,
WEBP_PNM_FORMAT,
WEBP_UNSUPPORTED_FORMAT
} WebPInputFileFormat;
// Try to infer the image format. 'data_size' should be larger than 12.
// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely.
WebPInputFileFormat WebPGuessImageType(const uint8_t* const data,
size_t data_size);
// Signature for common image-reading functions (ReadPNG, ReadJPEG, ...)
typedef int (*WebPImageReader)(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic,
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
// suitable reader function. The returned reader is never NULL, but
// unknown formats will return an always-failing valid reader.
WebPImageReader WebPGuessImageReader(const uint8_t* const data,
size_t data_size);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_IMAGEIO_IMAGE_DEC_H_

View File

@ -1,604 +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 <tchar.h>
#include <windows.h>
#include <wincodec.h>
#endif
#include "./imageio_util.h"
#include "../examples/unicode.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(SHCreateStreamOnFile((const LPTSTR)out_file_name,
STGM_WRITE | STGM_CREATE, stream));
}
if (FAILED(hr)) {
_ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"),
(const LPTSTR)out_file_name, hr);
}
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) && !WSTRCMP(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)
: WFOPEN(out_file_name, "wb");
if (fout == NULL) {
WFPRINTF(stderr, "Error opening output file %s\n",
(const W_CHAR*)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,160 +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>
#include "../examples/unicode.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) || !WSTRCMP(file_name, "-");
if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size);
if (data == NULL || data_size == NULL) return 0;
*data = NULL;
*data_size = 0;
in = WFOPEN(file_name, "rb");
if (in == NULL) {
WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)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);
WFPRINTF(stderr, "memory allocation failure when reading file %s\n",
(const W_CHAR*)file_name);
return 0;
}
ok = (fread(file_data, file_size, 1, in) == 1);
fclose(in);
if (!ok) {
WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n",
(int)file_size, (const W_CHAR*)file_name);
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) || !WSTRCMP(file_name, "-");
if (data == NULL) {
return 0;
}
out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb");
if (out == NULL) {
WFPRINTF(stderr, "Error! Cannot open output file '%s'\n",
(const W_CHAR*)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,270 +0,0 @@
// Copyright 2012 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.
// -----------------------------------------------------------------------------
//
// TIFF decode.
#include "./tiffdec.h"
#ifdef HAVE_CONFIG_H
#include "webp/config.h"
#endif
#include <limits.h>
#include <stdio.h>
#include <string.h>
#ifdef WEBP_HAVE_TIFF
#include <tiffio.h>
#include "webp/encode.h"
#include "./imageio_util.h"
#include "./metadata.h"
static const struct {
ttag_t tag;
size_t storage_offset;
} kTIFFMetadataMap[] = {
{ TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) },
{ TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) },
{ 0, 0 },
};
// Returns true on success. The caller must use MetadataFree() on 'metadata' in
// all cases.
static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) {
int i;
toff_t exif_ifd_offset;
for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) {
MetadataPayload* const payload =
(MetadataPayload*)((uint8_t*)metadata +
kTIFFMetadataMap[i].storage_offset);
void* tag_data;
uint32 tag_data_len;
if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) &&
!MetadataCopy((const char*)tag_data, tag_data_len, payload)) {
return 0;
}
}
// TODO(jzern): To extract the raw EXIF directory some parsing of it would be
// necessary to determine the overall size. In addition, value offsets in
// individual directory entries may need to be updated as, depending on the
// type, they are file based.
// Exif 2.2 Section 4.6.2 Tag Structure
// TIFF Revision 6.0 Part 1 Section 2 TIFF Structure #Image File Directory
if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &exif_ifd_offset)) {
fprintf(stderr, "Warning: EXIF extraction from TIFF is unsupported.\n");
}
return 1;
}
// Ad-hoc structure to supply read-from-memory functionalities.
typedef struct {
const uint8_t* data;
toff_t size;
toff_t pos;
} MyData;
static int MyClose(thandle_t opaque) {
(void)opaque;
return 0;
}
static toff_t MySize(thandle_t opaque) {
const MyData* const my_data = (MyData*)opaque;
return my_data->size;
}
static toff_t MySeek(thandle_t opaque, toff_t offset, int whence) {
MyData* const my_data = (MyData*)opaque;
offset += (whence == SEEK_CUR) ? my_data->pos
: (whence == SEEK_SET) ? 0
: my_data->size;
if (offset > my_data->size) return (toff_t)-1;
my_data->pos = offset;
return offset;
}
static int MyMapFile(thandle_t opaque, void** base, toff_t* size) {
(void)opaque;
(void)base;
(void)size;
return 0;
}
static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) {
(void)opaque;
(void)base;
(void)size;
}
static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) {
MyData* const my_data = (MyData*)opaque;
if (my_data->pos + size > my_data->size) {
size = (tsize_t)(my_data->size - my_data->pos);
}
if (size > 0) {
memcpy(dst, my_data->data + my_data->pos, size);
my_data->pos += size;
}
return size;
}
// Unmultiply Argb data. Taken from dsp/alpha_processing
// (we don't want to force a dependency to a libdspdec library).
#define MFIX 24 // 24bit fixed-point arithmetic
#define HALF ((1u << MFIX) >> 1)
static uint32_t Unmult(uint8_t x, uint32_t mult) {
const uint32_t v = (x * mult + HALF) >> MFIX;
return (v > 255u) ? 255u : v;
}
static WEBP_INLINE uint32_t GetScale(uint32_t a) {
return (255u << MFIX) / a;
}
#undef MFIX
#undef HALF
static void MultARGBRow(uint8_t* ptr, int width) {
int x;
for (x = 0; x < width; ++x, ptr += 4) {
const uint32_t alpha = ptr[3];
if (alpha < 255) {
if (alpha == 0) { // alpha == 0
ptr[0] = ptr[1] = ptr[2] = 0;
} else {
const uint32_t scale = GetScale(alpha);
ptr[0] = Unmult(ptr[0], scale);
ptr[1] = Unmult(ptr[1], scale);
ptr[2] = Unmult(ptr[2], scale);
}
}
}
}
int ReadTIFF(const uint8_t* const data, size_t data_size,
WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
MyData my_data = { data, (toff_t)data_size, 0 };
TIFF* tif;
uint32_t width, height;
uint16_t samples_per_px = 0;
uint16_t extra_samples = 0;
uint16_t* extra_samples_ptr = NULL;
uint32_t* raster;
int64_t alloc_size;
int ok = 0;
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) {
fprintf(stderr, "Error! Cannot parse TIFF file\n");
return 0;
}
dircount = TIFFNumberOfDirectories(tif);
if (dircount > 1) {
fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
"Only the first will be used, %d will be ignored.\n",
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) &&
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
goto End;
}
if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)width * height,
sizeof(*raster))) {
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.
alloc_size = (int64_t)((uint64_t)width * height * sizeof(*raster));
if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End;
raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size);
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, width, height, raster,
ORIENTATION_TOPLEFT, 1)) {
const int stride = width * sizeof(*raster);
pic->width = width;
pic->height = height;
// TIFF data is ABGR
#ifdef WORDS_BIGENDIAN
TIFFSwabArrayOfLong(raster, width * height);
#endif
// if we have an alpha channel, we must un-multiply from rgbA to RGBA
if (extra_samples == 1 && extra_samples_ptr != NULL &&
extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) {
uint32_t y;
uint8_t* tmp = (uint8_t*)raster;
for (y = 0; y < height; ++y) {
MultARGBRow(tmp, width);
tmp += stride;
}
}
ok = keep_alpha
? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
: WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
}
_TIFFfree(raster);
} else {
fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
}
if (ok) {
if (metadata != NULL) {
ok = ExtractMetadataFromTIFF(tif, metadata);
if (!ok) {
fprintf(stderr, "Error extracting TIFF metadata!\n");
MetadataFree(metadata);
WebPPictureFree(pic);
}
}
}
End:
TIFFClose(tif);
return ok;
}
#else // !WEBP_HAVE_TIFF
int ReadTIFF(const uint8_t* const data, size_t data_size,
struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)data;
(void)data_size;
(void)pic;
(void)keep_alpha;
(void)metadata;
fprintf(stderr, "TIFF support not compiled. Please install the libtiff "
"development package before building.\n");
return 0;
}
#endif // WEBP_HAVE_TIFF
// -----------------------------------------------------------------------------

View File

@ -1,244 +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 "../examples/unicode.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) {
WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)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

@ -1,11 +1,10 @@
#!/bin/bash #!/bin/bash
# #
# This script generates 'WebP.framework' and 'WebPDecoder.framework'. An iOS # This script generates 'WebP.framework'. An iOS app can decode WebP images
# app can decode WebP images by including 'WebPDecoder.framework' and both # by including 'WebP.framework'.
# encode and decode WebP images by including 'WebP.framework'.
# #
# Run ./iosbuild.sh to generate the frameworks under the current directory # Run ./iosbuild.sh to generate 'WebP.framework' under the current directory
# (the previous build will be erased if it exists). # (previous build will be erased if it exists).
# #
# This script is inspired by the build script written by Carson McDonald. # This script is inspired by the build script written by Carson McDonald.
# (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/). # (http://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/).
@ -13,74 +12,42 @@
set -e set -e
# Extract the latest SDK version from the final field of the form: iphoneosX.Y # Extract the latest SDK version from the final field of the form: iphoneosX.Y
readonly SDK=$(xcodebuild -showsdks \ declare -r SDK=$(xcodebuild -showsdks \
| grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
) )
# Extract Xcode version. declare -r OLDPATH=${PATH}
readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
if [[ -z "${XCODE}" ]]; then
echo "Xcode not available"
exit 1
fi
readonly OLDPATH=${PATH}
# Add iPhoneOS-V6 to the list of platforms below if you need armv6 support. # Add iPhoneOS-V6 to the list of platforms below if you need armv6 support.
# Note that iPhoneOS-V6 support is not available with the iOS6 SDK. # Note that iPhoneOS-V6 support is not available with the iOS6 SDK.
PLATFORMS="iPhoneSimulator iPhoneSimulator64" declare -r PLATFORMS="iPhoneSimulator iPhoneOS-V7 iPhoneOS-V7s"
PLATFORMS+=" iPhoneOS-V7 iPhoneOS-V7s iPhoneOS-V7-arm64" declare -r SRCDIR=$(dirname $0)
readonly PLATFORMS declare -r TOPDIR=$(pwd)
readonly SRCDIR=$(dirname $0) declare -r BUILDDIR="${TOPDIR}/iosbuild"
readonly TOPDIR=$(pwd) declare -r TARGETDIR="${TOPDIR}/WebP.framework"
readonly BUILDDIR="${TOPDIR}/iosbuild" declare -r DEVELOPER=$(xcode-select --print-path)
readonly TARGETDIR="${TOPDIR}/WebP.framework" declare -r PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework" declare -r LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
readonly DEVELOPER=$(xcode-select --print-path)
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
LIBLIST='' LIBLIST=''
DECLIBLIST=''
MUXLIBLIST=''
DEMUXLIBLIST=''
if [[ -z "${SDK}" ]]; then if [[ -z "${SDK}" ]]; then
echo "iOS SDK not available" echo "iOS SDK not available"
exit 1 exit 1
elif [[ ${SDK%%.*} -gt 8 ]]; then elif [[ ${SDK} < 4.0 ]]; then
EXTRA_CFLAGS="-fembed-bitcode" echo "You need iOS SDK version 4.0 or above"
elif [[ ${SDK} < 6.0 ]]; then
echo "You need iOS SDK version 6.0 or above"
exit 1 exit 1
else else
echo "iOS SDK Version ${SDK}" echo "iOS SDK Version ${SDK}"
fi fi
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ rm -rf ${BUILDDIR}
${MUXTARGETDIR} ${DEMUXTARGETDIR} rm -rf ${TARGETDIR}
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \ mkdir -p ${BUILDDIR}
${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/ mkdir -p ${TARGETDIR}/Headers/
if [[ ! -e ${SRCDIR}/configure ]]; then [[ -e ${SRCDIR}/configure ]] || (cd ${SRCDIR} && sh autogen.sh)
if ! (cd ${SRCDIR} && sh autogen.sh); then
cat <<EOT
Error creating configure script!
This script requires the autoconf/automake and libtool to build. MacPorts can
be used to obtain these:
http://www.macports.org/install.php
EOT
exit 1
fi
fi
for PLATFORM in ${PLATFORMS}; do for PLATFORM in ${PLATFORMS}; do
ARCH2="" if [[ "${PLATFORM}" == "iPhoneOS-V7s" ]]; then
if [[ "${PLATFORM}" == "iPhoneOS-V7-arm64" ]]; then
PLATFORM="iPhoneOS"
ARCH="aarch64"
ARCH2="arm64"
elif [[ "${PLATFORM}" == "iPhoneOS-V7s" ]]; then
PLATFORM="iPhoneOS" PLATFORM="iPhoneOS"
ARCH="armv7s" ARCH="armv7s"
elif [[ "${PLATFORM}" == "iPhoneOS-V7" ]]; then elif [[ "${PLATFORM}" == "iPhoneOS-V7" ]]; then
@ -89,9 +56,6 @@ for PLATFORM in ${PLATFORMS}; do
elif [[ "${PLATFORM}" == "iPhoneOS-V6" ]]; then elif [[ "${PLATFORM}" == "iPhoneOS-V6" ]]; then
PLATFORM="iPhoneOS" PLATFORM="iPhoneOS"
ARCH="armv6" ARCH="armv6"
elif [[ "${PLATFORM}" == "iPhoneSimulator64" ]]; then
PLATFORM="iPhoneSimulator"
ARCH="x86_64"
else else
ARCH="i386" ARCH="i386"
fi fi
@ -99,31 +63,25 @@ for PLATFORM in ${PLATFORMS}; do
ROOTDIR="${BUILDDIR}/${PLATFORM}-${SDK}-${ARCH}" ROOTDIR="${BUILDDIR}/${PLATFORM}-${SDK}-${ARCH}"
mkdir -p "${ROOTDIR}" mkdir -p "${ROOTDIR}"
DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain" export DEVROOT="${PLATFORMSROOT}/${PLATFORM}.platform/Developer"
SDKROOT="${PLATFORMSROOT}/" export SDKROOT="${DEVROOT}/SDKs/${PLATFORM}${SDK}.sdk"
SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG"
CFLAGS+=" -miphoneos-version-min=6.0 ${EXTRA_CFLAGS}"
set -x export CFLAGS="-arch ${ARCH} -pipe -isysroot ${SDKROOT}"
export CXXFLAGS=${CFLAGS}
export LDFLAGS="-arch ${ARCH} -pipe -isysroot ${SDKROOT}"
export PATH="${DEVROOT}/usr/bin:${OLDPATH}" export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
${SRCDIR}/configure --host=${ARCH}-apple-darwin --prefix=${ROOTDIR} \ ${SRCDIR}/configure --host=${ARCH}-apple-darwin --prefix=${ROOTDIR} \
--build=$(${SRCDIR}/config.guess) \ --build=$(${SRCDIR}/config.guess) \
--disable-shared --enable-static \ --disable-shared --enable-static \
--enable-libwebpdecoder --enable-swap-16bit-csp \ --enable-libwebpdecoder --enable-swap-16bit-csp
--enable-libwebpmux \
CFLAGS="${CFLAGS}"
set +x
# run make only in the src/ directory to create libwebp.a/libwebpdecoder.a # run make only in the src/ directory to create libwebpdecoder.a
cd src/ cd src/
make V=0 make V=0
make install make install
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a" LIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
make clean make clean
cd .. cd ..
@ -131,20 +89,5 @@ for PLATFORM in ${PLATFORMS}; do
export PATH=${OLDPATH} export PATH=${OLDPATH}
done done
echo "LIBLIST = ${LIBLIST}" cp -a ${SRCDIR}/src/webp/* ${TARGETDIR}/Headers/
cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/
${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP ${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP
echo "DECLIBLIST = ${DECLIBLIST}"
cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/
${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder
echo "MUXLIBLIST = ${MUXLIBLIST}"
cp -a ${SRCDIR}/src/webp/{types,mux,mux_types}.h \
${MUXTARGETDIR}/Headers/
${LIPO} -create ${MUXLIBLIST} -output ${MUXTARGETDIR}/WebPMux
echo "DEMUXLIBLIST = ${DEMUXLIBLIST}"
cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
${DEMUXTARGETDIR}/Headers/
${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux

View File

@ -82,7 +82,7 @@
# modified version of the Autoconf Macro, you may extend this special # modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well. # exception to the GPL to apply to your modified version as well.
#serial 21 #serial 18
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [ AC_DEFUN([AX_PTHREAD], [
@ -103,8 +103,8 @@ if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_LIBS="$LIBS" save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS" LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT([$ax_pthread_ok]) AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS="" PTHREAD_LIBS=""
PTHREAD_CFLAGS="" PTHREAD_CFLAGS=""
@ -164,20 +164,6 @@ case ${host_os} in
;; ;;
esac esac
# Clang doesn't consider unrecognized options an error unless we specify
# -Werror. We throw in some extra Clang-specific options to ensure that
# this doesn't happen for GCC, which also accepts -Werror.
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
save_CFLAGS="$CFLAGS"
ax_pthread_extra_flags="-Werror"
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
[AC_MSG_RESULT([yes])],
[ax_pthread_extra_flags=
AC_MSG_RESULT([no])])
CFLAGS="$save_CFLAGS"
if test x"$ax_pthread_ok" = xno; then if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do for flag in $ax_pthread_flags; do
@ -192,7 +178,7 @@ for flag in $ax_pthread_flags; do
;; ;;
pthread-config) pthread-config)
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
@ -207,7 +193,7 @@ for flag in $ax_pthread_flags; do
save_LIBS="$LIBS" save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS" save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS" LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h, # Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we # since some functions may be macros. (On the Sequent, we
@ -233,7 +219,7 @@ for flag in $ax_pthread_flags; do
LIBS="$save_LIBS" LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS" CFLAGS="$save_CFLAGS"
AC_MSG_RESULT([$ax_pthread_ok]) AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then if test "x$ax_pthread_ok" = xyes; then
break; break;
fi fi
@ -259,9 +245,9 @@ if test "x$ax_pthread_ok" = xyes; then
[attr_name=$attr; break], [attr_name=$attr; break],
[]) [])
done done
AC_MSG_RESULT([$attr_name]) AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant [Define to necessary symbol if this constant
uses a non-standard name on your system.]) uses a non-standard name on your system.])
fi fi
@ -275,54 +261,45 @@ if test "x$ax_pthread_ok" = xyes; then
if test "$GCC" = "yes"; then if test "$GCC" = "yes"; then
flag="-D_REENTRANT" flag="-D_REENTRANT"
else else
# TODO: What about Clang on Solaris?
flag="-mt -D_REENTRANT" flag="-mt -D_REENTRANT"
fi fi
;; ;;
esac esac
AC_MSG_RESULT([$flag]) AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT], [ ax_cv_PTHREAD_PRIO_INHERIT, [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]], AC_LINK_IFELSE([
[[int i = PTHREAD_PRIO_INHERIT;]])], AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no]) [ax_cv_PTHREAD_PRIO_INHERIT=no])
]) ])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
LIBS="$save_LIBS" LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS" CFLAGS="$save_CFLAGS"
# More AIX lossage: compile with *_r variant # More AIX lossage: must compile with xlc_r or cc_r
if test "x$GCC" != xyes; then if test x"$GCC" != xyes; then
case $host_os in AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
aix*) else
AS_CASE(["x/$CC"], PTHREAD_CC=$CC
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi fi
else
PTHREAD_CC="$CC"
fi fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST([PTHREAD_LIBS]) AC_SUBST(PTHREAD_CC)
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
: :
else else
ax_pthread_ok=no ax_pthread_ok=no

View File

@ -2,8 +2,8 @@
# system, for simple local building of the libraries and tools. # system, for simple local building of the libraries and tools.
# 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' and
# 'src/demux/libwebpdemux.a' and 'extras/libwebpextras.a'. # 'src/demux/libwebpdemux.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,228 +51,121 @@ 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
EXTRA_LIBS += -lpthread EXTRA_LIBS += -lpthread
# Control symbol visibility. Comment out if your compiler doesn't support it.
EXTRA_FLAGS += -fvisibility=hidden
# Extra flags to emulate C89 strictness with the full ANSI # Extra flags to emulate C89 strictness with the full ANSI
EXTRA_FLAGS += -Wextra -Wold-style-definition EXTRA_FLAGS += -Wextra -Wold-style-definition
EXTRA_FLAGS += -Wmissing-prototypes EXTRA_FLAGS += -Wmissing-prototypes
EXTRA_FLAGS += -Wmissing-declarations EXTRA_FLAGS += -Wmissing-declarations
EXTRA_FLAGS += -Wdeclaration-after-statement EXTRA_FLAGS += -Wdeclaration-after-statement
EXTRA_FLAGS += -Wshadow EXTRA_FLAGS += -Wshadow
EXTRA_FLAGS += -Wformat-security -Wformat-nonliteral
# EXTRA_FLAGS += -Wvla # EXTRA_FLAGS += -Wvla
# SSE4.1-specific flags:
ifeq ($(HAVE_SSE41), 1)
EXTRA_FLAGS += -DWEBP_HAVE_SSE41
src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1
endif
# NEON-specific flags:
# EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8
# -> seems to make the overall lib slower: -fno-split-wide-types
# MIPS (MSA) 32-bit build specific flags for mips32r5 (p5600):
# EXTRA_FLAGS += -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64
# EXTRA_FLAGS += -msched-weight -mload-store-pairs
# MIPS (MSA) 64-bit build specific flags for mips64r6 (i6400):
# EXTRA_FLAGS += -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64
# EXTRA_FLAGS += -msched-weight -mload-store-pairs
#### Nothing should normally be changed below this line #### #### Nothing should normally be changed below this line ####
AR = ar AR = ar
ARFLAGS = r ARFLAGS = r
CPPFLAGS = -I. -Isrc/ -Wall
ifeq ($(DEBUG), 1)
CFLAGS = -g
else
CFLAGS = -O3 -DNDEBUG
endif
CFLAGS += $(EXTRA_FLAGS)
CC = gcc CC = gcc
CPPFLAGS = -Isrc/ -Wall
CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
INSTALL = install INSTALL = install
GROFF = /usr/bin/groff GROFF = /usr/bin/groff
COL = /usr/bin/col COL = /usr/bin/col
LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm
ifdef BITTRACE
CFLAGS += -DBITTRACE=$(BITTRACE)
endif
ANIM_UTIL_OBJS = \
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/layer.o \
src/dec/tree_dec.o \ src/dec/quant.o \
src/dec/vp8_dec.o \ src/dec/tree.o \
src/dec/vp8l_dec.o \ src/dec/vp8.o \
src/dec/webp_dec.o \ src/dec/vp8l.o \
src/dec/webp.o \
DEMUX_OBJS = \ DEMUX_OBJS = \
src/demux/anim_decode.o \
src/demux/demux.o \ src/demux/demux.o \
DSP_DEC_OBJS = \ DSP_DEC_OBJS = \
src/dsp/alpha_processing.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_sse41.o \
src/dsp/cpu.o \ src/dsp/cpu.o \
src/dsp/dec.o \ src/dsp/dec.o \
src/dsp/dec_clip_tables.o \
src/dsp/dec_mips32.o \
src/dsp/dec_mips_dsp_r2.o \
src/dsp/dec_msa.o \
src/dsp/dec_neon.o \ src/dsp/dec_neon.o \
src/dsp/dec_sse2.o \ src/dsp/dec_sse2.o \
src/dsp/dec_sse41.o \
src/dsp/filters.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/lossless.o \ src/dsp/lossless.o \
src/dsp/lossless_mips_dsp_r2.o \
src/dsp/lossless_msa.o \
src/dsp/lossless_neon.o \
src/dsp/lossless_sse2.o \
src/dsp/rescaler.o \
src/dsp/rescaler_mips32.o \
src/dsp/rescaler_mips_dsp_r2.o \
src/dsp/rescaler_msa.o \
src/dsp/rescaler_neon.o \
src/dsp/rescaler_sse2.o \
src/dsp/upsampling.o \ src/dsp/upsampling.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_mips_dsp_r2.o \
src/dsp/yuv_neon.o \
src/dsp/yuv_sse2.o \
src/dsp/yuv_sse41.o \
DSP_ENC_OBJS = \ DSP_ENC_OBJS = \
src/dsp/cost.o \
src/dsp/cost_mips32.o \
src/dsp/cost_mips_dsp_r2.o \
src/dsp/cost_neon.o \
src/dsp/cost_sse2.o \
src/dsp/enc.o \ src/dsp/enc.o \
src/dsp/enc_mips32.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/lossless_enc.o \
src/dsp/lossless_enc_mips32.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_sse2.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/filter.o \
src/enc/filter_enc.o \ src/enc/frame.o \
src/enc/frame_enc.o \ src/enc/histogram.o \
src/enc/histogram_enc.o \ src/enc/iterator.o \
src/enc/iterator_enc.o \ src/enc/layer.o \
src/enc/near_lossless_enc.o \ src/enc/picture.o \
src/enc/picture_enc.o \ src/enc/quant.o \
src/enc/picture_csp_enc.o \ src/enc/syntax.o \
src/enc/picture_psnr_enc.o \ src/enc/token.o \
src/enc/picture_rescale_enc.o \ src/enc/tree.o \
src/enc/picture_tools_enc.o \ src/enc/vp8l.o \
src/enc/predictor_enc.o \ src/enc/webpenc.o \
src/enc/quant_enc.o \
src/enc/syntax_enc.o \
src/enc/token_enc.o \
src/enc/tree_enc.o \
src/enc/vp8l_enc.o \
src/enc/webp_enc.o \
EX_FORMAT_DEC_OBJS = \ EX_FORMAT_DEC_OBJS = \
imageio/image_dec.o \ examples/jpegdec.o \
imageio/jpegdec.o \ examples/metadata.o \
imageio/metadata.o \ examples/pngdec.o \
imageio/pngdec.o \ examples/tiffdec.o \
imageio/pnmdec.o \
imageio/tiffdec.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 \
GIFDEC_OBJS = \
examples/gifdec.o \
IMAGE_UTIL_OBJS = \
imageio/imageio_util.o \
MUX_OBJS = \ MUX_OBJS = \
src/mux/anim_encode.o \
src/mux/muxedit.o \ src/mux/muxedit.o \
src/mux/muxinternal.o \ src/mux/muxinternal.o \
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/rescaler.o \
src/utils/rescaler_utils.o \ src/utils/thread.o \
src/utils/thread_utils.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 = \
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) \
$(UTILS_ENC_OBJS) $(UTILS_ENC_OBJS)
LIBWEBPMUX_OBJS = $(MUX_OBJS) LIBWEBPMUX_OBJS = $(MUX_OBJS)
LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS)
LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS)
HDRS_INSTALLED = \ HDRS_INSTALLED = \
src/webp/decode.h \ src/webp/decode.h \
@ -296,91 +176,47 @@ HDRS_INSTALLED = \
src/webp/types.h \ src/webp/types.h \
HDRS = \ HDRS = \
src/dec/alphai_dec.h \ src/dec/decode_vp8.h \
src/dec/common_dec.h \ src/dec/vp8i.h \
src/dec/vp8_dec.h \ src/dec/vp8li.h \
src/dec/vp8i_dec.h \ src/dec/webpi.h \
src/dec/vp8li_dec.h \
src/dec/webpi_dec.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/msa_macro.h \
src/dsp/neon.h \
src/dsp/yuv.h \ src/dsp/yuv.h \
src/enc/backward_references_enc.h \ src/enc/cost.h \
src/enc/cost_enc.h \ src/enc/vp8enci.h \
src/enc/histogram_enc.h \ src/utils/bit_reader.h \
src/enc/vp8i_enc.h \ src/utils/bit_writer.h \
src/enc/vp8li_enc.h \ src/utils/color_cache.h \
src/mux/animi.h \ src/utils/filters.h \
src/mux/muxi.h \ src/utils/huffman.h \
src/utils/bit_reader_utils.h \ src/utils/huffman_encode.h \
src/utils/bit_reader_inl_utils.h \ src/utils/quant_levels.h \
src/utils/bit_writer_utils.h \ src/utils/quant_levels_dec.h \
src/utils/color_cache_utils.h \ src/utils/rescaler.h \
src/utils/endian_inl_utils.h \ src/utils/thread.h \
src/utils/filters_utils.h \
src/utils/huffman_utils.h \
src/utils/huffman_encode_utils.h \
src/utils/quant_levels_utils.h \
src/utils/quant_levels_dec_utils.h \
src/utils/random_utils.h \
src/utils/rescaler_utils.h \
src/utils/thread_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
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/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
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)
$(EX_FORMAT_DEC_OBJS): %.o: %.h $(EX_FORMAT_DEC_OBJS): %.o: %.h
# special dependencies:
# tree_dec.c/vp8_dec.c/bit_reader_utils.c <->
# bit_reader_inl_utils.h, endian_inl_utils.h
# bit_writer_utils.c <-> endian_inl_utils.h
src/dec/tree_dec.o: src/utils/bit_reader_inl_utils.h
src/dec/tree_dec.o: src/utils/endian_inl_utils.h
src/dec/vp8_dec.o: src/utils/bit_reader_inl_utils.h src/utils/endian_inl_utils.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/libexample_util.a: $(EX_UTIL_OBJS) examples/libexample_util.a: $(EX_UTIL_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)
@ -389,95 +225,41 @@ src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS)
%.a: %.a:
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS) examples/cwebp: examples/cwebp.o $(EX_FORMAT_DEC_OBJS)
examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS)
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
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: src/demux/libwebpdemux.a examples/libexample_util.a
examples/anim_diff: imageio/libimageio_util.a src/libwebp.a
examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS)
examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF
examples/anim_dump: examples/libanim_util.a examples/libgifdec.a
examples/anim_dump: src/demux/libwebpdemux.a
examples/anim_dump: examples/libexample_util.a
examples/anim_dump: imageio/libimageio_util.a
examples/anim_dump: imageio/libimageenc.a
examples/anim_dump: src/libwebp.a
examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS)
examples/cwebp: examples/libexample_util.a
examples/cwebp: imageio/libimagedec.a
examples/cwebp: src/demux/libwebpdemux.a
examples/cwebp: imageio/libimageio_util.a
examples/cwebp: src/libwebp.a examples/cwebp: src/libwebp.a
examples/cwebp: override 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: EXTRA_LIBS += $(DWEBP_LIBS)
examples/dwebp: src/demux/libwebpdemux.a examples/gif2webp: examples/libexample_util.a src/mux/libwebpmux.a src/libwebp.a
examples/dwebp: imageio/libimageenc.a examples/gif2webp: EXTRA_LIBS += $(GIF_LIBS)
examples/dwebp: imageio/libimageio_util.a
examples/dwebp: src/libwebp.a
examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS)
examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a
examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS)
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: override EXTRA_LIBS += $(GL_LIBS) examples/vwebp: EXTRA_LIBS += $(GL_LIBS)
examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL examples/webpmux: examples/libexample_util.a src/mux/libwebpmux.a
examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a examples/webpmux: src/libwebpdecoder.a
examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a
examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a
examples/img2webp: imageio/libimagedec.a
examples/img2webp: src/demux/libwebpdemux.a
examples/img2webp: src/mux/libwebpmux.a src/libwebp.a
examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS)
examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a
examples/webpinfo: src/libwebpdecoder.a
extras/get_disto: extras/get_disto.o $(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: override 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: override EXTRA_LIBS += $(SDL_LIBS)
$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES):
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)
dist: DESTDIR := dist dist: DESTDIR := dist
dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES) dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES)
dist: all dist: all
$(INSTALL) -m755 -d $(DESTDIR)/include/webp \ $(INSTALL) -m755 -d $(DESTDIR)/include/webp \
$(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib $(DESTDIR)/doc $(DESTDIR)/lib
$(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin $(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)
$(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp $(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp
$(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib $(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib
$(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib $(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib
$(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib $(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib
umask 022; \ umask 022; \
for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \ for m in man/[cd]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; \
@ -486,8 +268,6 @@ 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/*~ \
@ -496,5 +276,19 @@ clean:
src/utils/*.o src/utils/*~ \ src/utils/*.o src/utils/*~ \
src/webp/*~ man/*~ doc/*~ swig/*~ \ src/webp/*~ man/*~ doc/*~ swig/*~ \
.PHONY: all clean dist ex superclean: clean
$(RM) -r .git *.log *.cache *~
$(RM) -r .deps */.deps */*/.deps
$(RM) -r .libs */.libs */*/.libs
$(RM) */*.lo */*/*.lo
$(RM) */*.la */*/*.la
$(RM) Makefile */Makefile */*/Makefile
$(RM) Makefile.in */Makefile.in */*/Makefile.in
$(RM) config.log autom4te.cache libtool config.h stamp-h1
$(RM) aclocal.m4 compile
$(RM) config.guess config.h.in config.sub config.status
$(RM) configure depcomp install-sh ltmain.sh missing src/libwebp.pc
$(RM) m4/*
.PHONY: all clean dist ex superclean
.SUFFIXES: .SUFFIXES:

View File

@ -1,17 +1,8 @@
man_MANS = cwebp.1 dwebp.1 man_MANS = cwebp.1 dwebp.1
if BUILD_MUX if WANT_MUX
man_MANS += webpmux.1 man_MANS += webpmux.1
endif endif
if BUILD_GIF2WEBP if BUILD_GIF2WEBP
man_MANS += gif2webp.1 man_MANS += gif2webp.1
endif endif
if BUILD_IMG2WEBP
man_MANS += img2webp.1
endif
if BUILD_VWEBP
man_MANS += vwebp.1
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 11, 2019" .TH CWEBP 1 "March 13, 2013"
.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
@ -12,19 +12,13 @@ This manual page documents the
command. command.
.PP .PP
\fBcwebp\fP compresses an image using the WebP format. \fBcwebp\fP compresses an image using the WebP format.
Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples. Input format can be either PNG, JPEG, TIFF or raw Y'CbCr samples.
.SH OPTIONS .SH OPTIONS
The basic options are: The basic options are:
.TP .TP
.BI \-o " string .BI \-o " string
Specify the name of the output WebP file. If omitted, \fBcwebp\fP will Specify the name of the output WebP file. If omitted, \fBcwebp\fP will
perform compression but only report statistics. perform compression but only report statistics.
Using "\-" as output name will direct output to 'stdout'.
.TP
.BI \-\- " string
Explicitly specify the input file. This option is useful if the input
file starts with a '\-' for instance. This option must appear \fBlast\fP.
Any other options afterward will be ignored.
.TP .TP
.B \-h, \-help .B \-h, \-help
A short usage summary. A short usage summary.
@ -35,19 +29,6 @@ A summary of all the possible options.
.B \-version .B \-version
Print the version number (as major.minor.revision) and exit. Print the version number (as major.minor.revision) and exit.
.TP .TP
.B \-lossless
Encode the image without any loss. For images with fully transparent area,
the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the
\-exact option is used.
.TP
.BI \-near_lossless " int
Specify the level of near\-lossless image preprocessing. This option adjusts
pixel values to help compressibility, but has minimal impact on the visual
quality. It triggers lossless compression mode automatically. The range is 0
(maximum preprocessing) to 100 (no preprocessing, the default). The typical
value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
better results.
.TP
.BI \-q " float .BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default Specify the compression factor for RGB channels between 0 and 100. The default
is 75. is 75.
@ -55,52 +36,55 @@ is 75.
In case of lossy compression (default), a small factor produces a smaller file In case of lossy compression (default), a small factor produces a smaller file
with lower quality. Best quality is achieved by using a value of 100. with lower quality. Best quality is achieved by using a value of 100.
.br .br
In case of lossless compression (specified by the \fB\-lossless\fP option), a In case of lossless compression (specified by the \-lossless option), a small
small factor enables faster compression speed, but produces a larger file. factor enables faster compression speed, but produces a larger file. Maximum
Maximum compression is achieved by using a value of 100. compression is achieved by using a value of 100.
.TP
.BI \-z " int
Switch on \fBlossless\fP compression mode with the specified level between 0
and 9, with level 0 being the fastest, 9 being the slowest. Fast mode
produces larger file size than slower ones. A good default is \fB\-z 6\fP.
This option is actually a shortcut for some predefined settings for quality
and method. If options \fB\-q\fP or \fB\-m\fP are subsequently used, they will
invalidate the effect of this option.
.TP .TP
.BI \-alpha_q " int .BI \-alpha_q " int
Specify the compression factor for alpha compression between 0 and 100. Specify the compression factor for alpha compression between 0 and 100.
Lossless compression of alpha is achieved using a value of 100, while the lower Lossless compression of alpha is achieved using a value of 100, while the lower
values result in a lossy compression. The default is 100. values result in a lossy compression. The default is 100.
.TP .TP
.BI \-f " int
Specify the strength of the deblocking filter, between 0 (no filtering)
and 100 (maximum filtering). A value of 0 will turn off any filtering.
Higher value will increase the strength of the filtering process applied
after decoding the picture. The higher the value the smoother the picture will
appear. Typical values are usually in the range of 20 to 50.
.TP
.BI \-preset " string .BI \-preset " string
Specify a set of pre\-defined parameters to suit a particular type of Specify a set of pre-defined parameters to suit a particular type of
source material. Possible values are: \fBdefault\fP, \fBphoto\fP, source material. Possible values are: \fBdefault\fP, \fBphoto\fP,
\fBpicture\fP, \fBdrawing\fP, \fBicon\fP, \fBtext\fP. Since \fBpicture\fP, \fBdrawing\fP, \fBicon\fP, \fBtext\fP. Since
\fB\-preset\fP overwrites the other parameters' values (except the \fB\-preset\fP overwrites the other parameters' values (except the
\fB\-q\fP one), this option should preferably appear first in the \fB\-q\fP one), this option should preferably appear first in the
order of the arguments. order of the arguments.
.TP .TP
.BI \-sns " int
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
used to decide which area of the picture should use relatively less bits,
and where else to better transfer these bits. The possible range goes from
0 (algorithm is off) to 100 (the maximal effect). The default value is 80.
.TP
.BI \-m " int .BI \-m " int
Specify the compression method to use. This parameter controls the Specify the compression method to use. This parameter controls the
trade off between encoding speed and the compressed file size and quality. trade off between encoding speed and the compressed file size and quality.
Possible values range from 0 to 6. Default value is 4. Possible values range from 0 to 6. Default value is 4.
When higher values are used, the encoder will spend more time inspecting When higher values are used, the encoder will spend more time inspecting
additional encoding possibilities and decide on the quality gain. additional encoding possibilities and decide on the quality gain.
Lower value can result in faster processing time at the expense of Lower value can result is faster processing time at the expense of
larger file size and lower compression quality. larger file size and lower compression quality.
.TP .TP
.BI \-resize " width height .B \-jpeg_like
Resize the source to a rectangle with size \fBwidth\fP x \fBheight\fP. Change the internal parameter mapping to better match the expected size
If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0, of JPEG compression. This flag will generally produce an output file of
the value will be calculated preserving the aspect\-ratio. similar size to its JPEG equivalent (for the same \fB\-q\fP setting), but
.TP with less visual distortion.
.BI \-crop " x_position y_position width height
Crop the source to a rectangle with top\-left corner at coordinates
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
This cropping area must be fully contained within the source rectangle.
.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
@ -110,50 +94,13 @@ different in size and distortion. This flag is only effective for methods
some side effects on the bitstream: it forces certain bitstream features some side effects on the bitstream: it forces certain bitstream features
like number of partitions (forced to 1). Note that a more detailed report like number of partitions (forced to 1). Note that a more detailed report
of bitstream size is printed by \fBcwebp\fP when using this option. of bitstream size is printed by \fBcwebp\fP when using this option.
.SS LOSSY OPTIONS
These options are only effective when doing lossy encoding (the default, with
or without alpha).
.TP
.BI \-size " int
Specify a target size (in bytes) to try and reach for the compressed output.
The compressor will make several passes of partial encoding in order to get as
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
are used, \fB\-size\fP value will prevail.
.TP
.BI \-psnr " float
Specify a target PSNR (in dB) to try and reach for the compressed output.
The compressor will make several passes of partial encoding in order to get as
close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP
are used, \fB\-size\fP value will prevail.
.TP
.BI \-pass " int
Set a maximum number of passes to use during the dichotomy used by
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
specified, a default value of '6' passes will be used.
.TP .TP
.B \-af .B \-af
Turns auto\-filter on. This algorithm will spend additional time optimizing Turns auto-filter on. This algorithm will spend additional time optimizing
the filtering strength to reach a well\-balanced quality. the filtering strength to reach a well-balanced quality.
.TP
.B \-jpeg_like
Change the internal parameter mapping to better match the expected size
of JPEG compression. This flag will generally produce an output file of
similar size to its JPEG equivalent (for the same \fB\-q\fP setting), but
with less visual distortion.
.TP .SH ADDITIONAL OPTIONS
Advanced options: More advanced options are:
.TP
.BI \-f " int
Specify the strength of the deblocking filter, between 0 (no filtering)
and 100 (maximum filtering). A value of 0 will turn off any filtering.
Higher value will increase the strength of the filtering process applied
after decoding the picture. The higher the value the smoother the picture will
appear. Typical values are usually in the range of 20 to 50.
.TP .TP
.BI \-sharpness " int .BI \-sharpness " int
Specify the sharpness of the filtering (if used). Specify the sharpness of the filtering (if used).
@ -167,17 +114,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
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
used to decide which area of the picture should use relatively less bits,
and where else to better transfer these bits. The possible range goes from
0 (algorithm is off) to 100 (the maximal effect). The default value is 50.
.TP
.BI \-segments " int .BI \-segments " int
Change the number of partitions to use during the segmentation of the Change the number of partitions to use during the segmentation of the
sns algorithm. Segments should be in range 1 to 4. Default value is 4. sns algorithm. Segments should be in range 1 to 4. Default value is 4.
@ -187,30 +123,96 @@ is used.
.BI \-partition_limit " int .BI \-partition_limit " int
Degrade quality by limiting the number of bits used by some macroblocks. Degrade quality by limiting the number of bits used by some macroblocks.
Range is 0 (no degradation, the default) to 100 (full degradation). Range is 0 (no degradation, the default) to 100 (full degradation).
Useful values are usually around 30\-70 for moderately large images. Useful values are usually around 30-70 for moderately large images.
In the VP8 format, the so\-called control partition has a limit of 512k and In the VP8 format, the so-called control partition has a limit of 512k and
is used to store the following information: whether the macroblock is skipped, is used to store the following information: whether the macroblock is skipped,
which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16 which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
mode, and finally the prediction modes to use for each of the sub\-blocks. mode, and finally the prediction modes to use for each of the sub-blocks.
For a very large image, 512k only leaves room to few bits per 16x16 macroblock. For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
The absolute minimum is 4 bits per macroblock. Skip, segment, and mode The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
information can use up almost all these 4 bits (although the case is unlikely), information can use up almost all these 4 bits (although the case is unlikely),
which is problematic for very large images. The partition_limit factor controls which is problematic for very large images. The partition_limit factor controls
how frequently the most bit\-costly mode (intra 4x4) will be used. This is how frequently the most bit-costly mode (intra 4x4) will be used. This is
useful in case the 512k limit is reached and the following message is displayed: useful in case the 512k limit is reached and the following message is displayed:
\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP. \fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one If using \fB-partition_limit\fP is not enough to meet the 512k constraint, one
should use less segments in order to save more header bits per macroblock. should use less segments in order to save more header bits per macroblock.
See the \fB\-segments\fP option. See the \fB-segments\fP option.
.TP
.BI \-size " int
Specify a target size (in bytes) to try and reach for the compressed output.
Compressor will make several pass of partial encoding in order to get as
close as possible to this target.
.TP
.BI \-psnr " float
Specify a target PSNR (in dB) to try and reach for the compressed output.
Compressor will make several pass of partial encoding in order to get as
close as possible to this target.
.TP
.BI \-pass " int
Set a maximum number of passes to use during the dichotomy used by
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10.
.TP
.BI \-crop " x_position y_position width height
Crop the source to a rectangle with top-left corner at coordinates
(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP.
This cropping area must be fully contained within the source rectangle.
.TP
.BI \-s " width height
Specify that the input file actually consists of raw Y'CbCr samples following
the ITU-R BT.601 recommendation, in 4:2:0 linear format.
The luma plane has size \fBwidth\fP x \fBheight\fP.
.TP
.BI \-map " int
Output additional ASCII-map of encoding information. Possible map values
range from 1 to 6. This is only meant to help debugging.
.TP
.BI \-pre " int
Specify a pre-processing filter. This option is a placeholder
and has currently no effect.
.TP
.BI \-alpha_filter " string
Specify the predictive filtering method for the alpha plane. One of 'none',
\&'fast' or 'best', in increasing complexity and slowness order. Default is
\&'fast'. Internally, alpha filtering is performed using four possible
predictions (none, horizontal, vertical, gradient). The 'best' mode will try
each mode in turn and pick the one which gives the smaller size. The 'fast'
mode will just try to form an a-priori guess without testing all modes.
.TP
.BI \-alpha_method " int
Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes
no compression, 1 uses WebP lossless format for compression. The default is 1.
.TP
.B \-alpha_cleanup
Modify unseen RGB values under fully transparent area, to help compressibility.
The default is off.
.TP
.B \-noalpha
Using this option will discard the alpha channel.
.TP
.B \-lossless
Encode the image without any loss.
.TP
.BI \-hint " string
Specify the hint about input image type. Possible values are:
\fBphoto\fP, \fBpicture\fP or \fBgraph\fP.
.TP
.BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if
present.
Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBnone\fP.
.SS LOGGING OPTIONS Note: each input format may not support all combinations.
These options control the level of output: .TP
.B \-noasm
Disable all assembly optimizations.
.TP .TP
.B \-v .B \-v
Print extra information (encoding time in particular). Print extra information (encoding time in particular).
.TP .TP
.B \-print_psnr .B \-print_psnr
Compute and report average PSNR (Peak\-Signal\-To\-Noise ratio). Compute and report average PSNR (Peak-Signal-To-Noise ratio).
.TP .TP
.B \-print_ssim .B \-print_ssim
Compute and report average SSIM (structural similarity Compute and report average SSIM (structural similarity
@ -227,70 +229,14 @@ Report encoding progress in percent.
Do not print anything. Do not print anything.
.TP .TP
.B \-short .B \-short
Only print brief information (output file size and PSNR) for testing purposes. Only print brief information (output file size and PSNR) for testing purpose.
.TP
.BI \-map " int
Output additional ASCII\-map of encoding information. Possible map values
range from 1 to 6. This is only meant to help debugging.
.SS ADDITIONAL OPTIONS
More advanced options are:
.TP
.BI \-s " width height
Specify that the input file actually consists of raw Y'CbCr samples following
the ITU\-R BT.601 recommendation, in 4:2:0 linear format.
The luma plane has size \fBwidth\fP x \fBheight\fP.
.TP
.BI \-pre " int
Specify some preprocessing steps. Using a value of '2' will trigger
quality\-dependent pseudo\-random dithering during RGBA\->YUVA conversion
(lossy compression only).
.TP
.BI \-alpha_filter " string
Specify the predictive filtering method for the alpha plane. One of 'none',
\&'fast' or 'best', in increasing complexity and slowness order. Default is
\&'fast'. Internally, alpha filtering is performed using four possible
predictions (none, horizontal, vertical, gradient). The 'best' mode will try
each mode in turn and pick the one which gives the smaller size. The 'fast'
mode will just try to form an a priori guess without testing all modes.
.TP
.BI \-alpha_method " int
Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes
no compression, 1 uses WebP lossless format for compression. The default is 1.
.TP
.B \-exact
Preserve RGB values in transparent area. The default is off, to help
compressibility.
.TP
.BI \-blend_alpha " int
This option blends the alpha channel (if present) with the source using the
background color specified in hexadecimal as 0xrrggbb. The alpha channel is
afterward reset to the opaque value 255.
.TP
.B \-noalpha
Using this option will discard the alpha channel.
.TP
.BI \-hint " string
Specify the hint about input image type. Possible values are:
\fBphoto\fP, \fBpicture\fP or \fBgraph\fP.
.TP
.BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if
present.
Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBnone\fP.
Note: each input format may not support all combinations.
.TP
.B \-noasm
Disable all assembly optimizations.
.SH BUGS .SH BUGS
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
.br .br
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting\-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES .SH EXAMPLES
cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
@ -298,21 +244,18 @@ cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp
cwebp \-q 70 picture_with_alpha.png \-o picture_with_alpha.webp cwebp \-q 70 picture_with_alpha.png \-o picture_with_alpha.webp
.br .br
cwebp \-sns 70 \-f 50 \-size 60000 picture.png \-o picture.webp cwebp \-sns 70 \-f 50 \-size 60000 picture.png \-o picture.webp
.br
cwebp \-o picture.webp \-\- \-\-\-picture.png
.SH AUTHORS .SH AUTHORS
\fBcwebp\fP is a part of libwebp and was written by the WebP team. \fBcwebp\fP was written by the WebP team.
.br .br
The latest source tree is available at The latest source tree is available at http://www.webmproject.org/code
https://chromium.googlesource.com/webm/libwebp
.PP .PP
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>, This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others). for the Debian project (and may be used by others).
.SH SEE ALSO .SH SEE ALSO
.BR dwebp (1), .BR dwebp (1),
.BR gif2webp (1) .BR gif2webp (1).
.br .br
Please refer to http://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH DWEBP 1 "June 23, 2016" .TH DWEBP 1 "February 01, 2013"
.SH NAME .SH NAME
dwebp \- decompress a WebP file to an image file dwebp \- decompress a WebP file to an image file
.SH SYNOPSIS .SH SYNOPSIS
@ -23,19 +23,6 @@ Print the version number (as major.minor.revision) and exit.
.TP .TP
.BI \-o " string .BI \-o " string
Specify the name of the output file (as PNG format by default). Specify the name of the output file (as PNG format by default).
Using "-" as output name will direct output to 'stdout'.
.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 \-bmp
Change the output format to uncompressed BMP.
.TP
.B \-tiff
Change the output format to uncompressed TIFF.
.TP .TP
.B \-pam .B \-pam
Change the output format to PAM (retains alpha). Change the output format to PAM (retains alpha).
@ -45,7 +32,7 @@ Change the output format to PPM (discards alpha).
.TP .TP
.B \-pgm .B \-pgm
Change the output format to PGM. The output consists of luma/chroma Change the output format to PGM. The output consists of luma/chroma
samples instead of RGB, using the IMC4 layout. This option is mainly samples instead of RGB, using the ICM4 layout. This option is mainly
for verification and debugging purposes. for verification and debugging purposes.
.TP .TP
.B \-yuv .B \-yuv
@ -61,20 +48,7 @@ edges (especially the red ones), but should be faster.
.B \-nofilter .B \-nofilter
Don't use the in-loop filtering process even if it is required by Don't use the in-loop filtering process even if it is required by
the bitstream. This may produce visible blocks on the non-compliant output, the bitstream. This may produce visible blocks on the non-compliant output,
but it will make the decoding faster. but will make the decoding faster.
.TP
.BI \-dither " strength
Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a
post-processing effect applied to chroma components in lossy compression.
It helps by smoothing gradients and avoiding banding artifacts.
.TP
.BI \-alpha_dither
If the compressed file contains a transparency plane that was quantized
during compression, this flag will allow dithering the reconstructed plane
in order to generate smoother transparency gradients.
.TP
.B \-nodither
Disable all dithering (default).
.TP .TP
.B \-mt .B \-mt
Use multi-threading for decoding, if possible. Use multi-threading for decoding, if possible.
@ -87,19 +61,11 @@ The top-left corner will be snapped to even coordinates if needed.
This option is meant to reduce the memory needed for cropping large images. This option is meant to reduce the memory needed for cropping large images.
Note: the cropping is applied \fIbefore\fP any scaling. Note: the cropping is applied \fIbefore\fP any scaling.
.TP .TP
.B \-flip .BI \-scale " width height
Flip decoded image vertically (can be useful for OpenGL textures for instance).
.TP
\fB\-resize\fR, \fB\-scale\fI width height\fR
Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This
option is mostly intended to reducing the memory needed to decode large images, option is mostly intended to reducing the memory needed to decode large images,
when only a small version is needed (thumbnail, preview, etc.). Note: scaling when only a small version is needed (thumbnail, preview, etc.). Note: scaling
is applied \fIafter\fP cropping. is applied \fIafter\fP cropping.
If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0,
the value will be calculated preserving the aspect-ratio.
.TP
.B \-quiet
Do not print anything.
.TP .TP
.B \-v .B \-v
Print extra information (decoding time in particular). Print extra information (decoding time in particular).
@ -108,8 +74,8 @@ Print extra information (decoding time in particular).
Disable all assembly optimizations. Disable all assembly optimizations.
.SH BUGS .SH BUGS
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
.br .br
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
@ -118,24 +84,19 @@ http://www.webmproject.org/code/contribute/submitting-patches/
dwebp picture.webp \-o output.png dwebp picture.webp \-o output.png
.br .br
dwebp picture.webp \-ppm \-o output.ppm dwebp picture.webp \-ppm \-o output.ppm
.br
dwebp \-o output.ppm \-\- \-\-\-picture.webp
.br
cat picture.webp | dwebp \-o \- \-\- \- > output.ppm
.SH AUTHORS .SH AUTHORS
\fBdwebp\fP is a part of libwebp and was written by the WebP team. \fBdwebp\fP was written by the WebP team.
.br .br
The latest source tree is available at The latest source tree is available at http://www.webmproject.org/code
https://chromium.googlesource.com/webm/libwebp
.PP .PP
This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>, This manual page was written by Pascal Massimino <pascal.massimino@gmail.com>,
for the Debian project (and may be used by others). for the Debian project (and may be used by others).
.SH SEE ALSO .SH SEE ALSO
.BR cwebp (1), .BR cwebp (1),
.BR gif2webp (1), .BR webpmux (1),
.BR webpmux (1) .BR gif2webp (1).
.br .br
Please refer to http://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

View File

@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH GIF2WEBP 1 "January 25, 2018" .TH GIF2WEBP 1 "February 01, 2013"
.SH NAME .SH NAME
gif2webp \- Convert a GIF image to WebP gif2webp \- Convert a GIF image to WebP
.SH SYNOPSIS .SH SYNOPSIS
@ -18,13 +18,6 @@ The basic options are:
.BI \-o " string .BI \-o " string
Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will 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'.
.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 .TP
.B \-h, \-help .B \-h, \-help
Usage information. Usage information.
@ -35,10 +28,6 @@ Print the version number (as major.minor.revision) and exit.
.B \-lossy .B \-lossy
Encode the image using lossy compression. Encode the image using lossy compression.
.TP .TP
.B \-mixed
Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically.
.TP
.BI \-q " float .BI \-q " float
Specify the compression factor for RGB channels between 0 and 100. The default Specify the compression factor for RGB channels between 0 and 100. The default
is 75. is 75.
@ -60,51 +49,6 @@ additional encoding possibilities and decide on the quality gain.
Lower value can result is faster processing time at the expense of Lower value can result is faster processing time at the expense of
larger file size and lower compression quality. larger file size and lower compression quality.
.TP .TP
.BI \-min_size
Encode image to achieve smallest size. This disables key frame insertion and
picks the dispose method 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
A 'kmax' value of 0 will turn off insertion of key frames. A 'kmax' value of 1
will result in all frames being key frames. 'kmin' value is not taken into
account in both these special cases.
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.
.br
These two options are relevant only for animated images with large number of
frames (>50).
.br
When lower values are used, more frames will be converted to key frames. This
may lead to smaller number of frames required to decode a frame on average,
thereby improving the decoding performance. But this may lead to slightly bigger
file sizes.
Higher values may lead to worse decoding performance, but smaller file sizes.
.br
Some restrictions:
.br
(i) kmin < kmax,
.br
(ii) kmin >= kmax / 2 + 1 and
.br
(iii) kmax - kmin <= 30.
.br
If any of these restrictions are not met, they will be enforced automatically.
.TP
.BI \-metadata " string
A comma separated list of metadata to copy from the input to the output if
present.
Valid values: \fBall\fP, \fBnone\fP, \fBicc\fP, \fBxmp\fP.
The default is \fBxmp\fP.
.TP
.BI \-f " int .BI \-f " int
For lossy encoding only (specified by the \-lossy option). Specify the strength For lossy encoding only (specified by the \-lossy option). Specify the strength
of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering). of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).
@ -113,13 +57,6 @@ strength of the filtering process applied after decoding the picture. The higher
the value the smoother the picture will appear. Typical values are usually in 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
Use multi-threading for encoding, if possible.
.TP
.B \-loop_compatibility
If enabled, handle the loop information in a compatible fashion for Chrome
version prior to M62 (inclusive) and Firefox.
.TP
.B \-v .B \-v
Print extra information. Print extra information.
.TP .TP
@ -127,8 +64,8 @@ Print extra information.
Do not print anything. Do not print anything.
.SH BUGS .SH BUGS
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
.br .br
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
@ -141,24 +78,19 @@ gif2webp \-q 70 picture.gif \-o picture.webp
gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp
.br .br
gif2webp \-lossy \-f 50 picture.gif \-o picture.webp gif2webp \-lossy \-f 50 picture.gif \-o picture.webp
.br
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 was written by the WebP team.
.br .br
The latest source tree is available at The latest source tree is available at http://www.webmproject.org/code
https://chromium.googlesource.com/webm/libwebp
.PP .PP
This manual page was written by Urvang Joshi <urvang@google.com>, for the This manual page was written by Urvang Joshi <urvang@google.com>, for the
Debian project (and may be used by others). Debian project (and may be used by others).
.SH SEE ALSO .SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1), .BR dwebp (1),
.BR webpmux (1) .BR cwebp (1),
.BR webpmux (1).
.br .br
Please refer to http://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

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,101 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.TH VWEBP 1 "June 5, 2019"
.SH NAME
vwebp \- decompress a WebP file and display it in a window
.SH SYNOPSIS
.B vwebp
.RI [ options ] " input_file.webp
.br
.SH DESCRIPTION
This manual page documents the
.B vwebp
command.
.PP
\fBvwebp\fP decompresses a WebP file and displays it in a window using OpenGL.
.SH OPTIONS
.TP
.B \-h
Print usage summary.
.TP
.B \-version
Print version number and exit.
.TP
.B \-noicc
Don't use the ICC profile if present.
.TP
.B \-nofancy
Don't use the fancy YUV420 upscaler.
.TP
.B \-nofilter
Disable in-loop filtering.
.TP
.BI \-dither " strength
Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a
post-processing effect applied to chroma components in lossy compression.
It helps by smoothing gradients and avoiding banding artifacts. Default: 50.
.TP
.BI \-noalphadither
By default, quantized transparency planes are dithered during decompression,
to smooth the gradients. This flag will prevent this dithering.
.TP
.B \-usebgcolor
Fill transparent areas with the bitstream's own background color instead of
checkerboard only. Default is white for non-animated images.
.TP
.B \-mt
Use multi-threading for decoding, if possible.
.TP
.B \-info
Display image information on top of the decoded image.
.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
.SH KEYBOARD SHORTCUTS
.TP
.B 'c'
Toggle use of color profile.
.TP
.B 'b'
Toggle display of background color.
.TP
.B 'i'
Overlay file information.
.TP
.B 'd'
Disable blending and disposal process, for debugging purposes.
.TP
.B 'q' / 'Q' / ESC
Quit.
.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
vwebp picture.webp
.br
vwebp picture.webp -mt -dither 0
.br
vwebp \-\- \-\-\-picture.webp
.SH AUTHORS
\fBvwebp\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 for the Debian project (and may be used by others).
.SH SEE ALSO
.BR dwebp (1)
.br
Please refer to http://developers.google.com/speed/webp/ for additional
information.

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,8 +1,7 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.TH WEBPMUX 1 "April 23, 2018" .TH WEBPMUX 1 "March 16, 2013"
.SH NAME .SH NAME
webpmux \- create animated WebP files from non\-animated WebP images, extract webpmux \- command line tool to create WebP Mux/container file.
frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile.
.SH SYNOPSIS .SH SYNOPSIS
.B webpmux \-get .B webpmux \-get
.I GET_OPTIONS .I GET_OPTIONS
@ -35,31 +34,19 @@ 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
command. 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 a WebP container file
to add/extract/strip XMP/EXIF metadata and ICC profile. and extract/strip relevant data from the container file.
If a single file name (not starting with the character '\-') is supplied as
the argument, the command line arguments are actually tokenized from this file.
This allows for easy scripting or using large number of arguments.
.SH OPTIONS .SH OPTIONS
.SS GET_OPTIONS (\-get): .SS GET_OPTIONS (\-get):
.TP .TP
@ -73,7 +60,7 @@ Get EXIF metadata.
Get XMP metadata. Get XMP metadata.
.TP .TP
.BI frame " n .BI frame " n
Get nth frame from an animated image. (n = 0 has a special meaning: last frame). Get nth frame.
.SS SET_OPTIONS (\-set) .SS SET_OPTIONS (\-set)
.TP .TP
@ -103,53 +90,14 @@ 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.
.TP .TP
.I file_i +di[+xi+yi[+mi[bi]]] .I file_i +di[+xi+yi[+mi]]
Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image
offset for this frame, 'di' is the pause duration before next frame, 'mi' is offset for this frame, 'di' is the pause duration before next frame and 'mi' is
the dispose method for this frame (0 for NONE or 1 for BACKGROUND) and 'bi' is the dispose method for this frame (0 for NONE or 1 for BACKGROUND).
the blending method for this frame (+b for BLEND or \-b for NO_BLEND). 'mi' can be omitted and will default to 0 (NONE).
Argument 'bi' can be omitted and will default to +b (BLEND). Additionally, if 'mi' is ommitted then'xi' and 'yi' can be omitted and will
Also, 'mi' can be omitted if 'bi' is omitted and will default to 0 (NONE).
Finally, if 'mi' and 'bi' are omitted then 'xi' and 'yi' can be omitted and will
default to +0+0. default to +0+0.
.TP .TP
.BI \-loop " n .BI \-loop " n
@ -176,85 +124,51 @@ Output file in WebP format.
The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid. The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid.
.SH BUGS .SH BUGS
Please report all bugs to the issue tracker: Please report all bugs to our issue tracker:
https://bugs.chromium.org/p/webp http://code.google.com/p/webp/issues
.br .br
Patches welcome! See this page to get started: Patches welcome! See this page to get started:
http://www.webmproject.org/code/contribute/submitting\-patches/ http://www.webmproject.org/code/contribute/submitting-patches/
.SH EXAMPLES .SH EXAMPLES
.P
Add ICC profile:
.br
webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp
.P
Extract ICC profile:
.br .br
webpmux \-get icc icc_container.webp \-o image_profile.icc webpmux \-get icc icc_container.webp \-o image_profile.icc
.P
Strip ICC profile:
.br .br
webpmux \-strip icc icc_container.webp \-o without_icc.webp webpmux \-strip icc icc_container.webp \-o without_icc.webp
.P
Add XMP metadata:
.br .br
webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp
.P
Extract XMP metadata:
.br .br
webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp
.P
Strip XMP metadata:
.br .br
webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp
.P
Add EXIF metadata:
.br .br
webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp
.P
Extract EXIF metadata:
.br .br
webpmux \-get exif exif_container.webp \-o image_metadata.exif webpmux \-get exif exif_container.webp \-o image_metadata.exif
.P
Strip EXIF metadata:
.br .br
webpmux \-strip exif exif_container.webp \-o without_exif.webp webpmux \-strip exif exif_container.webp \-o without_exif.webp
.P
Create an animated WebP file from 3 (non\-animated) WebP images:
.br .br
webpmux \-frame 1.webp +100 \-frame 2.webp +100+50+50 webpmux \-frame anim_1.webp +100 \-frame anim_2.webp +100+50+50 \-loop 10
.br .br
.RS 8 .RS 8
\-frame 3.webp +100+50+50+1+b \-loop 10 \-bgcolor 255,255,255,255 \-bgcolor 255,255,255,255 \-o anim_container.webp
.br
\-o anim_container.webp
.RE .RE
.P
Get the 2nd frame from an animated WebP file:
.br .br
webpmux \-get frame 2 anim_container.webp \-o frame_2.webp webpmux \-get frame 2 anim_container.webp \-o frame_2.webp
.P
Using \-get/\-set/\-strip with input file name starting with '\-':
.br
webpmux \-set icc image_profile.icc \-o icc_container.webp \-\- \-\-\-in.webp
.br
webpmux \-get icc \-o image_profile.icc \-\- \-\-\-icc_container.webp
.br
webpmux \-strip icc \-o without_icc.webp \-\- \-\-\-icc_container.webp
.SH AUTHORS .SH AUTHORS
\fBwebpmux\fP is a part of libwebp and was written by the WebP team. \fBwebpmux\fP is written by the WebP team.
.br .br
The latest source tree is available at The latest source tree is available at http://www.webmproject.org/code
https://chromium.googlesource.com/webm/libwebp
.PP .PP
This manual page was written by Vikas Arora <vikaas.arora@gmail.com>, This manual page was written by Vikas Arora <vikaas.arora@gmail.com>,
for the Debian project (and may be used by others). for the Debian project (and may be used by others).
.SH SEE ALSO .SH SEE ALSO
.BR cwebp (1),
.BR dwebp (1), .BR dwebp (1),
.BR gif2webp (1) .BR cwebp (1),
.BR gif2webp (1).
.br .br
Please refer to http://developers.google.com/speed/webp/ for additional Please refer to http://developers.google.com/speed/webp/ for additional
information. information.

1
src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/*.pc

View File

@ -1,13 +1,14 @@
# The mux and demux libraries depend on libwebp, thus the '.' to force # The mux and demux libraries depend on libwebp, thus the '.' to force the
# the build order so it's available to them. # build order so it's available to them.
SUBDIRS = dec enc dsp utils . SUBDIRS = dec enc dsp utils .
if BUILD_MUX if WANT_MUX
SUBDIRS += mux SUBDIRS += mux
endif endif
if BUILD_DEMUX if WANT_DEMUX
SUBDIRS += demux SUBDIRS += demux
endif endif
AM_CPPFLAGS = -I$(top_srcdir)/src
lib_LTLIBRARIES = libwebp.la lib_LTLIBRARIES = libwebp.la
if BUILD_LIBWEBPDECODER if BUILD_LIBWEBPDECODER
@ -22,7 +23,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 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
# other than the ones listed on the command line, i.e., after linking, it will # other than the ones listed on the command line, i.e., after linking, it will
# not have unresolved symbols. Some platforms (Windows among them) require all # not have unresolved symbols. Some platforms (Windows among them) require all
# symbols in shared libraries to be resolved at library creation. # symbols in shared libraries to be resolved at library creation.
libwebp_la_LDFLAGS = -no-undefined -version-info 7:5:0 libwebp_la_LDFLAGS = -no-undefined -version-info 4:3:0
libwebpincludedir = $(includedir)/webp libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc pkgconfig_DATA = libwebp.pc
@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 3:5:0 libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 0:1: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) AM_CPPFLAGS = -I$(top_srcdir)/src
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 += buffer.c
libwebpdecode_la_SOURCES += buffer_dec.c libwebpdecode_la_SOURCES += decode_vp8.h
libwebpdecode_la_SOURCES += common_dec.h libwebpdecode_la_SOURCES += frame.c
libwebpdecode_la_SOURCES += vp8_dec.h libwebpdecode_la_SOURCES += idec.c
libwebpdecode_la_SOURCES += frame_dec.c libwebpdecode_la_SOURCES += io.c
libwebpdecode_la_SOURCES += idec_dec.c libwebpdecode_la_SOURCES += layer.c
libwebpdecode_la_SOURCES += io_dec.c libwebpdecode_la_SOURCES += quant.c
libwebpdecode_la_SOURCES += quant_dec.c libwebpdecode_la_SOURCES += tree.c
libwebpdecode_la_SOURCES += tree_dec.c libwebpdecode_la_SOURCES += vp8.c
libwebpdecode_la_SOURCES += vp8_dec.c libwebpdecode_la_SOURCES += vp8i.h
libwebpdecode_la_SOURCES += vp8i_dec.h libwebpdecode_la_SOURCES += vp8l.c
libwebpdecode_la_SOURCES += vp8l_dec.c libwebpdecode_la_SOURCES += vp8li.h
libwebpdecode_la_SOURCES += vp8li_dec.h libwebpdecode_la_SOURCES += webp.c
libwebpdecode_la_SOURCES += webp_dec.c libwebpdecode_la_SOURCES += webpi.h
libwebpdecode_la_SOURCES += webpi_dec.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 = $(USE_EXPERIMENTAL_CODE)
libwebpdecodeincludedir = $(includedir)/webp libwebpdecodeincludedir = $(includedir)/webp

115
src/dec/alpha.c Normal file
View File

@ -0,0 +1,115 @@
// Copyright 2011 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.
// -----------------------------------------------------------------------------
//
// Alpha-plane decompression.
//
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include "./vp8i.h"
#include "./vp8li.h"
#include "../utils/filters.h"
#include "../utils/quant_levels_dec.h"
#include "../webp/format_constants.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Decodes the compressed data 'data' of size 'data_size' into the 'output'.
// The 'output' buffer should be pre-allocated and must be of the same
// dimension 'height'x'width', as that of the image.
//
// Returns 1 on successfully decoding the compressed alpha and
// 0 if either:
// error in bit-stream header (invalid compression mode or filter), or
// error returned by appropriate compression method.
static int DecodeAlpha(const uint8_t* data, size_t data_size,
int width, int height, uint8_t* output) {
WEBP_FILTER_TYPE filter;
int pre_processing;
int rsrv;
int ok = 0;
int method;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
assert(width > 0 && height > 0);
assert(data != NULL && output != NULL);
if (data_size <= ALPHA_HEADER_LEN) {
return 0;
}
method = (data[0] >> 0) & 0x03;
filter = (data[0] >> 2) & 0x03;
pre_processing = (data[0] >> 4) & 0x03;
rsrv = (data[0] >> 6) & 0x03;
if (method < ALPHA_NO_COMPRESSION ||
method > ALPHA_LOSSLESS_COMPRESSION ||
filter >= WEBP_FILTER_LAST ||
pre_processing > ALPHA_PREPROCESSED_LEVELS ||
rsrv != 0) {
return 0;
}
if (method == ALPHA_NO_COMPRESSION) {
const size_t alpha_decoded_size = height * width;
ok = (alpha_data_size >= alpha_decoded_size);
if (ok) memcpy(output, alpha_data, alpha_decoded_size);
} else {
ok = VP8LDecodeAlphaImageStream(width, height, alpha_data, alpha_data_size,
output);
}
if (ok) {
WebPUnfilterFunc unfilter_func = WebPUnfilters[filter];
if (unfilter_func != NULL) {
// TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode
// and apply filter per image-row.
unfilter_func(width, height, width, output);
}
if (pre_processing == ALPHA_PREPROCESSED_LEVELS) {
ok = DequantizeLevels(output, width, height);
}
}
return ok;
}
//------------------------------------------------------------------------------
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
int row, int num_rows) {
const int width = dec->pic_hdr_.width_;
const int height = dec->pic_hdr_.height_;
if (row < 0 || num_rows < 0 || row + num_rows > height) {
return NULL; // sanity check.
}
if (row == 0) {
// Decode everything during the first call.
assert(!dec->is_alpha_decoded_);
if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_,
width, height, dec->alpha_plane_)) {
return NULL; // Error.
}
dec->is_alpha_decoded_ = 1;
}
// Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,232 +0,0 @@
// Copyright 2011 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.
// -----------------------------------------------------------------------------
//
// Alpha-plane decompression.
//
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
// Allocates a new alpha decoder instance.
static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec;
}
// Clears and deallocates an alpha decoder instance.
static void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_);
dec->vp8l_dec_ = NULL;
WebPSafeFree(dec);
}
}
//------------------------------------------------------------------------------
// Decoding.
// Initialize alpha decoding by parsing the alpha header and decoding the image
// header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc).
static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
size_t data_size, const VP8Io* const src_io,
uint8_t* output) {
int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
int rsrv;
VP8Io* const io = &dec->io_;
assert(data != NULL && output != NULL && src_io != NULL);
VP8FiltersInit();
dec->output_ = output;
dec->width_ = src_io->width;
dec->height_ = src_io->height;
assert(dec->width_ > 0 && dec->height_ > 0);
if (data_size <= ALPHA_HEADER_LEN) {
return 0;
}
dec->method_ = (data[0] >> 0) & 0x03;
dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
dec->pre_processing_ = (data[0] >> 4) & 0x03;
rsrv = (data[0] >> 6) & 0x03;
if (dec->method_ < ALPHA_NO_COMPRESSION ||
dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
dec->filter_ >= WEBP_FILTER_LAST ||
dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
rsrv != 0) {
return 0;
}
// Copy the necessary parameters from src_io to io
VP8InitIo(io);
WebPInitCustomIo(NULL, io);
io->opaque = dec;
io->width = src_io->width;
io->height = src_io->height;
io->use_cropping = src_io->use_cropping;
io->crop_left = src_io->crop_left;
io->crop_right = src_io->crop_right;
io->crop_top = src_io->crop_top;
io->crop_bottom = src_io->crop_bottom;
// No need to copy the scaling parameters.
if (dec->method_ == ALPHA_NO_COMPRESSION) {
const size_t alpha_decoded_size = dec->width_ * dec->height_;
ok = (alpha_data_size >= alpha_decoded_size);
} else {
assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
}
return ok;
}
// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
// starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded.
// Returns false in case of bitstream error.
static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_;
const int height = alph_dec->io_.crop_bottom;
if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
int y;
const uint8_t* prev_line = dec->alpha_prev_line_;
const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
uint8_t* dst = dec->alpha_plane_ + row * width;
assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
if (alph_dec->filter_ != WEBP_FILTER_NONE) {
assert(WebPUnfilters[alph_dec->filter_] != NULL);
for (y = 0; y < num_rows; ++y) {
WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
prev_line = dst;
dst += width;
deltas += width;
}
} else {
for (y = 0; y < num_rows; ++y) {
memcpy(dst, deltas, width * sizeof(*dst));
prev_line = dst;
dst += width;
deltas += width;
}
}
dec->alpha_prev_line_ = prev_line;
} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
assert(alph_dec->vp8l_dec_ != NULL);
if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
return 0;
}
}
if (row + num_rows >= height) {
dec->is_alpha_decoded_ = 1;
}
return 1;
}
static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
const int stride = io->width;
const int height = io->crop_bottom;
const uint64_t alpha_size = (uint64_t)stride * height;
assert(dec->alpha_plane_mem_ == NULL);
dec->alpha_plane_mem_ =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
if (dec->alpha_plane_mem_ == NULL) {
return 0;
}
dec->alpha_plane_ = dec->alpha_plane_mem_;
dec->alpha_prev_line_ = NULL;
return 1;
}
void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
assert(dec != NULL);
WebPSafeFree(dec->alpha_plane_mem_);
dec->alpha_plane_mem_ = NULL;
dec->alpha_plane_ = NULL;
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
}
//------------------------------------------------------------------------------
// Main entry point.
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
const VP8Io* const io,
int row, int num_rows) {
const int width = io->width;
const int height = io->crop_bottom;
assert(dec != NULL && io != NULL);
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
return NULL; // sanity check.
}
if (!dec->is_alpha_decoded_) {
if (dec->alph_dec_ == NULL) { // Initialize decoder.
dec->alph_dec_ = ALPHNew();
if (dec->alph_dec_ == NULL) return NULL;
if (!AllocateAlphaPlane(dec, io)) goto Error;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
io, dec->alpha_plane_)) {
goto Error;
}
// if we allowed use of alpha dithering, check whether it's needed at all
if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
dec->alpha_dithering_ = 0; // disable dithering
} else {
num_rows = height - row; // decode everything in one pass
}
}
assert(dec->alph_dec_ != NULL);
assert(row + num_rows <= height);
if (!ALPHDecode(dec, row, num_rows)) goto Error;
if (dec->is_alpha_decoded_) { // finished?
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
if (dec->alpha_dithering_ > 0) {
uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width
+ io->crop_left;
if (!WebPDequantizeLevels(alpha,
io->crop_right - io->crop_left,
io->crop_bottom - io->crop_top,
width, dec->alpha_dithering_)) {
goto Error;
}
}
}
}
// Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width;
Error:
WebPDeallocateAlphaMemory(dec);
return NULL;
}

View File

@ -1,54 +0,0 @@
// Copyright 2013 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.
// -----------------------------------------------------------------------------
//
// Alpha decoder: internal header.
//
// Author: Urvang (urvang@google.com)
#ifndef WEBP_DEC_ALPHAI_DEC_H_
#define WEBP_DEC_ALPHAI_DEC_H_
#include "src/dec/webpi_dec.h"
#include "src/utils/filters_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
struct VP8LDecoder; // Defined in dec/vp8li.h.
typedef struct ALPHDecoder ALPHDecoder;
struct ALPHDecoder {
int width_;
int height_;
int method_;
WEBP_FILTER_TYPE filter_;
int pre_processing_;
struct VP8LDecoder* vp8l_dec_;
VP8Io io_;
int use_8b_decode_; // Although alpha channel requires only 1 byte per
// pixel, sometimes VP8LDecoder may need to allocate
// 4 bytes per pixel internally during decode.
uint8_t* output_;
const uint8_t* prev_line_; // last output row (or NULL)
};
//------------------------------------------------------------------------------
// internal functions. Not public.
// Deallocate memory associated to dec->alpha_plane_ decoding
void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_DEC_ALPHAI_DEC_H_

View File

@ -13,15 +13,19 @@
#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"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 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 };
@ -33,11 +37,6 @@ static int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
} }
// strictly speaking, the very last (or first, if flipped) row
// doesn't require padding.
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
((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;
const WEBP_CSP_MODE mode = buffer->colorspace; const WEBP_CSP_MODE mode = buffer->colorspace;
@ -47,42 +46,33 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
ok = 0; ok = 0;
} else if (!WebPIsRGBMode(mode)) { // YUV checks } else if (!WebPIsRGBMode(mode)) { // YUV checks
const WebPYUVABuffer* const buf = &buffer->u.YUVA; const WebPYUVABuffer* const buf = &buffer->u.YUVA;
const int uv_width = (width + 1) / 2; const uint64_t y_size = (uint64_t)buf->y_stride * height;
const int uv_height = (height + 1) / 2; const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
const int y_stride = abs(buf->y_stride); const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
const int u_stride = abs(buf->u_stride); const uint64_t a_size = (uint64_t)buf->a_stride * height;
const int v_stride = abs(buf->v_stride);
const int a_stride = abs(buf->a_stride);
const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride);
const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride);
const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride);
const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride);
ok &= (y_size <= buf->y_size); ok &= (y_size <= buf->y_size);
ok &= (u_size <= buf->u_size); ok &= (u_size <= buf->u_size);
ok &= (v_size <= buf->v_size); ok &= (v_size <= buf->v_size);
ok &= (y_stride >= width); ok &= (buf->y_stride >= width);
ok &= (u_stride >= uv_width); ok &= (buf->u_stride >= (width + 1) / 2);
ok &= (v_stride >= uv_width); ok &= (buf->v_stride >= (width + 1) / 2);
ok &= (buf->y != NULL); ok &= (buf->y != NULL);
ok &= (buf->u != NULL); ok &= (buf->u != NULL);
ok &= (buf->v != NULL); ok &= (buf->v != NULL);
if (mode == MODE_YUVA) { if (mode == MODE_YUVA) {
ok &= (a_stride >= width); ok &= (buf->a_stride >= width);
ok &= (a_size <= buf->a_size); ok &= (a_size <= buf->a_size);
ok &= (buf->a != NULL); ok &= (buf->a != NULL);
} }
} 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 uint64_t size = (uint64_t)buf->stride * height;
const uint64_t size =
MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size); ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]); ok &= (buf->stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL); ok &= (buf->rgba != NULL);
} }
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM; return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
} }
#undef MIN_BUFFER_SIZE
static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) { static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
const int w = buffer->width; const int w = buffer->width;
@ -93,20 +83,15 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
return VP8_STATUS_INVALID_PARAM; return VP8_STATUS_INVALID_PARAM;
} }
if (buffer->is_external_memory <= 0 && buffer->private_memory == NULL) { if (!buffer->is_external_memory && buffer->private_memory == NULL) {
uint8_t* output; uint8_t* output;
int uv_stride = 0, a_stride = 0; int uv_stride = 0, a_stride = 0;
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);
@ -150,36 +135,10 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
return CheckDecBuffer(buffer); return CheckDecBuffer(buffer);
} }
VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) { VP8StatusCode WebPAllocateDecBuffer(int w, int h,
if (buffer == NULL) {
return VP8_STATUS_INVALID_PARAM;
}
if (WebPIsRGBMode(buffer->colorspace)) {
WebPRGBABuffer* const buf = &buffer->u.RGBA;
buf->rgba += (buffer->height - 1) * buf->stride;
buf->stride = -buf->stride;
} else {
WebPYUVABuffer* const buf = &buffer->u.YUVA;
const int H = buffer->height;
buf->y += (H - 1) * buf->y_stride;
buf->y_stride = -buf->y_stride;
buf->u += ((H - 1) >> 1) * buf->u_stride;
buf->u_stride = -buf->u_stride;
buf->v += ((H - 1) >> 1) * buf->v_stride;
buf->v_stride = -buf->v_stride;
if (buf->a != NULL) {
buf->a += (H - 1) * buf->a_stride;
buf->a_stride = -buf->a_stride;
}
}
return VP8_STATUS_OK;
}
VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const WebPDecoderOptions* const options, const WebPDecoderOptions* const options,
WebPDecBuffer* const buffer) { WebPDecBuffer* const out) {
VP8StatusCode status; if (out == NULL || w <= 0 || h <= 0) {
if (buffer == NULL || width <= 0 || height <= 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,41 +147,25 @@ 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) if (options->scaled_width <= 0 || options->scaled_height <= 0) {
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
if (!WebPRescalerGetScaledDimensions(
width, height, &scaled_width, &scaled_height)) {
return VP8_STATUS_INVALID_PARAM; return VP8_STATUS_INVALID_PARAM;
} }
width = scaled_width; w = options->scaled_width;
height = scaled_height; h = options->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); return AllocateBuffer(out);
if (status != VP8_STATUS_OK) return status;
// Use the stride trick if vertical flip is needed.
if (options != NULL && options->flip) {
status = WebPFlipBuffer(buffer);
}
return status;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -239,9 +182,8 @@ int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
void WebPFreeDecBuffer(WebPDecBuffer* buffer) { void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
if (buffer != NULL) { if (buffer != NULL) {
if (buffer->is_external_memory <= 0) { if (!buffer->is_external_memory)
WebPSafeFree(buffer->private_memory); free(buffer->private_memory);
}
buffer->private_memory = NULL; buffer->private_memory = NULL;
} }
} }
@ -268,45 +210,8 @@ void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
} }
} }
VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src_buf,
WebPDecBuffer* const dst_buf) {
assert(src_buf != NULL && dst_buf != NULL);
assert(src_buf->colorspace == dst_buf->colorspace);
dst_buf->width = src_buf->width;
dst_buf->height = src_buf->height;
if (CheckDecBuffer(dst_buf) != VP8_STATUS_OK) {
return VP8_STATUS_INVALID_PARAM;
}
if (WebPIsRGBMode(src_buf->colorspace)) {
const WebPRGBABuffer* const src = &src_buf->u.RGBA;
const WebPRGBABuffer* const dst = &dst_buf->u.RGBA;
WebPCopyPlane(src->rgba, src->stride, dst->rgba, dst->stride,
src_buf->width * kModeBpp[src_buf->colorspace],
src_buf->height);
} else {
const WebPYUVABuffer* const src = &src_buf->u.YUVA;
const WebPYUVABuffer* const dst = &dst_buf->u.YUVA;
WebPCopyPlane(src->y, src->y_stride, dst->y, dst->y_stride,
src_buf->width, src_buf->height);
WebPCopyPlane(src->u, src->u_stride, dst->u, dst->u_stride,
(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
WebPCopyPlane(src->v, src->v_stride, dst->v, dst->v_stride,
(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
if (WebPIsAlphaMode(src_buf->colorspace)) {
WebPCopyPlane(src->a, src->a_stride, dst->a, dst->a_stride,
src_buf->width, src_buf->height);
}
}
return VP8_STATUS_OK;
}
int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
const WebPBitstreamFeatures* const features) {
assert(output != NULL);
return (output->is_external_memory >= 2) &&
WebPIsPremultipliedMode(output->colorspace) &&
(features != NULL && features->has_alpha);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@ -1,54 +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.
// -----------------------------------------------------------------------------
//
// Definitions and macros common to encoding and decoding
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DEC_COMMON_DEC_H_
#define WEBP_DEC_COMMON_DEC_H_
// intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes
B_TM_PRED = 1,
B_VE_PRED = 2,
B_HE_PRED = 3,
B_RD_PRED = 4,
B_VR_PRED = 5,
B_LD_PRED = 6,
B_VL_PRED = 7,
B_HD_PRED = 8,
B_HU_PRED = 9,
NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
// Luma16 or UV modes
DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
B_PRED = NUM_BMODES, // refined I4x4 mode
NUM_PRED_MODES = 4,
// special modes
B_DC_PRED_NOTOP = 4,
B_DC_PRED_NOLEFT = 5,
B_DC_PRED_NOTOPLEFT = 6,
NUM_B_DC_MODES = 7 };
enum { MB_FEATURE_TREE_PROBS = 3,
NUM_MB_SEGMENTS = 4,
NUM_REF_LF_DELTAS = 4,
NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
MAX_NUM_PARTITIONS = 8,
// Probabilities
NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC
NUM_BANDS = 8,
NUM_CTX = 3,
NUM_PROBAS = 11
};
#endif // WEBP_DEC_COMMON_DEC_H_

View File

@ -11,12 +11,12 @@
// //
// 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 #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
@ -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;
@ -132,8 +132,7 @@ static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION); return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
} }
// Decode the VP8 frame header. Returns true if ok. // Start decoding a new picture. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already. // Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
@ -157,29 +156,29 @@ 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);
#ifdef __cplusplus #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"
#endif #endif
#endif // WEBP_DEC_VP8_DEC_H_ #endif /* WEBP_WEBP_DECODE_VP8_H_ */

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