diff options
81 files changed, 1769 insertions, 25 deletions
diff --git a/Makefile.fetch b/Makefile.fetch index b988fbf7e717..78ff78b9e312 100644 --- a/Makefile.fetch +++ b/Makefile.fetch @@ -161,6 +161,7 @@ $(WORKDIR)/download: $(BUILDDIR)/config_$(gb_Side).mk $(SRCDIR)/download.lst $(S $(call fetch_Optional,LIBNUMBERTEXT,LIBNUMBERTEXT_TARBALL) \ $(call fetch_Optional,LIBPNG,LIBPNG_TARBALL) \ $(call fetch_Optional,LIBTOMMATH,LIBTOMMATH_TARBALL) \ + $(call fetch_Optional,LIBWEBP,LIBWEBP_TARBALL) \ $(call fetch_Optional,LIBXML2,LIBXML_TARBALL) \ $(call fetch_Optional,XMLSEC,XMLSEC_TARBALL) \ $(call fetch_Optional,LIBXSLT,LIBXSLT_TARBALL) \ diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 6ba871409779..2e7e86266e34 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -2608,6 +2608,57 @@ endef endif # !SYSTEM_LIBPNG +ifneq ($(SYSTEM_LIBWEBP),) + +define gb_LinkTarget__use_libwebp +$(call gb_LinkTarget_set_include,$(1),\ + $$(INCLUDE) \ + $(LIBWEBP_CFLAGS) \ +) + +$(call gb_LinkTarget_add_libs,$(1),\ + $(LIBWEBP_LIBS) \ +) + +endef + +gb_ExternalProject__use_libwebp := + +else # !SYSTEM_LIBWEBP + +define gb_LinkTarget__use_libwebp +$(call gb_LinkTarget_set_include,$(1),\ + $(LIBWEBP_CFLAGS) \ + $$(INCLUDE) \ +) + +$(call gb_LinkTarget_set_include,$(1),\ + -I$(call gb_UnpackedTarball_get_dir,libwebp)/src \ + $$(INCLUDE) \ +) +ifeq ($(OS),WNT) +$(call gb_LinkTarget_add_libs,$(1),\ + $(call gb_UnpackedTarball_get_dir,libwebp)/output/lib/libwebp$(gb_StaticLibrary_PLAINEXT) \ +) +else +$(call gb_LinkTarget_add_libs,$(1),\ + -L$(call gb_UnpackedTarball_get_dir,libwebp)/src/.libs -lwebp \ +) +endif +$(call gb_LinkTarget_use_external_project,$(1),libwebp) + +endef + +define gb_ExternalProject__use_libwebp +$(call gb_ExternalProject_use_external_project,$(1),\ + libwebp \ +) + +endef + +endif # !SYSTEM_LIBWEBP + + ifneq ($(SYSTEM_CURL),) define gb_LinkTarget__use_curl diff --git a/bin/lo-all-static-libs b/bin/lo-all-static-libs index 11230c695248..fbe6d7010624 100755 --- a/bin/lo-all-static-libs +++ b/bin/lo-all-static-libs @@ -123,6 +123,7 @@ echo $INSTDIR/$LIBO_LIB_FOLDER/lib*.a \ $WORKDIR/UnpackedTarball/liborcus/src/*/.libs/*.a \ $WORKDIR/UnpackedTarball/librevenge/src/*/.libs/*.a \ $WORKDIR/UnpackedTarball/libvisio/src/lib/.libs/*.a \ + $WORKDIR/UnpackedTarball/libwebp/src/.libs/*.a \ $WORKDIR/UnpackedTarball/libwp?/src/lib/.libs/*.a \ $WORKDIR/UnpackedTarball/raptor/src/.libs/*.a \ $WORKDIR/UnpackedTarball/rasqal/src/.libs/*.a \ diff --git a/config_host.mk.in b/config_host.mk.in index f512e719ee6c..3aee8c0f84bb 100644 --- a/config_host.mk.in +++ b/config_host.mk.in @@ -417,6 +417,8 @@ export LIBSERIALIZER_JAR=@LIBSERIALIZER_JAR@ export LIBTOMMATH_CFLAGS=@LIBTOMMATH_CFLAGS@ export LIBTOMMATH_LIBS=@LIBTOMMATH_LIBS@ export LIBTOOL=@LIBTOOL@ +export LIBWEBP_CFLAGS=$(gb_SPACE)@LIBWEBP_CFLAGS@ +export LIBWEBP_LIBS=$(gb_SPACE)@LIBWEBP_LIBS@ export LIBXML_CFLAGS=$(gb_SPACE)@LIBXML_CFLAGS@ export LIBXML_JAR=@LIBXML_JAR@ export LIBXML_LIBS=$(gb_SPACE)@LIBXML_LIBS@ @@ -640,6 +642,7 @@ export SYSTEM_LIBNUMBERTEXT_DATA=@SYSTEM_LIBNUMBERTEXT_DATA@ export SYSTEM_LIBORCUS=@SYSTEM_LIBORCUS@ export SYSTEM_LIBPNG=@SYSTEM_LIBPNG@ export SYSTEM_LIBTOMMATH=@SYSTEM_LIBTOMMATH@ +export SYSTEM_LIBWEBP=@SYSTEM_LIBWEBP@ export SYSTEM_LIBXML=@SYSTEM_LIBXML@ export SYSTEM_LIBXML_FOR_BUILD=@SYSTEM_LIBXML_FOR_BUILD@ export SYSTEM_LIBXSLT=@SYSTEM_LIBXSLT@ diff --git a/configure.ac b/configure.ac index 2f4e9fa56875..bb53c75fac73 100644 --- a/configure.ac +++ b/configure.ac @@ -13438,6 +13438,12 @@ LIBPNG_LIBS_internal="-L${WORKDIR}/LinkTarget/StaticLibrary -llibpng" libo_CHECK_SYSTEM_MODULE([libpng],[LIBPNG],[libpng]) dnl =================================================================== +dnl Test whether to build libwebp or rely on the system version +dnl =================================================================== + +libo_CHECK_SYSTEM_MODULE([libwebp],[LIBWEBP],[libwebp]) + +dnl =================================================================== dnl Check for runtime JVM search path dnl =================================================================== if test "$ENABLE_JAVA" != ""; then diff --git a/download.lst b/download.lst index e3f10866ea53..48f847b64ff8 100644 --- a/download.lst +++ b/download.lst @@ -160,6 +160,8 @@ export LIBNUMBERTEXT_SHA256SUM := db9060d208501bd7bc06300a55d8489d29dd560ee0fbbd export LIBNUMBERTEXT_TARBALL := libnumbertext-1.0.8.tar.xz export LIBTOMMATH_SHA256SUM := 083daa92d8ee6f4af96a6143b12d7fc8fe1a547e14f862304f7281f8f7347483 export LIBTOMMATH_TARBALL := ltm-1.0.zip +export LIBWEBP_SHA256SUM := 808b98d2f5b84e9b27fdef6c5372dac769c3bda4502febbfa5031bd3c4d7d018 +export LIBWEBP_TARBALL := libwebp-1.2.1.tar.gz export XMLSEC_SHA256SUM := 26041d35a20a245ed5a2fb9ee075f10825664d274220cb5190340fa87a4d0931 export XMLSEC_TARBALL := xmlsec1-1.2.33.tar.gz export LIBXML_SHA256SUM := c8d6681e38c56f172892c85ddc0852e1fd4b53b4209e7f4ebf17f7e2eae71d92 diff --git a/external/Module_external.mk b/external/Module_external.mk index 66759274caa8..946b9dd16ed7 100644 --- a/external/Module_external.mk +++ b/external/Module_external.mk @@ -62,6 +62,7 @@ $(eval $(call gb_Module_add_moduledirs,external,\ $(call gb_Helper_optional,LIBLANGTAG,liblangtag) \ $(call gb_Helper_optional,LIBNUMBERTEXT,libnumbertext) \ $(call gb_Helper_optional,LIBPNG,libpng) \ + $(call gb_Helper_optional,LIBWEBP,libwebp) \ $(call gb_Helper_optional,LIBXML2,libxml2) \ $(call gb_Helper_optional,LIBXSLT,libxslt) \ $(call gb_Helper_optional,LPSOLVE,lpsolve) \ diff --git a/external/libwebp/ExternalProject_libwebp.mk b/external/libwebp/ExternalProject_libwebp.mk new file mode 100644 index 000000000000..beb7a39e7b64 --- /dev/null +++ b/external/libwebp/ExternalProject_libwebp.mk @@ -0,0 +1,52 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_ExternalProject_ExternalProject,libwebp)) + +$(eval $(call gb_ExternalProject_register_targets,libwebp,\ + build \ +)) + +ifeq ($(COM),MSC) +$(eval $(call gb_ExternalProject_use_nmake,libwebp,build)) + +$(call gb_ExternalProject_get_state_target,libwebp,build): + $(call gb_Trace_StartRange,libwebp,EXTERNAL) + $(call gb_ExternalProject_run,build,\ + nmake -nologo -f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output \ + ) + $(call gb_Trace_EndRange,libwebp,EXTERNAL) +else +$(eval $(call gb_ExternalProject_use_autoconf,libwebp,build)) + +$(call gb_ExternalProject_get_state_target,libwebp,build) : + $(call gb_Trace_StartRange,libwebp,EXTERNAL) + $(call gb_ExternalProject_run,build,\ + export PKG_CONFIG="" \ + && MAKE=$(MAKE) $(gb_RUN_CONFIGURE) ./configure \ + --enable-static \ + --with-pic \ + --disable-shared \ + --disable-gl \ + --disable-sdl \ + --disable-png \ + --disable-jpeg \ + --disable-tiff \ + --disable-gif \ + --disable-wic \ + $(if $(verbose),--disable-silent-rules,--enable-silent-rules) \ + CXXFLAGS="$(gb_CXXFLAGS) $(if $(ENABLE_OPTIMIZED),$(gb_COMPILEROPTFLAGS),$(gb_COMPILERNOOPTFLAGS))" \ + CPPFLAGS="$(CPPFLAGS) $(BOOST_CPPFLAGS)" \ + $(if $(CROSS_COMPILING),--build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM)) \ + && $(MAKE) \ + ) + $(call gb_Trace_EndRange,libwebp,EXTERNAL) +endif + +# vim: set noet sw=4 ts=4: diff --git a/external/libwebp/Makefile b/external/libwebp/Makefile new file mode 100644 index 000000000000..e4968cf85fb6 --- /dev/null +++ b/external/libwebp/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/external/libwebp/Makefile.vc.patch b/external/libwebp/Makefile.vc.patch new file mode 100644 index 000000000000..653998319b82 --- /dev/null +++ b/external/libwebp/Makefile.vc.patch @@ -0,0 +1,145 @@ +--- Makefile.vc.sav 2021-07-30 00:55:37.000000000 +0200 ++++ Makefile.vc 2022-01-25 17:35:30.206117700 +0100 +@@ -7,11 +7,11 @@ + LIBWEBPDEMUX_BASENAME = libwebpdemux + + !IFNDEF ARCH +-!IF ! [ cl 2>&1 | find "x86" > NUL ] ++!IF ! [ $(CC) 2>&1 | grep -q "x86" > NUL ] + ARCH = x86 +-!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ] ++!ELSE IF ! [ $(CC) 2>&1 | grep -q "x64" > NUL ] + ARCH = x64 +-!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ] ++!ELSE IF ! [ $(CC) 2>&1 | grep -q "ARM" > NUL ] + ARCH = ARM + !ELSE + !ERROR Unable to auto-detect toolchain architecture! \ +@@ -27,8 +27,8 @@ + ## Nothing more to do below this line! + + NOLOGO = /nologo +-CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG +-CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1 ++CCNODBG = $(CC) $(NOLOGO) /O2 /DNDEBUG ++CCDEBUG = $(CC) $(NOLOGO) /Od /Zi /D_DEBUG /RTC1 + CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c + CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN + LDFLAGS = /LARGEADDRESSAWARE /MANIFEST /NXCOMPAT /DYNAMICBASE +@@ -67,7 +67,7 @@ + RTLIB = /MD + RTLIBD = /MDd + !ENDIF +-DIRBASE = $(OUTDIR)\$(CFG)\$(ARCH) ++DIRBASE = $(OUTDIR) + DIROBJ = $(DIRBASE)\obj + DIRLIB = $(DIRBASE)\lib + DIRINC = $(DIRBASE)\include +@@ -86,10 +86,10 @@ + + # Target configuration + !IF "$(CFG)" == "release-static" +-CC = $(CCNODBG) ++CC_ = $(CCNODBG) + STATICLIBBUILD = TRUE + !ELSE IF "$(CFG)" == "debug-static" +-CC = $(CCDEBUG) ++CC_ = $(CCDEBUG) + RTLIB = $(RTLIBD) + STATICLIBBUILD = TRUE + LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug +@@ -97,11 +97,11 @@ + LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug + LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug + !ELSE IF "$(CFG)" == "release-dynamic" +-CC = $(CCNODBG) ++CC_ = $(CCNODBG) + RC = $(RCNODBG) + DLLBUILD = TRUE + !ELSE IF "$(CFG)" == "debug-dynamic" +-CC = $(CCDEBUG) ++CC_ = $(CCDEBUG) + RC = $(RCDEBUG) + RTLIB = $(RTLIBD) + DLLBUILD = TRUE +@@ -112,7 +112,7 @@ + !ENDIF + + !IF "$(STATICLIBBUILD)" == "TRUE" +-CC = $(CC) $(RTLIB) ++CC_ = $(CC_) $(RTLIB) + CFGSET = TRUE + LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib + LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib +@@ -120,7 +120,7 @@ + LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib + !ELSE IF "$(DLLBUILD)" == "TRUE" + DLLINC = webp_dll.h +-CC = $(CC) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL ++CC_ = $(CC_) /I$(DIROBJ) /FI$(DLLINC) $(RTLIB) /DWEBP_DLL + LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib + LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib + LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib +@@ -421,7 +421,7 @@ + $(DIROBJ)\$(DLLINC) + + {$(DIROBJ)}.c{$(DIROBJ)}.obj: +- $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< ++ $(CC_) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< + + {src}.rc{$(DIROBJ)}.res: + $(RC) /fo$@ $< +@@ -461,39 +461,39 @@ + # 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) \ ++ $(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) \ ++ $(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) \ ++ $(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) \ ++ $(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) \ ++ $(CC_) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ + /Fo$(DIROBJ)\examples\ examples\$(@B).c + # Batch rules + {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\ $< ++ $(CC_) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $< + {imageio}.c{$(DIROBJ)\imageio}.obj:: +- $(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $< ++ $(CC_) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $< + {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:: +- $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\demux\ $< ++ $(CC_) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\demux\ $< + {src\dsp}.c{$(DIROBJ)\dsp}.obj:: +- $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ $< ++ $(CC_) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ $< + {src\enc}.c{$(DIROBJ)\enc}.obj:: +- $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\enc\ $< ++ $(CC_) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\enc\ $< + {src\mux}.c{$(DIROBJ)\mux}.obj:: +- $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\mux\ $< ++ $(CC_) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\mux\ $< + {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" diff --git a/external/libwebp/Module_libwebp.mk b/external/libwebp/Module_libwebp.mk new file mode 100644 index 000000000000..b89056ac3d35 --- /dev/null +++ b/external/libwebp/Module_libwebp.mk @@ -0,0 +1,17 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Module_Module,libwebp)) + +$(eval $(call gb_Module_add_targets,libwebp,\ + ExternalProject_libwebp \ + UnpackedTarball_libwebp \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/external/libwebp/README b/external/libwebp/README new file mode 100644 index 000000000000..1308c278baca --- /dev/null +++ b/external/libwebp/README @@ -0,0 +1 @@ +libwebp is a library to encode and decode images in WebP format, from [https://developers.google.com/speed/webp/] diff --git a/external/libwebp/UnpackedTarball_libwebp.mk b/external/libwebp/UnpackedTarball_libwebp.mk new file mode 100644 index 000000000000..67f797157717 --- /dev/null +++ b/external/libwebp/UnpackedTarball_libwebp.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UnpackedTarball_UnpackedTarball,libwebp)) + +$(eval $(call gb_UnpackedTarball_set_tarball,libwebp,$(LIBWEBP_TARBALL))) + +$(eval $(call gb_UnpackedTarball_set_patchlevel,libwebp,0)) + +$(eval $(call gb_UnpackedTarball_add_patches,libwebp,\ + external/libwebp/Makefile.vc.patch \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/filter/Configuration_filter.mk b/filter/Configuration_filter.mk index dfeacc6a542c..a58b8396c551 100644 --- a/filter/Configuration_filter.mk +++ b/filter/Configuration_filter.mk @@ -442,6 +442,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_web_filters.xc writer_web_pdf_Export\ writer_web_png_Export\ writer_web_jpg_Export\ + writer_web_webp_Export\ writerweb8_writer_template\ writerweb8_writer \ )) @@ -715,6 +716,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_drawgraphics_typ svm_StarView_Metafile \ tga_Truevision_TARGA \ tif_Tag_Image_File \ + webp_WebP \ wmf_MS_Windows_Metafile \ xbm_X_Consortium \ xpm_XPM \ @@ -742,6 +744,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_drawgraphics_f SVM___StarView_Metafile \ TGA___Truevision_TARGA \ TIF___Tag_Image_File \ + WEBP___WebP \ WMF___MS_Windows_Metafile \ XBM___X_Consortium \ XPM \ @@ -757,6 +760,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_drawgraphics_f draw_png_Export \ draw_svg_Export \ draw_tif_Export \ + draw_webp_Export \ draw_wmf_Export \ )) @@ -781,6 +785,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_impressgraphics_ svm_StarView_Metafile \ tif_Tag_Image_File \ wmf_MS_Windows_Metafile \ + webp_WebP \ xpm_XPM \ )) @@ -795,6 +800,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_impressgraphic impress_png_Export \ impress_svg_Export \ impress_tif_Export \ + impress_webp_Export \ impress_wmf_Export \ )) @@ -809,6 +815,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_writergraphics writer_jpg_Export \ writer_png_Export \ writer_svg_Export \ + writer_webp_Export \ )) # fcfg_calcgraphics @@ -821,6 +828,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_calcgraphics_f calc_jpg_Export \ calc_png_Export \ calc_svg_Export \ + calc_webp_Export \ )) # fcfg_internalgraphics @@ -848,6 +856,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_internalgraphics svm_StarView_Metafile \ tga_Truevision_TARGA \ tif_Tag_Image_File \ + webp_WebP \ wmf_MS_Windows_Metafile \ xbm_X_Consortium \ xpm_XPM \ @@ -887,11 +896,13 @@ $(eval $(call filter_Configuration_add_internal_filters,fcfg_langpack,fcfg_inter tga_Import \ tif_Export \ tif_Import \ + webp_Export \ + webp_Import \ wmf_Export \ wmf_Import \ xbm_Import \ xpm_Import \ - mov_Import \ + mov_Import \ )) # fcfg_xslt diff --git a/filter/qa/complex/filter/detection/typeDetection/files.csv b/filter/qa/complex/filter/detection/typeDetection/files.csv index b882ea1179ca..8e558590b4e7 100644 --- a/filter/qa/complex/filter/detection/typeDetection/files.csv +++ b/filter/qa/complex/filter/detection/typeDetection/files.csv @@ -111,6 +111,7 @@ ppm;Graphics/pic.ppm;ppm_Portable_Pixelmap;ppm_Portable_Pixelmap ras;Graphics/pic.ras;ras_Sun_Rasterfile;ras_Sun_Rasterfile svm;Graphics/pic.svm;svm_StarView_Metafile;svm_StarView_Metafile:generic_Text tif;Graphics/pic.tif;tif_Tag_Image_File;tif_Tag_Image_File:generic_Text +webp;Graphics/pic.webp;webp_WebP;webp_WebP wmf;Graphics/pic.wmf;wmf_MS_Windows_Metafile;wmf_MS_Windows_Metafile:generic_Text diff --git a/filter/source/config/cache/typedetection.cxx b/filter/source/config/cache/typedetection.cxx index ac4d9aed9f2a..b91ac31566af 100644 --- a/filter/source/config/cache/typedetection.cxx +++ b/filter/source/config/cache/typedetection.cxx @@ -232,6 +232,7 @@ int getFlatTypeRank(const OUString& rType) "pcd_Photo_CD_Base", "pcd_Photo_CD_Base4", "pcd_Photo_CD_Base16", + "webp_WebP", "impress_CGM_Computer_Graphics_Metafile", // There is binary and ascii variants ? "draw_WordPerfect_Graphics", "draw_Visio_Document", diff --git a/filter/source/config/fragments/filters/WEBP___WebP.xcu b/filter/source/config/fragments/filters/WEBP___WebP.xcu new file mode 100644 index 000000000000..9c650e3de42e --- /dev/null +++ b/filter/source/config/fragments/filters/WEBP___WebP.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="WEBP - WebP" oor:op="replace"> + <prop oor:name="Flags"><value>IMPORT ALIEN</value></prop> + <prop oor:name="UIComponent"/> + <prop oor:name="FilterService"/> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.drawing.DrawingDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/calc_webp_Export.xcu b/filter/source/config/fragments/filters/calc_webp_Export.xcu new file mode 100644 index 000000000000..a6e5d18a3347 --- /dev/null +++ b/filter/source/config/fragments/filters/calc_webp_Export.xcu @@ -0,0 +1,20 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +--> + <node oor:name="calc_webp_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN 3RDPARTYFILTER SUPPORTSSELECTION</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="FilterService"><value>com.sun.star.comp.GraphicExportFilter</value></prop> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.sheet.SpreadsheetDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/draw_webp_Export.xcu b/filter/source/config/fragments/filters/draw_webp_Export.xcu new file mode 100644 index 000000000000..e6da69197a61 --- /dev/null +++ b/filter/source/config/fragments/filters/draw_webp_Export.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="draw_webp_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN SUPPORTSSELECTION</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="FilterService"/> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.drawing.DrawingDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/impress_webp_Export.xcu b/filter/source/config/fragments/filters/impress_webp_Export.xcu new file mode 100644 index 000000000000..00284a272cba --- /dev/null +++ b/filter/source/config/fragments/filters/impress_webp_Export.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="impress_webp_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN SUPPORTSSELECTION</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="FilterService"/> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.presentation.PresentationDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/writer_web_webp_Export.xcu b/filter/source/config/fragments/filters/writer_web_webp_Export.xcu new file mode 100644 index 000000000000..5273bb72228b --- /dev/null +++ b/filter/source/config/fragments/filters/writer_web_webp_Export.xcu @@ -0,0 +1,21 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + <node oor:name="writer_web_webp_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN 3RDPARTYFILTER</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="FilterService"><value>com.sun.star.comp.GraphicExportFilter</value></prop> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.text.WebDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/filters/writer_webp_Export.xcu b/filter/source/config/fragments/filters/writer_webp_Export.xcu new file mode 100644 index 000000000000..ceb56a8c035f --- /dev/null +++ b/filter/source/config/fragments/filters/writer_webp_Export.xcu @@ -0,0 +1,30 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="writer_webp_Export" oor:op="replace"> + <prop oor:name="Flags"><value>EXPORT ALIEN 3RDPARTYFILTER</value></prop> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="FilterService"><value>com.sun.star.comp.GraphicExportFilter</value></prop> + <prop oor:name="UserData"><value></value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="FileFormatVersion"><value>0</value></prop> + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="TemplateName"/> + <prop oor:name="DocumentService"><value>com.sun.star.text.TextDocument</value></prop> + </node> diff --git a/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu b/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu new file mode 100644 index 000000000000..70ff15429734 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/webp_Export.xcu @@ -0,0 +1,27 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="webp_Export" oor:op="replace" > + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="FormatName"><value>SVEWEBP</value></prop> + <prop oor:name="RealFilterName"/> + <prop oor:name="UIComponent"><value>com.sun.star.svtools.SvFilterOptionsDialog</value></prop> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="Flags"><value>EXPORT</value></prop> + </node> diff --git a/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu b/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu new file mode 100644 index 000000000000..cdce5c9e4047 --- /dev/null +++ b/filter/source/config/fragments/internalgraphicfilters/webp_Import.xcu @@ -0,0 +1,27 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="webp_Import" oor:op="replace" > + <prop oor:name="Type"><value>webp_WebP</value></prop> + <prop oor:name="FormatName"><value>SVIWEBP</value></prop> + <prop oor:name="RealFilterName"><value>WEBP - WebP</value></prop> + <prop oor:name="UIComponent"/> + <prop oor:name="UIName"> + <value xml:lang="en-US">WEBP - WebP Image</value> + </prop> + <prop oor:name="Flags"><value>IMPORT</value></prop> + </node> diff --git a/filter/source/config/fragments/types/webp_WebP.xcu b/filter/source/config/fragments/types/webp_WebP.xcu new file mode 100644 index 000000000000..e58984fbedc7 --- /dev/null +++ b/filter/source/config/fragments/types/webp_WebP.xcu @@ -0,0 +1,29 @@ +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . +--> + <node oor:name="webp_WebP" oor:op="replace" > + <prop oor:name="DetectService"><value>com.sun.star.comp.draw.FormatDetector</value></prop> + <prop oor:name="URLPattern"/> + <prop oor:name="Extensions"><value>webp</value></prop> + <prop oor:name="MediaType"><value>image/webp</value></prop> + <prop oor:name="Preferred"><value>false</value></prop> + <prop oor:name="PreferredFilter"><value>WEBP - WebP</value></prop> + <prop oor:name="UIName"> + <value>WEBP - WebP Image</value> + </prop> + <prop oor:name="ClipboardFormat"/> + </node> diff --git a/icon-themes/breeze/res/sx03223.png b/icon-themes/breeze/res/sx03223.png Binary files differnew file mode 100644 index 000000000000..82e6f7b14f31 --- /dev/null +++ b/icon-themes/breeze/res/sx03223.png diff --git a/icon-themes/breeze_dark/res/sx03223.png b/icon-themes/breeze_dark/res/sx03223.png Binary files differnew file mode 100644 index 000000000000..82e6f7b14f31 --- /dev/null +++ b/icon-themes/breeze_dark/res/sx03223.png diff --git a/icon-themes/breeze_dark_svg/res/sx03223.svg b/icon-themes/breeze_dark_svg/res/sx03223.svg new file mode 100644 index 000000000000..576860153fb7 --- /dev/null +++ b/icon-themes/breeze_dark_svg/res/sx03223.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2v8.992188l-1 1v.007812h1v2h12v-2.998047h1v-.009765l-1-1.0000005v-7.9921875zm1 1h10v5.9921875l-3.9941406-3.9921875h-.0058594v.0019531h-.0058594l-2.4960937 2.4921875-.4941407-.4941406h-.0039062-.0039062l-2.9960938 2.9941406zm2 1c-.554 0-1 .446-1 1s.446 1 1 1 1-.446 1-1-.446-1-1-1zm4 2.4101562 4 3.9980468v.591797h-2.992188l-2.8007808-2.796875zm-3 2 .5.5 2.0898438 2.0898438h-5.1816407zm-3 3.5898438h6.5898438l.0019531.001953h1.4082031v-.001953h2v1h-10z" fill="#4e9b06"/></svg>
\ No newline at end of file diff --git a/icon-themes/breeze_svg/res/sx03223.svg b/icon-themes/breeze_svg/res/sx03223.svg new file mode 100644 index 000000000000..576860153fb7 --- /dev/null +++ b/icon-themes/breeze_svg/res/sx03223.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2v8.992188l-1 1v.007812h1v2h12v-2.998047h1v-.009765l-1-1.0000005v-7.9921875zm1 1h10v5.9921875l-3.9941406-3.9921875h-.0058594v.0019531h-.0058594l-2.4960937 2.4921875-.4941407-.4941406h-.0039062-.0039062l-2.9960938 2.9941406zm2 1c-.554 0-1 .446-1 1s.446 1 1 1 1-.446 1-1-.446-1-1-1zm4 2.4101562 4 3.9980468v.591797h-2.992188l-2.8007808-2.796875zm-3 2 .5.5 2.0898438 2.0898438h-5.1816407zm-3 3.5898438h6.5898438l.0019531.001953h1.4082031v-.001953h2v1h-10z" fill="#4e9b06"/></svg>
\ No newline at end of file diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox index 5767a9e5265f..174a7ca3ca15 100644 --- a/include/sal/log-areas.dox +++ b/include/sal/log-areas.dox @@ -469,6 +469,7 @@ certain functionality. @li @c vcl.emf - EMF/EMF+ processing @li @c vcl.eventtesting @li @c vcl.filter +@li @c vcl.filter.webp @li @c vcl.fonts - font-specific code @li @c vcl.fonts.detail @li @c vcl.gdi - the GDI part of VCL, devices, bitmaps, etc. diff --git a/include/svl/inettype.hxx b/include/svl/inettype.hxx index 13663fd3b260..dc5aa4f3a732 100644 --- a/include/svl/inettype.hxx +++ b/include/svl/inettype.hxx @@ -103,6 +103,7 @@ inline constexpr OUStringLiteral CONTENT_TYPE_STR_IMAGE_PCX = u"image/pcx"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_IMAGE_PNG = u"image/png"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_IMAGE_TIFF = u"image/tiff"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_IMAGE_BMP = u"image/x-MS-bmp"; +inline constexpr OUStringLiteral CONTENT_TYPE_STR_IMAGE_WEBP = u"image/webp"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_INET_MSG_RFC822 = u"message/rfc822"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_INET_MULTI_ALTERNATIVE = u"multipart/alternative"; inline constexpr OUStringLiteral CONTENT_TYPE_STR_INET_MULTI_DIGEST = u"multipart/digest"; @@ -178,6 +179,7 @@ enum INetContentType CONTENT_TYPE_IMAGE_PNG, CONTENT_TYPE_IMAGE_TIFF, CONTENT_TYPE_IMAGE_BMP, + CONTENT_TYPE_IMAGE_WEBP, CONTENT_TYPE_TEXT_HTML, CONTENT_TYPE_TEXT_PLAIN, CONTENT_TYPE_TEXT_URL, diff --git a/include/svtools/imagemgr.hxx b/include/svtools/imagemgr.hxx index 6abe56b08bb0..a2b48247f4d2 100644 --- a/include/svtools/imagemgr.hxx +++ b/include/svtools/imagemgr.hxx @@ -37,6 +37,7 @@ enum class SvImageId { GIF = START + 61, HTML = START + 63, JPG = START + 64, + WEBP = START + 65, Math = START + 68, MathTemplate = START + 69, File = START + 74, diff --git a/include/svx/strings.hrc b/include/svx/strings.hrc index c172cbfa0a3c..a368a4c77906 100644 --- a/include/svx/strings.hrc +++ b/include/svx/strings.hrc @@ -1412,6 +1412,7 @@ #define STR_IMAGE_PCT NC_("STR_IMAGE_PCT", "PCT image") #define STR_IMAGE_SVG NC_("STR_IMAGE_SVG", "SVG image") #define STR_IMAGE_BMP NC_("STR_IMAGE_BMP", "BMP image") +#define STR_IMAGE_WEBP NC_("STR_IMAGE_WEBP", "WebP image") #define STR_IMAGE_UNKNOWN NC_("STR_IMAGE_UNKNOWN", "Unknown") #define STR_SWITCH NC_("STR_SWITCH", "Switch") diff --git a/include/vcl/gfxlink.hxx b/include/vcl/gfxlink.hxx index ad4caebc7b86..30228f339cd7 100644 --- a/include/vcl/gfxlink.hxx +++ b/include/vcl/gfxlink.hxx @@ -47,12 +47,13 @@ enum class GfxLinkType NativeSvg = 9, NativeMov = 10, NativeBmp = 11, - NativePdf = 12, // If a new type is added, make sure to change NativeLast too + NativePdf = 12, + NativeWebp = 13, // If a new type is added, make sure to change NativeLast too // Alias for when the first native type starts and last native // type ends. NativeFirst = NativeGif, - NativeLast = NativePdf, + NativeLast = NativeWebp, }; class Graphic; diff --git a/include/vcl/graphicfilter.hxx b/include/vcl/graphicfilter.hxx index b1eba2b141ed..2d2f071e7d71 100644 --- a/include/vcl/graphicfilter.hxx +++ b/include/vcl/graphicfilter.hxx @@ -89,6 +89,7 @@ namespace o3tl #define IMP_PCD "SVPCD" #define IMP_PBM "SVPBM" #define IMP_DXF "SVDXF" +#define IMP_WEBP "SVIWEBP" #define EXP_BMP "SVBMP" #define EXP_SVMETAFILE "SVMETAFILE" @@ -101,6 +102,7 @@ namespace o3tl #define EXP_TIFF "SVTIFF" #define EXP_EPS "SVEEPS" #define EXP_GIF "SVEGIF" +#define EXP_WEBP "SVEWEBP" inline constexpr OUStringLiteral BMP_SHORTNAME = u"BMP"; @@ -115,6 +117,7 @@ inline constexpr OUStringLiteral WMF_SHORTNAME = u"WMF"; inline constexpr OUStringLiteral EMF_SHORTNAME = u"EMF"; inline constexpr OUStringLiteral SVG_SHORTNAME = u"SVG"; inline constexpr OUStringLiteral PDF_SHORTNAME = u"PDF"; +inline constexpr OUStringLiteral WEBP_SHORTNAME = u"WEBP"; // Info class for all supported file formats @@ -137,6 +140,7 @@ enum class GraphicFileFormat TGA = 0x000e, PSD = 0x000f, EPS = 0x0010, + WEBP = 0x0011, DXF = 0x00f1, MET = 0x00f2, PCT = 0x00f3, @@ -184,6 +188,7 @@ class VCL_DLLPUBLIC GraphicDescriptor final bool ImpDetectTGA( SvStream& rStm, bool bExtendedInfo ); bool ImpDetectPSD( SvStream& rStm, bool bExtendedInfo ); bool ImpDetectEPS( SvStream& rStm, bool bExtendedInfo ); + bool ImpDetectWEBP( SvStream& rStm, bool bExtendedInfo ); bool ImpDetectDXF( SvStream& rStm, bool bExtendedInfo ); bool ImpDetectMET( SvStream& rStm, bool bExtendedInfo ); bool ImpDetectPCT( SvStream& rStm, bool bExtendedInfo ); @@ -374,6 +379,7 @@ public: static ErrCode readPCD(SvStream & rStream, Graphic & rGraphic); static ErrCode readPBM(SvStream & rStream, Graphic & rGraphic); static ErrCode readDXF(SvStream & rStream, Graphic & rGraphic); + static ErrCode readWEBP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType); private: OUString aFilterPath; diff --git a/include/vcl/salctype.hxx b/include/vcl/salctype.hxx index 409fc5a79993..71f256b1986e 100644 --- a/include/vcl/salctype.hxx +++ b/include/vcl/salctype.hxx @@ -37,7 +37,8 @@ enum class ConvertDataFormat TIF, WMF, EMF, - SVG + SVG, + WEBP }; class SvStream; diff --git a/readlicense_oo/license/license.xml b/readlicense_oo/license/license.xml index 389c8c7cd006..9c00f393bf77 100644 --- a/readlicense_oo/license/license.xml +++ b/readlicense_oo/license/license.xml @@ -1129,6 +1129,37 @@ glennrp at users.sourceforge.net<br /> February 3, 2011 </p> </div> + <div class="LIBWEBP"> + <h2>libwebp</h2> + <p>The following software may be included in this product: libwebp. Use of any of this software is governed by + the terms of the license below:</p> + <p>Copyright (c) 2010, Google Inc. All rights reserved.</p> + <p>Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met:</p> + <ol> + <li>Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer.</li> + <li>Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution.</li> + <li>Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission.</li> + </ol> + <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p> + </div> <div class="PAGEMAKER"> <h2>libpagemaker</h2> <p>The following software may be included in this product: libpagemaker. Use of any of this software is governed diff --git a/scp2/source/draw/registryitem_draw.scp b/scp2/source/draw/registryitem_draw.scp index 93cadcaa1ca5..79440c00653b 100644 --- a/scp2/source/draw/registryitem_draw.scp +++ b/scp2/source/draw/registryitem_draw.scp @@ -1092,6 +1092,7 @@ CONDITIONAL_REGISTER_DOC_EXTENSION( Tiff, gid_Module_Prg_Draw_Other_Reg, tiff, CONDITIONAL_REGISTER_DOC_EXTENSION( Xbm, gid_Module_Prg_Draw_Other_Reg, xbm, XBM, X_BITMAP, 5, sdraw.exe, open, Draw ) CONDITIONAL_REGISTER_DOC_EXTENSION( Xpm, gid_Module_Prg_Draw_Other_Reg, xpm, XPM, X_PIXMAP, 5, sdraw.exe, open, Draw ) CONDITIONAL_REGISTER_DOC_EXTENSION( PCD, gid_Module_Prg_Draw_Other_Reg, pcd, PCD, KODAK_PHOTO_CD_IMAGE, 5, sdraw.exe, open, Draw ) +CONDITIONAL_REGISTER_DOC_EXTENSION( Webp, gid_Module_Prg_Draw_Other_Reg, webp, WEBP, WEBP, 5, sdraw.exe, open, Draw ) // registering ms-visio URI scheme handler CONDITIONAL_REGISTER_URI_HANDLER( ms-visio, ms_visio, gid_Module_Prg_Draw_MSO_Reg, SELECT_VISIO ) diff --git a/solenv/sanitizers/ui/svt.suppr b/solenv/sanitizers/ui/svt.suppr index 40c22f896163..188bd9ea0289 100644 --- a/solenv/sanitizers/ui/svt.suppr +++ b/solenv/sanitizers/ui/svt.suppr @@ -1,6 +1,6 @@ svtools/uiconfig/ui/checkboxcontrol.ui://GtkCheckButton[@id='checkbox'] button-no-label svtools/uiconfig/ui/editcontrol.ui://GtkEntry[@id='entry'] no-labelled-by -svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionjpgsb'] no-labelled-by +svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionjpgwebpsb'] no-labelled-by svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionpngsb'] no-labelled-by svtools/uiconfig/ui/graphicexport.ui://GtkLabel[@id='estsizeft'] orphan-label svtools/uiconfig/ui/placeedit.ui://GtkButton[@id='repositoriesRefresh'] button-no-label diff --git a/svtools/inc/bitmaps.hlst b/svtools/inc/bitmaps.hlst index 275b73c83538..5aa57db637ed 100644 --- a/svtools/inc/bitmaps.hlst +++ b/svtools/inc/bitmaps.hlst @@ -39,6 +39,7 @@ inline constexpr OUStringLiteral BMP_DXF_SC = u"res/sx03217.png"; inline constexpr OUStringLiteral BMP_MET_SC = u"res/sx03218.png"; inline constexpr OUStringLiteral BMP_PNG_SC = u"res/sx03219.png"; inline constexpr OUStringLiteral BMP_SVM_SC = u"res/sx03222.png"; +inline constexpr OUStringLiteral BMP_WEBP_SC = u"res/sx03223.png"; inline constexpr OUStringLiteral BMP_GLOBAL_DOC_SC = u"res/sx03226.png"; inline constexpr OUStringLiteral BMP_DRAW_SC = u"res/sx03227.png"; inline constexpr OUStringLiteral BMP_DRAWTEMPLATE_SC = u"res/sx03228.png"; @@ -85,6 +86,7 @@ inline constexpr OUStringLiteral BMP_DXF_LC = u"res/lx03217.png"; inline constexpr OUStringLiteral BMP_MET_LC = u"res/lx03218.png"; inline constexpr OUStringLiteral BMP_PNG_LC = u"res/lx03219.png"; inline constexpr OUStringLiteral BMP_SVM_LC = u"res/lx03222.png"; +inline constexpr OUStringLiteral BMP_WEBP_LC = u"res/lx03223.png"; inline constexpr OUStringLiteral BMP_GLOBAL_DOC_LC = u"res/lx03226.png"; inline constexpr OUStringLiteral BMP_DRAW_LC = u"res/lx03227.png"; inline constexpr OUStringLiteral BMP_DRAWTEMPLATE_LC = u"res/lx03228.png"; diff --git a/svtools/source/filter/exportdialog.cxx b/svtools/source/filter/exportdialog.cxx index 76d90f7b8e06..2d563e02b274 100644 --- a/svtools/source/filter/exportdialog.cxx +++ b/svtools/source/filter/exportdialog.cxx @@ -57,6 +57,7 @@ #define FORMAT_EMF 13 #define FORMAT_EPS 14 #define FORMAT_SVG 16 +#define FORMAT_WEBP 17 #define UNIT_DEFAULT -1 #define UNIT_INCH 0 @@ -89,6 +90,8 @@ static sal_Int16 GetFilterFormat(std::u16string_view rExt) nFormat = FORMAT_EPS; else if ( rExt == u"SVG" ) nFormat = FORMAT_SVG; + else if ( rExt == u"WEBP" ) + nFormat = FORMAT_WEBP; return nFormat; } @@ -293,6 +296,15 @@ uno::Sequence< beans::PropertyValue > ExportDialog::GetFilterData( bool bUpdateC pFilterOptions->WriteInt32("CompressionMode", nCheck); } break; + + case FORMAT_WEBP : + { + assert(mpSbCompression); + pFilterOptions->WriteInt32("Quality", static_cast<sal_Int32>(mpSbCompression->get_value())); + pFilterOptions->WriteBool("Lossless", mxCbLossless->get_active()); + } + break; + } uno::Sequence< beans::PropertyValue > aRet( pFilterOptions->GetFilterData() ); @@ -582,12 +594,13 @@ ExportDialog::ExportDialog(FltCallDialogParameter& rPara, , mxLbResolution(m_xBuilder->weld_combo_box("resolutionlb")) , mxColorDepth(m_xBuilder->weld_widget("colordepth")) , mxLbColorDepth(m_xBuilder->weld_combo_box("colordepthlb")) - , mxJPGQuality(m_xBuilder->weld_widget("jpgquality")) + , mxJPGWEBPQuality(m_xBuilder->weld_widget("jpgwebpquality")) , mxPNGCompression(m_xBuilder->weld_widget("pngcompression")) , mxSbPngCompression(m_xBuilder->weld_scale("compressionpngsb")) , mxNfPngCompression(m_xBuilder->weld_spin_button("compressionpngnf")) - , mxSbJpgCompression(m_xBuilder->weld_scale("compressionjpgsb")) - , mxNfJpgCompression(m_xBuilder->weld_spin_button("compressionjpgnf")) + , mxSbJpgWebpCompression(m_xBuilder->weld_scale("compressionjpgwebpsb")) + , mxNfJpgWebpCompression(m_xBuilder->weld_spin_button("compressionjpgwebpnf")) + , mxCbLossless(m_xBuilder->weld_check_button("losslesscb")) , mxMode(m_xBuilder->weld_widget("mode")) , mxCbInterlaced(m_xBuilder->weld_check_button("interlacedcb")) , mxBMPCompression(m_xBuilder->weld_widget("bmpcompression")) @@ -681,6 +694,8 @@ ExportDialog::ExportDialog(FltCallDialogParameter& rPara, mxCbInterlaced->connect_toggled( LINK( this, ExportDialog, UpdateHdl ) ); + mxCbLossless->connect_toggled( LINK( this, ExportDialog, UpdateHdlLossless ) ); + mxCbSaveTransparency->connect_toggled( LINK( this, ExportDialog, UpdateHdl ) ); mxModifyDimension->connect_toggled( LINK( this, ExportDialog, UpdateLock ) ); @@ -761,15 +776,16 @@ void ExportDialog::createFilterOptions() mxColorDepth->show(); // Quality - mxJPGQuality->show(); + mxJPGWEBPQuality->show(); sal_Int32 nQuality = mpFilterOptionsItem->ReadInt32("Quality", 75); if ((nQuality < 1 ) || (nQuality > 100)) nQuality = 75; - mpSbCompression = mxSbJpgCompression.get(); - mpNfCompression = mxNfJpgCompression.get(); + mpSbCompression = mxSbJpgWebpCompression.get(); + mpNfCompression = mxNfJpgWebpCompression.get(); mpSbCompression->set_range(1, 100); mpNfCompression->set_range(1, 100); mpNfCompression->set_value(nQuality); + mxCbLossless->hide(); // only for WebP } break; case FORMAT_PNG : @@ -852,6 +868,24 @@ void ExportDialog::createFilterOptions() mxRbEPSCompressionNone->set_active( nCompr != 1 ); } break; + case FORMAT_WEBP : + { + // Quality + mxJPGWEBPQuality->show(); + sal_Int32 nQuality = mpFilterOptionsItem->ReadInt32("Quality", 75); + if ((nQuality < 1 ) || (nQuality > 100)) + nQuality = 75; + mpSbCompression = mxSbJpgWebpCompression.get(); + mpNfCompression = mxNfJpgWebpCompression.get(); + mpSbCompression->set_range(1, 100); + mpNfCompression->set_range(1, 100); + mpNfCompression->set_value(nQuality); + + // Lossless + mxCbLossless->set_active(mpFilterOptionsItem->ReadBool("Lossless", true)); + UpdateHdlLossless(*mxCbLossless); + } + break; } } @@ -995,6 +1029,13 @@ IMPL_LINK_NOARG(ExportDialog, UpdateHdl, weld::Toggleable&, void) updateControls(); } +IMPL_LINK_NOARG(ExportDialog, UpdateHdlLossless, weld::Toggleable&, void) +{ + mpSbCompression->set_sensitive(!mxCbLossless->get_active()); + mpNfCompression->set_sensitive(!mxCbLossless->get_active()); + updateControls(); +} + IMPL_LINK_NOARG(ExportDialog, UpdateLock, weld::Toggleable&, void) { if (mxModifyResolution->get_active()) diff --git a/svtools/source/filter/exportdialog.hxx b/svtools/source/filter/exportdialog.hxx index 28953ee0224c..1c7c63953a16 100644 --- a/svtools/source/filter/exportdialog.hxx +++ b/svtools/source/filter/exportdialog.hxx @@ -104,14 +104,16 @@ private: std::unique_ptr<weld::Widget> mxColorDepth; std::unique_ptr<weld::ComboBox> mxLbColorDepth; - std::unique_ptr<weld::Widget> mxJPGQuality; + std::unique_ptr<weld::Widget> mxJPGWEBPQuality; std::unique_ptr<weld::Widget> mxPNGCompression; std::unique_ptr<weld::Scale> mxSbPngCompression; std::unique_ptr<weld::SpinButton> mxNfPngCompression; - std::unique_ptr<weld::Scale> mxSbJpgCompression; - std::unique_ptr<weld::SpinButton> mxNfJpgCompression; + std::unique_ptr<weld::Scale> mxSbJpgWebpCompression; + std::unique_ptr<weld::SpinButton> mxNfJpgWebpCompression; + + std::unique_ptr<weld::CheckButton> mxCbLossless; std::unique_ptr<weld::Widget> mxMode; std::unique_ptr<weld::CheckButton> mxCbInterlaced; @@ -152,6 +154,7 @@ private: DECL_LINK(UpdateHdlMtfSizeY, weld::SpinButton&, void); DECL_LINK(UpdateHdlNfResolution, weld::SpinButton&, void); DECL_LINK(SbCompressionUpdateHdl, weld::Scale&, void); + DECL_LINK(UpdateHdlLossless, weld::Toggleable&, void); DECL_LINK(OK, weld::Button&, void); diff --git a/svtools/source/misc/imagemgr.cxx b/svtools/source/misc/imagemgr.cxx index 58cba39f574f..7ac01619162e 100644 --- a/svtools/source/misc/imagemgr.cxx +++ b/svtools/source/misc/imagemgr.cxx @@ -153,6 +153,7 @@ SvtExtensionResIdMapping_Impl const ExtensionMap_Impl[] = { "url", false, STR_DESCRIPTION_LINK, SvImageId::NONE }, { "vor", false, STR_DESCRIPTION_SOFFICE_TEMPLATE_DOC, SvImageId::WriterTemplate }, { "vxd", true, STR_DESCRIPTION_SYSFILE, SvImageId::NONE }, + { "webp", true, STR_DESCRIPTION_GRAPHIC_DOC, SvImageId::WEBP }, { "wmf", true, STR_DESCRIPTION_GRAPHIC_DOC, SvImageId::WMF }, { "xls", false, STR_DESCRIPTION_EXCEL_DOC, SvImageId::Calc }, { "xlt", false, STR_DESCRIPTION_EXCEL_TEMPLATE_DOC, SvImageId::CalcTemplate }, @@ -568,6 +569,8 @@ static OUString GetImageNameFromList_Impl( SvImageId nImageId, vcl::ImageType eI return BMP_TEXTFILE_LC; case SvImageId::TIFF: return BMP_TIFF_LC; + case SvImageId::WEBP: + return BMP_WEBP_LC; case SvImageId::WMF: return BMP_WMF_LC; case SvImageId::Writer: @@ -667,6 +670,8 @@ static OUString GetImageNameFromList_Impl( SvImageId nImageId, vcl::ImageType eI return BMP_TEXTFILE_SC; case SvImageId::TIFF: return BMP_TIFF_SC; + case SvImageId::WEBP: + return BMP_WEBP_SC; case SvImageId::WMF: return BMP_WMF_SC; case SvImageId::Writer: diff --git a/svtools/uiconfig/ui/graphicexport.ui b/svtools/uiconfig/ui/graphicexport.ui index 223dd3dd456c..27cf6d17f04e 100644 --- a/svtools/uiconfig/ui/graphicexport.ui +++ b/svtools/uiconfig/ui/graphicexport.ui @@ -368,12 +368,12 @@ </packing> </child> <child> - <object class="GtkFrame" id="jpgquality"> + <object class="GtkFrame" id="jpgwebpquality"> <property name="can-focus">False</property> <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <!-- n-columns=2 n-rows=1 --> + <!-- n-columns=2 n-rows=2 --> <object class="GtkGrid" id="grid2"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -381,7 +381,27 @@ <property name="margin-top">6</property> <property name="column-spacing">6</property> <child> - <object class="GtkSpinButton" id="compressionjpgnf"> + <object class="GtkCheckButton" id="losslesscb"> + <property name="label" translatable="yes" context="graphicexport|losslesscb">Lossless</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="use-underline">True</property> + <property name="active">True</property> + <property name="draw-indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="losslesscb-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="graphicexport|extended_tip|losslesscb">Lossless images do not lose quality but result in larger files.</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="compressionjpgwebpnf"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="activates-default">True</property> @@ -389,18 +409,18 @@ <property name="truncate-multiline">True</property> <property name="adjustment">adjustment1</property> <child internal-child="accessible"> - <object class="AtkObject" id="compressionjpgnf-atkobject"> - <property name="AtkObject::accessible-description" translatable="yes" context="graphicexport|extended_tip|compressionjpgnf">Sets the quality for the export. Choose from a low quality with minimal file size, up to a high quality and big file size.</property> + <object class="AtkObject" id="compressionjpgwebpnf-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="graphicexport|extended_tip|compressionjpgwebpnf">Sets the quality for the export. Choose from a low quality with minimal file size, up to a high quality and big file size.</property> </object> </child> </object> <packing> <property name="left-attach">1</property> - <property name="top-attach">0</property> + <property name="top-attach">1</property> </packing> </child> <child> - <object class="GtkScale" id="compressionjpgsb"> + <object class="GtkScale" id="compressionjpgwebpsb"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="valign">center</property> @@ -410,7 +430,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">0</property> + <property name="top-attach">1</property> </packing> </child> </object> diff --git a/svx/source/core/graphichelper.cxx b/svx/source/core/graphichelper.cxx index f98d1ac0a63d..f62b5db08eaa 100644 --- a/svx/source/core/graphichelper.cxx +++ b/svx/source/core/graphichelper.cxx @@ -122,6 +122,9 @@ void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& case GfxLinkType::NativePdf: aExtension = "pdf"; break; + case GfxLinkType::NativeWebp: + aExtension = "webp"; + break; default: break; } @@ -163,6 +166,9 @@ OUString GraphicHelper::GetImageType(const Graphic& rGraphic) case GfxLinkType::NativeBmp: aGraphicTypeString = SvxResId(STR_IMAGE_BMP); break; + case GfxLinkType::NativeWebp: + aGraphicTypeString = SvxResId(STR_IMAGE_WEBP); + break; default: break; } diff --git a/svx/source/gallery2/galtheme.cxx b/svx/source/gallery2/galtheme.cxx index dff3696b8cd8..4a9d10e609ff 100644 --- a/svx/source/gallery2/galtheme.cxx +++ b/svx/source/gallery2/galtheme.cxx @@ -407,6 +407,7 @@ bool GalleryTheme::InsertGraphic(const Graphic& rGraphic, sal_uInt32 nInsertPos) case GfxLinkType::NativeMet: nExportFormat = ConvertDataFormat::MET; break; case GfxLinkType::NativePct: nExportFormat = ConvertDataFormat::PCT; break; case GfxLinkType::NativeSvg: nExportFormat = ConvertDataFormat::SVG; break; + case GfxLinkType::NativeWebp: nExportFormat = ConvertDataFormat::WEBP; break; default: break; } diff --git a/svx/source/xml/xmlgrhlp.cxx b/svx/source/xml/xmlgrhlp.cxx index 0604f0f95d8e..b95130a8a658 100644 --- a/svx/source/xml/xmlgrhlp.cxx +++ b/svx/source/xml/xmlgrhlp.cxx @@ -690,6 +690,7 @@ OUString SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference<css::graphic::X break; } case GfxLinkType::NativePdf: aExtension = ".pdf"; break; + case GfxLinkType::NativeWebp: aExtension = ".webp"; break; default: aExtension = ".grf"; diff --git a/svx/source/xoutdev/_xoutbmp.cxx b/svx/source/xoutdev/_xoutbmp.cxx index 8eaec8e5a5fc..cb690df32623 100644 --- a/svx/source/xoutdev/_xoutbmp.cxx +++ b/svx/source/xoutdev/_xoutbmp.cxx @@ -34,6 +34,7 @@ constexpr OUStringLiteral FORMAT_BMP = u"bmp"; constexpr OUStringLiteral FORMAT_GIF = u"gif"; constexpr OUStringLiteral FORMAT_JPG = u"jpg"; constexpr OUStringLiteral FORMAT_PNG = u"png"; +constexpr OUStringLiteral FORMAT_WEBP = u"webp"; using namespace com::sun::star; @@ -182,6 +183,7 @@ ErrCode XOutBitmap::WriteGraphic( const Graphic& rGraphic, OUString& rFileName, case GfxLinkType::NativeJpg: aExt = FORMAT_JPG; break; case GfxLinkType::NativePng: aExt = FORMAT_PNG; break; + case GfxLinkType::NativeWebp: aExt = FORMAT_WEBP; break; default: break; diff --git a/vcl/CppunitTest_vcl_filters_test.mk b/vcl/CppunitTest_vcl_filters_test.mk index ab5108f51b1c..f9f8e40cca98 100644 --- a/vcl/CppunitTest_vcl_filters_test.mk +++ b/vcl/CppunitTest_vcl_filters_test.mk @@ -22,6 +22,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_filters_test, \ vcl/qa/cppunit/graphicfilter/filters-test \ vcl/qa/cppunit/graphicfilter/filters-tiff-test \ vcl/qa/cppunit/graphicfilter/filters-tga-test \ + vcl/qa/cppunit/graphicfilter/filters-webp-test \ )) $(eval $(call gb_CppunitTest_set_include,vcl_filters_test,\ diff --git a/vcl/Executable_webpfuzzer.mk b/vcl/Executable_webpfuzzer.mk new file mode 100644 index 000000000000..3851fbe52cd1 --- /dev/null +++ b/vcl/Executable_webpfuzzer.mk @@ -0,0 +1,45 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,webpfuzzer)) + +$(eval $(call gb_Executable_use_api,webpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,webpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,webpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,webpfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,webpfuzzer,\ + $(fuzzer_statics) \ +)) + +$(eval $(call gb_Executable_add_exception_objects,webpfuzzer,\ + vcl/workben/webpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,webpfuzzer,\ + $(LIB_FUZZING_ENGINE) \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index ebf87d7e8b70..9182f223eb93 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -90,6 +90,7 @@ $(eval $(call gb_Library_use_externals,vcl,\ libeot \ libjpeg \ libpng \ + libwebp \ mdds_headers \ )) @@ -484,6 +485,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/filter/wmf/wmfexternal \ vcl/source/filter/wmf/wmfwr \ vcl/source/filter/png/pngwrite \ + vcl/source/filter/webp/reader \ + vcl/source/filter/webp/writer \ vcl/source/font/DirectFontSubstitution \ vcl/source/font/Feature \ vcl/source/font/FeatureCollector \ diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk index efca0207b6b1..090e517b0d0a 100644 --- a/vcl/Module_vcl.mk +++ b/vcl/Module_vcl.mk @@ -189,6 +189,7 @@ $(eval $(call gb_Module_add_targets,vcl,\ Executable_htmlfuzzer \ Executable_sftfuzzer \ Executable_dbffuzzer \ + Executable_webpfuzzer \ )) endif diff --git a/vcl/inc/filter/WebpReader.hxx b/vcl/inc/filter/WebpReader.hxx new file mode 100644 index 000000000000..fd8cc4894a26 --- /dev/null +++ b/vcl/inc/filter/WebpReader.hxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vcl/graph.hxx> + +VCL_DLLPUBLIC bool ImportWebpGraphic(SvStream& rStream, Graphic& rGraphic); + +bool ReadWebpInfo(SvStream& rStream, Size& pixelSize, sal_uInt16& bitsPerPixel, bool& hasAlpha); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/filter/WebpWriter.hxx b/vcl/inc/filter/WebpWriter.hxx new file mode 100644 index 000000000000..d3b6431c63ff --- /dev/null +++ b/vcl/inc/filter/WebpWriter.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <tools/stream.hxx> +#include <vcl/graph.hxx> +#include <vcl/FilterConfigItem.hxx> + +VCL_DLLPUBLIC bool ExportWebpGraphic(SvStream& rStream, const Graphic& rGraphic, + FilterConfigItem* pFilterConfigItem); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/GraphicFormatDetector.hxx b/vcl/inc/graphic/GraphicFormatDetector.hxx index f2f0393caeee..34a8b16a2c5d 100644 --- a/vcl/inc/graphic/GraphicFormatDetector.hxx +++ b/vcl/inc/graphic/GraphicFormatDetector.hxx @@ -77,6 +77,7 @@ public: bool checkTGA(); bool checkMOV(); bool checkPDF(); + bool checkWEBP(); }; } diff --git a/vcl/inc/graphic/UnoGraphicDescriptor.hxx b/vcl/inc/graphic/UnoGraphicDescriptor.hxx index 6a233e09ae16..096b30fd694e 100644 --- a/vcl/inc/graphic/UnoGraphicDescriptor.hxx +++ b/vcl/inc/graphic/UnoGraphicDescriptor.hxx @@ -51,6 +51,7 @@ #define MIMETYPE_EMF "image/x-emf" #define MIMETYPE_SVG "image/svg+xml" #define MIMETYPE_PDF "application/pdf" +#define MIMETYPE_WEBP "image/webp" inline constexpr OUStringLiteral MIMETYPE_VCLGRAPHIC = u"image/x-vclgraphic"; namespace comphelper { class PropertySetInfo; } diff --git a/vcl/qa/cppunit/GraphicDescriptorTest.cxx b/vcl/qa/cppunit/GraphicDescriptorTest.cxx index 652393ae9b63..865202cedbf5 100644 --- a/vcl/qa/cppunit/GraphicDescriptorTest.cxx +++ b/vcl/qa/cppunit/GraphicDescriptorTest.cxx @@ -34,6 +34,7 @@ class GraphicDescriptorTest : public test::BootstrapFixtureBase void testDetectGIF(); void testDetectTIF(); void testDetectBMP(); + void testDetectWEBP(); CPPUNIT_TEST_SUITE(GraphicDescriptorTest); CPPUNIT_TEST(testDetectPNG); @@ -41,6 +42,7 @@ class GraphicDescriptorTest : public test::BootstrapFixtureBase CPPUNIT_TEST(testDetectGIF); CPPUNIT_TEST(testDetectTIF); CPPUNIT_TEST(testDetectBMP); + CPPUNIT_TEST(testDetectWEBP); CPPUNIT_TEST_SUITE_END(); }; @@ -138,6 +140,20 @@ void GraphicDescriptorTest::testDetectBMP() CPPUNIT_ASSERT_EQUAL(MapUnit::MapMM, aGraphic.GetPrefMapMode().GetMapUnit()); } +void GraphicDescriptorTest::testDetectWEBP() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, u"webp"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::WEBP, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(tools::Long(100), aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(100), aDescriptor.GetSizePixel().Height()); +} + } // namespace CPPUNIT_TEST_SUITE_REGISTRATION(GraphicDescriptorTest); diff --git a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx index 264a0e8cd48d..4c16bfc82e1b 100644 --- a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx +++ b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx @@ -47,6 +47,7 @@ class GraphicFormatDetectorTest : public test::BootstrapFixtureBase void testDetectSVGZ(); void testDetectPDF(); void testDetectEPS(); + void testDetectWEBP(); void testMatchArray(); void testCheckArrayForMatchingStrings(); @@ -67,6 +68,7 @@ class GraphicFormatDetectorTest : public test::BootstrapFixtureBase CPPUNIT_TEST(testDetectSVGZ); CPPUNIT_TEST(testDetectPDF); CPPUNIT_TEST(testDetectEPS); + CPPUNIT_TEST(testDetectWEBP); CPPUNIT_TEST(testMatchArray); CPPUNIT_TEST(testCheckArrayForMatchingStrings); CPPUNIT_TEST_SUITE_END(); @@ -312,6 +314,21 @@ void GraphicFormatDetectorTest::testDetectEPS() CPPUNIT_ASSERT_EQUAL(OUString("EPS"), rFormatExtension); } +void GraphicFormatDetectorTest::testDetectWEBP() +{ + SvFileStream aFileStream(getFullUrl(u"TypeDetectionExample.webp"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "WEBP"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkWEBP()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(vcl::peekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("WEBP"), rFormatExtension); +} + void GraphicFormatDetectorTest::testMatchArray() { std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n" diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx index 44ad1df12829..2e398c544c79 100644 --- a/vcl/qa/cppunit/GraphicTest.cxx +++ b/vcl/qa/cppunit/GraphicTest.cxx @@ -81,6 +81,7 @@ private: void testLoadXPM(); void testLoadPCX(); void testLoadEPS(); + void testLoadWEBP(); void testAvailableThreaded(); @@ -118,6 +119,7 @@ private: CPPUNIT_TEST(testLoadXPM); CPPUNIT_TEST(testLoadPCX); CPPUNIT_TEST(testLoadEPS); + CPPUNIT_TEST(testLoadWEBP); CPPUNIT_TEST(testAvailableThreaded); @@ -305,7 +307,7 @@ void GraphicTest::testUnloadedGraphic() void GraphicTest::testUnloadedGraphicLoading() { - const OUString aFormats[] = { "png", "gif", "jpg", "tif" }; + const OUString aFormats[] = { "png", "gif", "jpg", "tif", "webp" }; for (OUString const& sFormat : aFormats) { @@ -1310,6 +1312,14 @@ void GraphicTest::testLoadEPS() CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aGraphic.GetType()); } +void GraphicTest::testLoadWEBP() +{ + Graphic aGraphic = loadGraphic(u"TypeDetectionExample.webp"); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(tools::Long(10), aGraphic.GetSizePixel().Height()); +} + void GraphicTest::testAvailableThreaded() { Graphic jpgGraphic1 = importUnloadedGraphic(u"TypeDetectionExample.jpg"); diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.webp b/vcl/qa/cppunit/data/TypeDetectionExample.webp Binary files differnew file mode 100644 index 000000000000..e85ae121637b --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.webp diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossless.webp b/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossless.webp Binary files differnew file mode 100644 index 000000000000..abb67cc5f4b6 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossless.webp diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossy.webp b/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossy.webp Binary files differnew file mode 100644 index 000000000000..c587b1bb22c0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/alpha_lossy.webp diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/webp/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/webp/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossless.webp b/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossless.webp Binary files differnew file mode 100644 index 000000000000..b22ebc3b28bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossless.webp diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossy.webp b/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossy.webp Binary files differnew file mode 100644 index 000000000000..c118febb0e9a --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/noalpha_lossy.webp diff --git a/vcl/qa/cppunit/graphicfilter/data/webp/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/webp/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/webp/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/filters-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-test.cxx index 22078cf9de65..f10de06fc837 100644 --- a/vcl/qa/cppunit/graphicfilter/filters-test.cxx +++ b/vcl/qa/cppunit/graphicfilter/filters-test.cxx @@ -145,6 +145,8 @@ void VclFiltersTest::testExportImport() checkExportImport(u"bmp"); fprintf(stderr, "Check ExportImport TIF\n"); checkExportImport(u"tif"); + fprintf(stderr, "Check ExportImport WEBP\n"); + checkExportImport(u"webp"); } void VclFiltersTest::testCVEs() diff --git a/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx new file mode 100644 index 000000000000..90528199c0ba --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/filters-webp-test.cxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <unotest/filters-test.hxx> +#include <test/bootstrapfixture.hxx> +#include <vcl/FilterConfigItem.hxx> +#include <bitmap/BitmapWriteAccess.hxx> +#include <tools/stream.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <graphic/GraphicFormatDetector.hxx> +#include <filter/WebpReader.hxx> +#include <comphelper/propertyvalue.hxx> + +using namespace css; + +/* Implementation of Filters test */ + +class WebpFilterTest : public test::FiltersTest, public test::BootstrapFixture +{ +public: + WebpFilterTest() + : BootstrapFixture(true, false) + { + } + + virtual bool load(const OUString&, const OUString& rURL, const OUString&, SfxFilterFlags, + SotClipboardFormatId, unsigned int) override; + + /** + * Ensure CVEs remain unbroken + */ + void testCVEs(); + + void testRoundtripLossless(); + void testRoundtripLossy(); + void testReadAlphaLossless(); + void testReadAlphaLossy(); + void testReadNoAlphaLossless(); + void testReadNoAlphaLossy(); + + CPPUNIT_TEST_SUITE(WebpFilterTest); + CPPUNIT_TEST(testCVEs); + CPPUNIT_TEST(testRoundtripLossless); + CPPUNIT_TEST(testRoundtripLossy); + CPPUNIT_TEST(testReadAlphaLossless); + CPPUNIT_TEST(testReadAlphaLossy); + CPPUNIT_TEST(testReadNoAlphaLossless); + CPPUNIT_TEST(testReadNoAlphaLossy); + CPPUNIT_TEST_SUITE_END(); + +private: + void testRoundtrip(bool lossy); + void testRead(bool lossy, bool alpha); +}; + +bool WebpFilterTest::load(const OUString&, const OUString& rURL, const OUString&, SfxFilterFlags, + SotClipboardFormatId, unsigned int) +{ + SvFileStream aFileStream(rURL, StreamMode::READ); + Graphic aGraphic; + return ImportWebpGraphic(aFileStream, aGraphic); +} + +void WebpFilterTest::testCVEs() +{ +#ifndef DISABLE_CVE_TESTS + testDir(OUString(), m_directories.getURLFromSrc(u"/vcl/qa/cppunit/graphicfilter/data/webp/")); +#endif +} + +void WebpFilterTest::testRoundtripLossless() { testRoundtrip(false); } + +void WebpFilterTest::testRoundtripLossy() { testRoundtrip(true); } + +void WebpFilterTest::testRoundtrip(bool lossy) +{ + // Do not use just 2x2, lossy saving would change colors. + Bitmap aBitmap(Size(20, 20), vcl::PixelFormat::N24_BPP); + AlphaMask aAlpha(Size(20, 20)); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->SetFillColor(COL_WHITE); + pAccess->FillRect(tools::Rectangle(Point(0, 0), Size(10, 10))); + pAccess->SetFillColor(COL_BLACK); + pAccess->FillRect(tools::Rectangle(Point(10, 0), Size(10, 10))); + pAccess->SetFillColor(COL_LIGHTRED); + pAccess->FillRect(tools::Rectangle(Point(0, 10), Size(10, 10))); + pAccess->SetFillColor(COL_BLUE); + pAccess->FillRect(tools::Rectangle(Point(10, 10), Size(10, 10))); + AlphaScopedWriteAccess pAccessAlpha(aAlpha); + pAccessAlpha->SetFillColor(BitmapColor(0)); // opaque + pAccessAlpha->FillRect(tools::Rectangle(Point(0, 0), Size(10, 10))); + pAccessAlpha->FillRect(tools::Rectangle(Point(10, 0), Size(10, 10))); + pAccessAlpha->FillRect(tools::Rectangle(Point(0, 10), Size(10, 10))); + pAccessAlpha->SetFillColor(BitmapColor(64, 64, 64)); + pAccessAlpha->FillRect(tools::Rectangle(Point(10, 10), Size(10, 10))); + } + BitmapEx aBitmapEx(aBitmap, aAlpha); + + SvMemoryStream aStream; + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName(u"webp"); + css::uno::Sequence<css::beans::PropertyValue> aFilterData{ + comphelper::makePropertyValue("Lossless", !lossy), + comphelper::makePropertyValue("Quality", sal_Int32(100)) + }; + rFilter.ExportGraphic(Graphic(aBitmapEx), "none", aStream, nFilterFormat, &aFilterData); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + Graphic aGraphic; + ErrCode bResult = rFilter.ImportGraphic(aGraphic, "none", aStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + CPPUNIT_ASSERT_EQUAL(GfxLinkType::NativeWebp, aGraphic.GetGfxLink().GetType()); + BitmapEx aResultBitmap = aGraphic.GetBitmapEx(); + CPPUNIT_ASSERT_EQUAL(Size(20, 20), aResultBitmap.GetSizePixel()); + CPPUNIT_ASSERT(aResultBitmap.IsAlpha()); + + { + Bitmap tmpBitmap = aResultBitmap.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(tmpBitmap); + // Note that x,y are swapped. + CPPUNIT_ASSERT_EQUAL(COL_WHITE, Color(pAccess->GetPixel(0, 0))); + CPPUNIT_ASSERT_EQUAL(COL_BLACK, Color(pAccess->GetPixel(0, 19))); + if (lossy) + { + CPPUNIT_ASSERT_LESS(sal_uInt16(3), + pAccess->GetPixel(19, 0).GetColorError(COL_LIGHTRED)); + CPPUNIT_ASSERT_LESS(sal_uInt16(3), pAccess->GetPixel(19, 19).GetColorError(COL_BLUE)); + } + else + { + CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, Color(pAccess->GetPixel(19, 0))); + CPPUNIT_ASSERT_EQUAL(COL_BLUE, Color(pAccess->GetPixel(19, 19))); + } + AlphaMask tmpAlpha = aResultBitmap.GetAlpha(); + AlphaMask::ScopedReadAccess pAccessAlpha(tmpAlpha); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 19)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(19, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(64), pAccessAlpha->GetPixelIndex(19, 19)); + } + + aStream.Seek(STREAM_SEEK_TO_BEGIN); + vcl::GraphicFormatDetector aDetector(aStream, ""); + + CPPUNIT_ASSERT_EQUAL(true, aDetector.detect()); + CPPUNIT_ASSERT_EQUAL(true, aDetector.checkWEBP()); + CPPUNIT_ASSERT_EQUAL(OUString(u"WEBP"), aDetector.msDetectedFormat); +} + +void WebpFilterTest::testReadAlphaLossless() { testRead(false, true); } + +void WebpFilterTest::testReadAlphaLossy() { testRead(true, true); } + +void WebpFilterTest::testReadNoAlphaLossless() { testRead(false, false); } + +void WebpFilterTest::testReadNoAlphaLossy() { testRead(true, false); } + +void WebpFilterTest::testRead(bool lossy, bool alpha) +{ + // Read a file created in GIMP and check it's read correctly. + OUString file = m_directories.getURLFromSrc(u"/vcl/qa/cppunit/graphicfilter/data/webp/") + + (alpha ? u"alpha" : u"noalpha") + "_" + (lossy ? u"lossy" : u"lossless") + + ".webp"; + SvFileStream aFileStream(file, StreamMode::READ); + Graphic aGraphic; + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, "none", aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + CPPUNIT_ASSERT_EQUAL(GfxLinkType::NativeWebp, aGraphic.GetGfxLink().GetType()); + BitmapEx aResultBitmap = aGraphic.GetBitmapEx(); + CPPUNIT_ASSERT_EQUAL(Size(10, 10), aResultBitmap.GetSizePixel()); + CPPUNIT_ASSERT_EQUAL(alpha, aResultBitmap.IsAlpha()); + + { + Bitmap tmpBitmap = aResultBitmap.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(tmpBitmap); + // Note that x,y are swapped. + if (lossy) + CPPUNIT_ASSERT_LESS(sal_uInt16(2), pAccess->GetPixel(0, 0).GetColorError(COL_LIGHTRED)); + else + CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, Color(pAccess->GetPixel(0, 0))); + CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, Color(pAccess->GetPixel(9, 9))); + if (alpha) + { + AlphaMask tmpAlpha = aResultBitmap.GetAlpha(); + AlphaMask::ScopedReadAccess pAccessAlpha(tmpAlpha); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), pAccessAlpha->GetPixelIndex(0, 0)); + CPPUNIT_ASSERT_EQUAL(sal_uInt8(255), pAccessAlpha->GetPixelIndex(0, 9)); + } + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(WebpFilterTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/FilterConfigCache.cxx b/vcl/source/filter/FilterConfigCache.cxx index 370e8cffed8b..3430d0251cd7 100644 --- a/vcl/source/filter/FilterConfigCache.cxx +++ b/vcl/source/filter/FilterConfigCache.cxx @@ -41,10 +41,10 @@ using namespace ::com::sun::star::configuration ; const char* FilterConfigCache::FilterConfigCacheEntry::InternalPixelFilterNameList[] = { - IMP_BMP, IMP_GIF, IMP_PNG, IMP_JPEG, IMP_TIFF, + IMP_BMP, IMP_GIF, IMP_PNG, IMP_JPEG, IMP_TIFF, IMP_WEBP, IMP_XBM, IMP_XPM, IMP_TGA, IMP_PICT, IMP_MET, IMP_RAS, IMP_PCX, IMP_MOV, IMP_PSD, IMP_PCD, IMP_PBM, IMP_DXF, - EXP_BMP, EXP_GIF, EXP_PNG, EXP_JPEG, EXP_TIFF, + EXP_BMP, EXP_GIF, EXP_PNG, EXP_JPEG, EXP_TIFF, EXP_WEBP, nullptr }; @@ -226,6 +226,8 @@ const char* FilterConfigCache::InternalFilterListForSvxLight[] = "xpm","1","SVIXPM", "svg","1","SVISVG", "svg","2","SVESVG", + "webp","1","SVIWEBP", + "webp","2","SVEWEBP", nullptr }; diff --git a/vcl/source/filter/GraphicFormatDetector.cxx b/vcl/source/filter/GraphicFormatDetector.cxx index 6c8df32a456e..2dddcfa0f9ae 100644 --- a/vcl/source/filter/GraphicFormatDetector.cxx +++ b/vcl/source/filter/GraphicFormatDetector.cxx @@ -274,6 +274,16 @@ bool peekGraphicFormat(SvStream& rStream, OUString& rFormatExtension, bool bTest } } + if (!bTest || rFormatExtension.startsWith("WEBP")) + { + bSomethingTested = true; + if (aDetector.checkWEBP()) + { + rFormatExtension = aDetector.msDetectedFormat; + return true; + } + } + return bTest && !bSomethingTested; } @@ -816,6 +826,18 @@ bool GraphicFormatDetector::checkPDF() return false; } +bool GraphicFormatDetector::checkWEBP() +{ + if (maFirstBytes[0] == 'R' && maFirstBytes[1] == 'I' && maFirstBytes[2] == 'F' + && maFirstBytes[3] == 'F' && maFirstBytes[8] == 'W' && maFirstBytes[9] == 'E' + && maFirstBytes[10] == 'B' && maFirstBytes[11] == 'P') + { + msDetectedFormat = "WEBP"; + return true; + } + return false; +} + } // vcl namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx index ae04ede2dacf..6e486035b777 100644 --- a/vcl/source/filter/graphicfilter.cxx +++ b/vcl/source/filter/graphicfilter.cxx @@ -64,6 +64,8 @@ #include <filter/GifWriter.hxx> #include <filter/BmpReader.hxx> #include <filter/BmpWriter.hxx> +#include <filter/WebpReader.hxx> +#include <filter/WebpWriter.hxx> #include <osl/module.hxx> #include <com/sun/star/uno/Reference.h> #include <com/sun/star/awt/Size.hpp> @@ -82,6 +84,7 @@ #include <memory> #include <mutex> #include <string_view> +#include <o3tl/string_view.hxx> #include <vcl/TypeSerializer.hxx> #include "FilterConfigCache.hxx" @@ -90,6 +93,24 @@ #include <graphic/GraphicFormatDetector.hxx> #include <graphic/GraphicReader.hxx> +// Support for GfxLinkType::NativeWebp is so far disabled, +// as enabling it would write .webp images e.g. to .odt documents, +// making those images unreadable for older readers. So for now +// disable the support so that .webp images will be written out as .png, +// and somewhen later enable the support unconditionally. +static bool supportNativeWebp() +{ + const char* const testname = getenv("LO_TESTNAME"); + if(testname == nullptr) + return false; + // Enable support only for those unittests that test it. + if( std::string_view("_anonymous_namespace___GraphicTest__testUnloadedGraphicLoading_") == testname + || std::string_view("VclFiltersTest__testExportImport_") == testname + || o3tl::starts_with(std::string_view(testname), "WebpFilterTest__")) + return true; + return false; +} + static std::vector< GraphicFilter* > gaFilterHdlList; static std::mutex& getListMutex() @@ -899,6 +920,13 @@ Graphic GraphicFilter::ImportUnloadedGraphic(SvStream& rIStream, sal_uInt64 size { eLinkType = GfxLinkType::NativeMet; } + else if (aFilterName.equalsIgnoreAsciiCase(IMP_WEBP)) + { + if(supportNativeWebp()) + eLinkType = GfxLinkType::NativeWebp; + else + nStatus = ERRCODE_GRFILTER_FILTERERROR; + } else { nStatus = ERRCODE_GRFILTER_FILTERERROR; @@ -1305,6 +1333,18 @@ ErrCode GraphicFilter::readDXF(SvStream & rStream, Graphic & rGraphic) return ERRCODE_GRFILTER_FILTERERROR; } +ErrCode GraphicFilter::readWEBP(SvStream & rStream, Graphic & rGraphic, GfxLinkType & rLinkType) +{ + if (ImportWebpGraphic(rStream, rGraphic)) + { + if(supportNativeWebp()) + rLinkType = GfxLinkType::NativeWebp; + return ERRCODE_NONE; + } + else + return ERRCODE_GRFILTER_FILTERERROR; +} + ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream, sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags, const css::uno::Sequence< css::beans::PropertyValue >* /*pFilterData*/, @@ -1455,6 +1495,10 @@ ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, { nStatus = readDXF(rIStream, rGraphic); } + else if (aFilterName.equalsIgnoreAsciiCase(IMP_WEBP)) + { + nStatus = readWEBP(rIStream, rGraphic, eLinkType); + } else nStatus = ERRCODE_GRFILTER_FILTERERROR; } @@ -1840,6 +1884,14 @@ ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& r } } } + else if (aFilterName.equalsIgnoreAsciiCase(EXP_WEBP)) + { + if (!ExportWebpGraphic(rOStm, aGraphic, &aConfigItem)) + nStatus = ERRCODE_GRFILTER_FORMATERROR; + + if( rOStm.GetError() ) + nStatus = ERRCODE_GRFILTER_IOERROR; + } else nStatus = ERRCODE_GRFILTER_FILTERERROR; } @@ -1882,6 +1934,7 @@ IMPL_LINK( GraphicFilter, FilterCallback, ConvertData&, rData, bool ) case ConvertDataFormat::WMF: aShortName = WMF_SHORTNAME; break; case ConvertDataFormat::EMF: aShortName = EMF_SHORTNAME; break; case ConvertDataFormat::SVG: aShortName = SVG_SHORTNAME; break; + case ConvertDataFormat::WEBP: aShortName = WEBP_SHORTNAME; break; default: break; diff --git a/vcl/source/filter/graphicfilter2.cxx b/vcl/source/filter/graphicfilter2.cxx index 0360c51d3347..5f73d570d9f6 100644 --- a/vcl/source/filter/graphicfilter2.cxx +++ b/vcl/source/filter/graphicfilter2.cxx @@ -25,6 +25,7 @@ #include <vcl/outdev.hxx> #include <vcl/graphicfilter.hxx> #include <unotools/ucbstreamhelper.hxx> +#include <filter/WebpReader.hxx> #include "graphicfilter_internal.hxx" #define DATA_SIZE 640 @@ -87,6 +88,7 @@ bool GraphicDescriptor::Detect( bool bExtendedInfo ) else if ( ImpDetectPSD( rStm, bExtendedInfo ) ) bRet = true; else if ( ImpDetectEPS( rStm, bExtendedInfo ) ) bRet = true; else if ( ImpDetectPCD( rStm, bExtendedInfo ) ) bRet = true; + else if ( ImpDetectWEBP( rStm, bExtendedInfo ) ) bRet = true; rStm.SetEndian( nOldFormat ); } @@ -1142,6 +1144,36 @@ bool GraphicDescriptor::ImpDetectSVG( SvStream& /*rStm*/, bool /*bExtendedInfo*/ return bRet; } +bool GraphicDescriptor::ImpDetectWEBP( SvStream& rStm, bool bExtendedInfo ) +{ + sal_uInt32 nTemp32 = 0; + bool bRet = false; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetEndian( SvStreamEndian::BIG ); + rStm.ReadUInt32( nTemp32 ); + + if ( nTemp32 == 0x52494646 ) + { + rStm.ReadUInt32( nTemp32 ); // skip + rStm.ReadUInt32( nTemp32 ); + if ( nTemp32 == 0x57454250 ) + { + nFormat = GraphicFileFormat::WEBP; + bRet = true; + + if ( bExtendedInfo ) + { + rStm.Seek(nStmPos); + ReadWebpInfo(rStm, aPixSize, nBitsPerPixel, bIsAlpha ); + bIsTransparent = bIsAlpha; + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + OUString GraphicDescriptor::GetImportFormatShortName( GraphicFileFormat nFormat ) { const char *pKeyName = nullptr; @@ -1171,6 +1203,7 @@ OUString GraphicDescriptor::GetImportFormatShortName( GraphicFileFormat nFormat case GraphicFileFormat::WMF : pKeyName = "wmf"; break; case GraphicFileFormat::EMF : pKeyName = "emf"; break; case GraphicFileFormat::SVG : pKeyName = "svg"; break; + case GraphicFileFormat::WEBP : pKeyName = "webp"; break; default: assert(false); } diff --git a/vcl/source/filter/webp/reader.cxx b/vcl/source/filter/webp/reader.cxx new file mode 100644 index 000000000000..e8c885053965 --- /dev/null +++ b/vcl/source/filter/webp/reader.cxx @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <vcl/graph.hxx> +#include <tools/stream.hxx> +#include <filter/WebpReader.hxx> +#include <bitmap/BitmapWriteAccess.hxx> +#include <salinst.hxx> +#include <sal/log.hxx> +#include <unotools/configmgr.hxx> +#include <svdata.hxx> + +#include <webp/decode.h> + +static bool readWebpInfo(SvStream& stream, std::vector<uint8_t>& data, + WebPBitstreamFeatures& features) +{ + for (;;) + { + // Read 4096 (more) bytes. + size_t lastSize = data.size(); + data.resize(data.size() + 4096); + sal_Size nBytesRead = stream.ReadBytes(data.data() + lastSize, 4096); + if (nBytesRead <= 0) + return false; + data.resize(lastSize + nBytesRead); + int status = WebPGetFeatures(data.data(), data.size(), &features); + if (status == VP8_STATUS_OK) + break; + if (status == VP8_STATUS_NOT_ENOUGH_DATA) + continue; // Try again with 4096 more bytes read. + return false; + } + return true; +} + +static bool readWebp(SvStream& stream, Graphic& graphic) +{ + WebPDecoderConfig config; + if (!WebPInitDecoderConfig(&config)) + { + SAL_WARN("vcl.filter.webp", "WebPInitDecoderConfig() failed"); + return false; + } + // This unique_ptr is here just to ensure WebPFreeDecBuffer() is called at the end, + // it doesn't actually own the data as such. + std::unique_ptr<WebPDecBuffer, decltype(&WebPFreeDecBuffer)> freeBuffer(&config.output, + WebPFreeDecBuffer); + std::vector<uint8_t> data; + if (!readWebpInfo(stream, data, config.input)) + return false; + // Here various parts of 'config' can be altered if wanted. + const int& width = config.input.width; + const int& height = config.input.height; + const int& has_alpha = config.input.has_alpha; + + if (width > SAL_MAX_INT32 / 8 || height > SAL_MAX_INT32 / 8) + return false; // avoid overflows later + + const bool bFuzzing = utl::ConfigManager::IsFuzzing(); + const bool bSupportsBitmap32 = bFuzzing || ImplGetSVData()->mpDefInst->supportsBitmap32(); + + Bitmap bitmap; + AlphaMask bitmapAlpha; + if (bSupportsBitmap32 && has_alpha) + { + bitmap = Bitmap(Size(width, height), vcl::PixelFormat::N32_BPP); + } + else + { + bitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); + if (has_alpha) + bitmapAlpha = AlphaMask(Size(width, height)); + } + + BitmapScopedWriteAccess access(bitmap); + // If data cannot be read directly into the bitmap, read data first to this buffer and then convert. + std::vector<uint8_t> tmpRgbaData; + enum class PixelMode + { + DirectRead, // read data directly to the bitmap + Split, // read to tmp buffer and split to rgb and alpha + SetPixel // read to tmp buffer and use setPixel() + }; + PixelMode pixelMode = PixelMode::SetPixel; + + config.output.width = width; + config.output.height = height; + config.output.is_external_memory = 1; + if (bSupportsBitmap32 && has_alpha) + { + switch (RemoveScanline(access->GetScanlineFormat())) + { + // Our bitmap32 code expects premultiplied. + case ScanlineFormat::N32BitTcRgba: + config.output.colorspace = MODE_rgbA; + pixelMode = PixelMode::DirectRead; + break; + case ScanlineFormat::N32BitTcBgra: + config.output.colorspace = MODE_bgrA; + pixelMode = PixelMode::DirectRead; + break; + case ScanlineFormat::N32BitTcArgb: + config.output.colorspace = MODE_Argb; + pixelMode = PixelMode::DirectRead; + break; + default: + config.output.colorspace = MODE_RGBA; + pixelMode = PixelMode::SetPixel; + break; + } + } + else + { + if (has_alpha) + { + switch (RemoveScanline(access->GetScanlineFormat())) + { + case ScanlineFormat::N24BitTcRgb: + config.output.colorspace = MODE_RGBA; + pixelMode = PixelMode::Split; + break; + case ScanlineFormat::N24BitTcBgr: + config.output.colorspace = MODE_BGRA; + pixelMode = PixelMode::Split; + break; + default: + config.output.colorspace = MODE_RGBA; + pixelMode = PixelMode::SetPixel; + break; + } + } + else + { + switch (RemoveScanline(access->GetScanlineFormat())) + { + case ScanlineFormat::N24BitTcRgb: + config.output.colorspace = MODE_RGB; + pixelMode = PixelMode::DirectRead; + break; + case ScanlineFormat::N24BitTcBgr: + config.output.colorspace = MODE_BGR; + pixelMode = PixelMode::DirectRead; + break; + default: + config.output.colorspace = MODE_RGBA; + pixelMode = PixelMode::SetPixel; + break; + } + } + } + if (pixelMode == PixelMode::DirectRead) + { + config.output.u.RGBA.rgba = access->GetBuffer(); + config.output.u.RGBA.stride = access->GetScanlineSize(); + config.output.u.RGBA.size = access->GetScanlineSize() * access->Height(); + } + else + { + tmpRgbaData.resize(width * height * 4); + config.output.u.RGBA.rgba = tmpRgbaData.data(); + config.output.u.RGBA.stride = width * 4; + config.output.u.RGBA.size = tmpRgbaData.size(); + } + + std::unique_ptr<WebPIDecoder, decltype(&WebPIDelete)> decoder(WebPIDecode(nullptr, 0, &config), + WebPIDelete); + + bool success = true; + for (;;) + { + // During first iteration, use data read while reading the header. + int status = WebPIAppend(decoder.get(), data.data(), data.size()); + if (status == VP8_STATUS_OK) + break; + if (status != VP8_STATUS_SUSPENDED) + { + // An error, still try to return at least a partially read bitmap, + // even if returning an error flag. + success = false; + break; + } + // If more data is needed, reading 4096 bytes more and repeat. + data.resize(4096); + sal_Size nBytesRead = stream.ReadBytes(data.data(), 4096); + if (nBytesRead <= 0) + { + // Truncated file, again try to return at least something. + success = false; + break; + } + data.resize(nBytesRead); + } + + switch (pixelMode) + { + case PixelMode::DirectRead: + { + // Adjust for IsBottomUp() if necessary. + if (access->IsBottomUp()) + { + std::vector<char> tmp; + const sal_uInt32 lineSize = access->GetScanlineSize(); + tmp.resize(lineSize); + for (tools::Long y = 0; y < access->Height() / 2; ++y) + { + tools::Long otherY = access->Height() - 1 - y; + memcpy(tmp.data(), access->GetScanline(y), lineSize); + memcpy(access->GetScanline(y), access->GetScanline(otherY), lineSize); + memcpy(access->GetScanline(otherY), tmp.data(), lineSize); + } + } + break; + } + case PixelMode::Split: + { + // Split to normal and alpha bitmaps. + AlphaScopedWriteAccess accessAlpha(bitmapAlpha); + for (tools::Long y = 0; y < access->Height(); ++y) + { + const unsigned char* src = tmpRgbaData.data() + width * 4 * y; + unsigned char* dstB = access->GetScanline(y); + unsigned char* dstA = accessAlpha->GetScanline(y); + for (tools::Long x = 0; x < access->Width(); ++x) + { + memcpy(dstB, src, 3); + *dstA = 255 - *(src + 3); + src += 4; + dstB += 3; + dstA += 1; + } + } + break; + } + case PixelMode::SetPixel: + { + for (tools::Long y = 0; y < access->Height(); ++y) + { + const unsigned char* src = tmpRgbaData.data() + width * 4 * y; + for (tools::Long x = 0; x < access->Width(); ++x) + { + sal_uInt8 r = src[0]; + sal_uInt8 g = src[1]; + sal_uInt8 b = src[2]; + sal_uInt8 a = src[3]; + access->SetPixel(y, x, Color(ColorAlpha, a, r, g, b)); + src += 4; + } + } + if (!bitmapAlpha.IsEmpty()) + { + AlphaScopedWriteAccess accessAlpha(bitmapAlpha); + for (tools::Long y = 0; y < accessAlpha->Height(); ++y) + { + const unsigned char* src = tmpRgbaData.data() + width * 4 * y; + for (tools::Long x = 0; x < accessAlpha->Width(); ++x) + { + sal_uInt8 a = src[3]; + accessAlpha->SetPixelIndex(y, x, 255 - a); + src += 4; + } + } + } + break; + } + } + + access.reset(); // Flush BitmapScopedWriteAccess. + if (bSupportsBitmap32 && has_alpha) + graphic = BitmapEx(bitmap); + else + { + if (has_alpha) + graphic = BitmapEx(bitmap, bitmapAlpha); + else + graphic = BitmapEx(bitmap); + } + return success; +} + +bool ImportWebpGraphic(SvStream& rStream, Graphic& rGraphic) +{ + bool bRetValue = readWebp(rStream, rGraphic); + if (!bRetValue) + rStream.SetError(SVSTREAM_FILEFORMAT_ERROR); + return bRetValue; +} + +bool ReadWebpInfo(SvStream& stream, Size& pixelSize, sal_uInt16& bitsPerPixel, bool& hasAlpha) +{ + std::vector<uint8_t> data; + WebPBitstreamFeatures features; + if (!readWebpInfo(stream, data, features)) + return false; + pixelSize = Size(features.width, features.height); + bitsPerPixel = features.has_alpha ? 32 : 24; + hasAlpha = features.has_alpha; + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/webp/writer.cxx b/vcl/source/filter/webp/writer.cxx new file mode 100644 index 000000000000..32da25e93ca3 --- /dev/null +++ b/vcl/source/filter/webp/writer.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <vcl/graph.hxx> +#include <tools/stream.hxx> +#include <filter/WebpWriter.hxx> +#include <vcl/BitmapReadAccess.hxx> +#include <sal/log.hxx> + +#include <webp/encode.h> + +static int writerFunction(const uint8_t* data, size_t size, const WebPPicture* picture) +{ + SvStream* stream = static_cast<SvStream*>(picture->custom_ptr); + return stream->WriteBytes(data, size) == size ? 1 : 0; +} + +static WebPPreset presetToValue(const OUString& preset) +{ + if (preset.equalsIgnoreAsciiCase("picture")) + return WEBP_PRESET_PICTURE; + if (preset.equalsIgnoreAsciiCase("photo")) + return WEBP_PRESET_PHOTO; + if (preset.equalsIgnoreAsciiCase("drawing")) + return WEBP_PRESET_DRAWING; + if (preset.equalsIgnoreAsciiCase("icon")) + return WEBP_PRESET_ICON; + if (preset.equalsIgnoreAsciiCase("text")) + return WEBP_PRESET_TEXT; + return WEBP_PRESET_DEFAULT; +} + +static bool writeWebp(SvStream& rStream, const BitmapEx& bitmapEx, bool lossless, + const OUString& preset, int quality) +{ + WebPConfig config; + if (!WebPConfigInit(&config)) + { + SAL_WARN("vcl.filter.webp", "WebPConfigInit() failed"); + return false; + } + if (lossless) + { + if (!WebPConfigLosslessPreset(&config, 6)) + { + SAL_WARN("vcl.filter.webp", "WebPConfigLosslessPreset() failed"); + return false; + } + } + else + { + if (!WebPConfigPreset(&config, presetToValue(preset), quality)) + { + SAL_WARN("vcl.filter.webp", "WebPConfigPreset() failed"); + return false; + } + } + // Here various parts of 'config' can be altered if wanted. + assert(WebPValidateConfig(&config)); + + const int width = bitmapEx.GetSizePixel().Width(); + const int height = bitmapEx.GetSizePixel().Height(); + + WebPPicture picture; + if (!WebPPictureInit(&picture)) + { + SAL_WARN("vcl.filter.webp", "WebPPictureInit() failed"); + return false; + } + picture.width = width; + picture.height = height; + picture.use_argb = lossless ? 1 : 0; // libwebp recommends argb only for lossless + // This unique_ptr is here just to ensure WebPPictureFree() is called at the end, + // it doesn't actually own the data as such. + std::unique_ptr<WebPPicture, decltype(&WebPPictureFree)> freePicture(&picture, WebPPictureFree); + + // Apparently libwebp needs the entire image data at once in WebPPicture, + // so allocate it and copy there. + Bitmap bitmap(bitmapEx.GetBitmap()); + AlphaMask bitmapAlpha; + if (bitmapEx.IsAlpha()) + bitmapAlpha = bitmapEx.GetAlpha(); + Bitmap::ScopedReadAccess access(bitmap); + AlphaMask::ScopedReadAccess accessAlpha(bitmapAlpha); + bool dataDone = false; + if (!access->IsBottomUp() && bitmapAlpha.IsEmpty()) + { + // Try to directly copy the bitmap data. + switch (access->GetScanlineFormat()) + { + case ScanlineFormat::N24BitTcRgb: + if (!WebPPictureImportRGB(&picture, access->GetBuffer(), access->GetScanlineSize())) + { + SAL_WARN("vcl.filter.webp", "WebPPictureImportRGB() failed"); + return false; + } + dataDone = true; + break; + case ScanlineFormat::N24BitTcBgr: + if (!WebPPictureImportBGR(&picture, access->GetBuffer(), access->GetScanlineSize())) + { + SAL_WARN("vcl.filter.webp", "WebPPictureImportBGR() failed"); + return false; + } + dataDone = true; + break; + // Our argb formats are premultiplied, so can't read directly using libwebp functions. + default: + break; + } + } + if (!dataDone) + { + // It would be simpler to convert the bitmap to 32bpp, but our 32bpp support is broken + // (it's unspecified whether it's premultiplied or not, for example). So handle this manually. + // Special handling for some common cases, generic otherwise. + if (!WebPPictureAlloc(&picture)) + { + SAL_WARN("vcl.filter.webp", "WebPPictureAlloc() failed"); + return false; + } + std::vector<uint8_t> data; + const int bpp = 4; + data.resize(width * height * bpp); + if (!bitmapAlpha.IsEmpty()) + { + for (tools::Long y = 0; y < access->Height(); ++y) + { + unsigned char* dst = data.data() + width * bpp * y; + const sal_uInt8* srcB = access->GetScanline(y); + const sal_uInt8* srcA = accessAlpha->GetScanline(y); + for (tools::Long x = 0; x < access->Width(); ++x) + { + BitmapColor color = access->GetPixelFromData(srcB, x); + BitmapColor transparency = accessAlpha->GetPixelFromData(srcA, x); + color.SetAlpha(255 - transparency.GetIndex()); + dst[0] = color.GetRed(); + dst[1] = color.GetGreen(); + dst[2] = color.GetBlue(); + dst[3] = color.GetAlpha(); + dst += bpp; + } + } + } + else + { + for (tools::Long y = 0; y < access->Height(); ++y) + { + unsigned char* dst = data.data() + width * bpp * y; + const sal_uInt8* src = access->GetScanline(y); + for (tools::Long x = 0; x < access->Width(); ++x) + { + Color color = access->GetPixelFromData(src, x); + dst[0] = color.GetRed(); + dst[1] = color.GetGreen(); + dst[2] = color.GetBlue(); + dst[3] = color.GetAlpha(); + dst += bpp; + } + } + } + // And now import from the temporary data. Use the import function rather + // than writing the data directly to avoid the need to write the data + // in the exact format WebPPicture wants (YUV, etc.). + if (!WebPPictureImportRGBA(&picture, data.data(), width * bpp)) + { + SAL_WARN("vcl.filter.webp", "WebPPictureImportRGBA() failed"); + return false; + } + } + + picture.writer = writerFunction; + picture.custom_ptr = &rStream; + return WebPEncode(&config, &picture); +} + +bool ExportWebpGraphic(SvStream& rStream, const Graphic& rGraphic, + FilterConfigItem* pFilterConfigItem) +{ + BitmapEx bitmap = rGraphic.GetBitmapEx(); + // If lossless, neither presets nor quality matter. + bool lossless = pFilterConfigItem->ReadBool("Lossless", true); + // Preset is WebPPreset values. + const OUString preset = pFilterConfigItem->ReadString("Preset", ""); + int quality = pFilterConfigItem->ReadInt32("Quality", 75); + return writeWebp(rStream, bitmap, lossless, preset, quality); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/gfxlink.cxx b/vcl/source/gdi/gfxlink.cxx index 147f89febc85..0baddbf931ae 100644 --- a/vcl/source/gdi/gfxlink.cxx +++ b/vcl/source/gdi/gfxlink.cxx @@ -134,6 +134,7 @@ bool GfxLink::LoadNative( Graphic& rGraphic ) const case GfxLinkType::NativeSvg: aShortName = SVG_SHORTNAME; break; case GfxLinkType::NativeBmp: aShortName = BMP_SHORTNAME; break; case GfxLinkType::NativePdf: aShortName = PDF_SHORTNAME; break; + case GfxLinkType::NativeWebp: aShortName = WEBP_SHORTNAME; break; default: break; } if (!aShortName.isEmpty()) diff --git a/vcl/source/gdi/mtfxmldump.cxx b/vcl/source/gdi/mtfxmldump.cxx index f7a3b0078462..f0a4d2ba0537 100644 --- a/vcl/source/gdi/mtfxmldump.cxx +++ b/vcl/source/gdi/mtfxmldump.cxx @@ -466,6 +466,7 @@ OUString convertGfxLinkTypeToString(GfxLinkType eGfxLinkType) case GfxLinkType::NativeSvg: return "NativeSvg"; case GfxLinkType::NativeTif: return "NativeTif"; case GfxLinkType::NativeWmf: return "NativeWmf"; + case GfxLinkType::NativeWebp: return "NativeWebp"; case GfxLinkType::NONE: return "None"; } return OUString(); diff --git a/vcl/source/graphic/UnoGraphicDescriptor.cxx b/vcl/source/graphic/UnoGraphicDescriptor.cxx index 60f2dcaa4c8b..a4d21c4420e6 100644 --- a/vcl/source/graphic/UnoGraphicDescriptor.cxx +++ b/vcl/source/graphic/UnoGraphicDescriptor.cxx @@ -127,6 +127,7 @@ void GraphicDescriptor::implCreate( SvStream& rIStm, const OUString* pURL ) case GraphicFileFormat::RAS: pMimeType = MIMETYPE_RAS; cType = graphic::GraphicType::PIXEL; break; case GraphicFileFormat::TGA: pMimeType = MIMETYPE_TGA; cType = graphic::GraphicType::PIXEL; break; case GraphicFileFormat::PSD: pMimeType = MIMETYPE_PSD; cType = graphic::GraphicType::PIXEL; break; + case GraphicFileFormat::WEBP: pMimeType = MIMETYPE_WEBP; cType = graphic::GraphicType::PIXEL; break; case GraphicFileFormat::EPS: pMimeType = MIMETYPE_EPS; cType = graphic::GraphicType::VECTOR; break; case GraphicFileFormat::DXF: pMimeType = MIMETYPE_DXF; cType = graphic::GraphicType::VECTOR; break; @@ -298,6 +299,7 @@ void GraphicDescriptor::_getPropertyValues( const comphelper::PropertyMapEntry** case GfxLinkType::NativeWmf: pMimeType = MIMETYPE_WMF; break; case GfxLinkType::NativeMet: pMimeType = MIMETYPE_MET; break; case GfxLinkType::NativePct: pMimeType = MIMETYPE_PCT; break; + case GfxLinkType::NativeWebp: pMimeType = MIMETYPE_WEBP; break; // added Svg mimetype support case GfxLinkType::NativeSvg: pMimeType = MIMETYPE_SVG; break; diff --git a/vcl/workben/fftester.cxx b/vcl/workben/fftester.cxx index 218909dde6c7..d69c07708841 100644 --- a/vcl/workben/fftester.cxx +++ b/vcl/workben/fftester.cxx @@ -62,6 +62,7 @@ #include <filter/PcdReader.hxx> #include <filter/PbmReader.hxx> #include <filter/DxfReader.hxx> +#include <filter/WebpReader.hxx> #include <filter/XpmReader.hxx> #include <osl/file.hxx> #include <osl/module.hxx> @@ -252,6 +253,12 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) SvFileStream aFileStream(out, StreamMode::READ); ret = static_cast<int>(ImportTiffGraphicImport(aFileStream, aGraphic)); } + else if (strcmp(argv[2], "webp") == 0) + { + Graphic aGraphic; + SvFileStream aFileStream(out, StreamMode::READ); + ret = static_cast<int>(ImportWebpGraphic(aFileStream, aGraphic)); + } #ifndef DISABLE_DYNLOADING else if ((strcmp(argv[2], "doc") == 0) || (strcmp(argv[2], "ww8") == 0)) { diff --git a/vcl/workben/webpfuzzer.cxx b/vcl/workben/webpfuzzer.cxx new file mode 100644 index 000000000000..b7ae8f741447 --- /dev/null +++ b/vcl/workben/webpfuzzer.cxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <tools/stream.hxx> +#include <vcl/FilterConfigItem.hxx> +#include "commonfuzzer.hxx" +#include <filter/WebpReader.hxx> + +#include <config_features.h> +#include <osl/detail/component-mapping.h> + +const lib_to_factory_mapping* lo_get_factory_map(void) +{ + static lib_to_factory_mapping map[] = { { 0, 0 } }; + + return map; +} + +const lib_to_constructor_mapping* lo_get_constructor_map(void) +{ + static lib_to_constructor_mapping map[] = { { 0, 0 } }; + + return map; +} + +extern "C" void* lo_get_custom_widget_func(const char*) { return nullptr; } + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + TypicalFuzzerInitialize(argc, argv); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ); + Graphic aGraphic; + (void)ImportWebpGraphic(aStream, aGraphic); + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/workben/webpfuzzer.options b/vcl/workben/webpfuzzer.options new file mode 100644 index 000000000000..678d526b1ea9 --- /dev/null +++ b/vcl/workben/webpfuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 65536 |