From 35b4a1a3b548ac92792f1b70d22e7cf85b0f13ad Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 20 Jun 2018 14:20:22 +0100 Subject: [PATCH] fix mem leak in pngsave and some reformatting and changelog notes --- .gitignore | 1 + ChangeLog | 1 + compile | 348 -------------------------------------- configure.ac | 81 ++++----- libvips/foreign/pngsave.c | 6 + libvips/foreign/vipspng.c | 61 +++++-- 6 files changed, 92 insertions(+), 406 deletions(-) delete mode 100755 compile diff --git a/.gitignore b/.gitignore index 2d9f8f64..c91c0ee7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +compile a.out *.log *.trs diff --git a/ChangeLog b/ChangeLog index cfa43c02..2eca4791 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ - composite has params for x/y position of sub-images [medakk] - add Mitchell kernel - pyramid builders have a choice of 2x2 shrinkers [harukizaemon] +- add `palette` option to pngsave [felixbuenemann] 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges [AdriĆ ] diff --git a/compile b/compile deleted file mode 100755 index 99e50524..00000000 --- a/compile +++ /dev/null @@ -1,348 +0,0 @@ -#! /bin/sh -# Wrapper for compilers which do not understand '-c -o'. - -scriptversion=2018-03-07.03; # UTC - -# Copyright (C) 1999-2018 Free Software Foundation, Inc. -# Written by Tom Tromey . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -nl=' -' - -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent tools from complaining about whitespace usage. -IFS=" "" $nl" - -file_conv= - -# func_file_conv build_file lazy -# Convert a $build file to $host form and store it in $file -# Currently only supports Windows hosts. If the determined conversion -# type is listed in (the comma separated) LAZY, no conversion will -# take place. -func_file_conv () -{ - file=$1 - case $file in - / | /[!/]*) # absolute file, and not a UNC file - if test -z "$file_conv"; then - # lazily determine how to convert abs files - case `uname -s` in - MINGW*) - file_conv=mingw - ;; - CYGWIN*) - file_conv=cygwin - ;; - *) - file_conv=wine - ;; - esac - fi - case $file_conv/,$2, in - *,$file_conv,*) - ;; - mingw/*) - file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` - ;; - cygwin/*) - file=`cygpath -m "$file" || echo "$file"` - ;; - wine/*) - file=`winepath -w "$file" || echo "$file"` - ;; - esac - ;; - esac -} - -# func_cl_dashL linkdir -# Make cl look for libraries in LINKDIR -func_cl_dashL () -{ - func_file_conv "$1" - if test -z "$lib_path"; then - lib_path=$file - else - lib_path="$lib_path;$file" - fi - linker_opts="$linker_opts -LIBPATH:$file" -} - -# func_cl_dashl library -# Do a library search-path lookup for cl -func_cl_dashl () -{ - lib=$1 - found=no - save_IFS=$IFS - IFS=';' - for dir in $lib_path $LIB - do - IFS=$save_IFS - if $shared && test -f "$dir/$lib.dll.lib"; then - found=yes - lib=$dir/$lib.dll.lib - break - fi - if test -f "$dir/$lib.lib"; then - found=yes - lib=$dir/$lib.lib - break - fi - if test -f "$dir/lib$lib.a"; then - found=yes - lib=$dir/lib$lib.a - break - fi - done - IFS=$save_IFS - - if test "$found" != yes; then - lib=$lib.lib - fi -} - -# func_cl_wrapper cl arg... -# Adjust compile command to suit cl -func_cl_wrapper () -{ - # Assume a capable shell - lib_path= - shared=: - linker_opts= - for arg - do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - eat=1 - case $2 in - *.o | *.[oO][bB][jJ]) - func_file_conv "$2" - set x "$@" -Fo"$file" - shift - ;; - *) - func_file_conv "$2" - set x "$@" -Fe"$file" - shift - ;; - esac - ;; - -I) - eat=1 - func_file_conv "$2" mingw - set x "$@" -I"$file" - shift - ;; - -I*) - func_file_conv "${1#-I}" mingw - set x "$@" -I"$file" - shift - ;; - -l) - eat=1 - func_cl_dashl "$2" - set x "$@" "$lib" - shift - ;; - -l*) - func_cl_dashl "${1#-l}" - set x "$@" "$lib" - shift - ;; - -L) - eat=1 - func_cl_dashL "$2" - ;; - -L*) - func_cl_dashL "${1#-L}" - ;; - -static) - shared=false - ;; - -Wl,*) - arg=${1#-Wl,} - save_ifs="$IFS"; IFS=',' - for flag in $arg; do - IFS="$save_ifs" - linker_opts="$linker_opts $flag" - done - IFS="$save_ifs" - ;; - -Xlinker) - eat=1 - linker_opts="$linker_opts $2" - ;; - -*) - set x "$@" "$1" - shift - ;; - *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) - func_file_conv "$1" - set x "$@" -Tp"$file" - shift - ;; - *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) - func_file_conv "$1" mingw - set x "$@" "$file" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift - done - if test -n "$linker_opts"; then - linker_opts="-link$linker_opts" - fi - exec "$@" $linker_opts - exit 1 -} - -eat= - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: compile [--help] [--version] PROGRAM [ARGS] - -Wrapper for compilers which do not understand '-c -o'. -Remove '-o dest.o' from ARGS, run PROGRAM with the remaining -arguments, and rename the output as expected. - -If you are trying to build a whole package this is not the -right script to run: please start by reading the file 'INSTALL'. - -Report bugs to . -EOF - exit $? - ;; - -v | --v*) - echo "compile $scriptversion" - exit $? - ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ - icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) - func_cl_wrapper "$@" # Doesn't return... - ;; -esac - -ofile= -cfile= - -for arg -do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - # So we strip '-o arg' only if arg is an object. - eat=1 - case $2 in - *.o | *.obj) - ofile=$2 - ;; - *) - set x "$@" -o "$2" - shift - ;; - esac - ;; - *.c) - cfile=$1 - set x "$@" "$1" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift -done - -if test -z "$ofile" || test -z "$cfile"; then - # If no '-o' option was seen then we might have been invoked from a - # pattern rule where we don't need one. That is ok -- this is a - # normal compilation that the losing compiler can handle. If no - # '.c' file was seen then we are probably linking. That is also - # ok. - exec "$@" -fi - -# Name of file we expect compiler to create. -cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` - -# Create the lock directory. -# Note: use '[/\\:.-]' here to ensure that we don't use the same name -# that we are using for the .o file. Also, base the name on the expected -# object file name, since that is what matters with a parallel build. -lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d -while true; do - if mkdir "$lockdir" >/dev/null 2>&1; then - break - fi - sleep 1 -done -# FIXME: race condition here if user kills between mkdir and trap. -trap "rmdir '$lockdir'; exit 1" 1 2 15 - -# Run the compile. -"$@" -ret=$? - -if test -f "$cofile"; then - test "$cofile" = "$ofile" || mv "$cofile" "$ofile" -elif test -f "${cofile}bj"; then - test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" -fi - -rmdir "$lockdir" -exit $ret - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/configure.ac b/configure.ac index f707c791..c09495e8 100644 --- a/configure.ac +++ b/configure.ac @@ -70,7 +70,7 @@ filter_list="deprecated introspect.c dummy.c fuzz " contains() { string="$1" substring="$2" - if test "${string#*$substring}" != "$string"; then + if test x"${string#*$substring}" != x"$string"; then return 0 # $substring is in $string else return 1 # $substring is not in $string @@ -137,12 +137,12 @@ AC_ARG_ENABLE(debug, [turn on debugging @<:@default=debug_default()@:>@]),, enable_debug=debug_default()) -if test "x$enable_debug" = "xyes"; then +if test x"$enable_debug" = x"yes"; then VIPS_DEBUG_FLAGS="-DDEBUG_FATAL -DDEBUG_LEAK" else VIPS_DEBUG_FLAGS="-DG_DISABLE_CAST_CHECKS" - if test "x$enable_debug" = "xno"; then + if test x"$enable_debug" = x"no"; then VIPS_DEBUG_FLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" fi fi @@ -192,7 +192,7 @@ case "$host" in esac AC_MSG_RESULT([$vips_os_win32]) -if test x"$vips_os_win32" = "xyes"; then +if test x"$vips_os_win32" = x"yes"; then AC_DEFINE(OS_WIN32,1,[native win32]) # makes gcc use win native alignment @@ -200,7 +200,7 @@ if test x"$vips_os_win32" = "xyes"; then fi # CImg needs flags changed on win32 -if test x"$vips_os_win32" = "xyes"; then +if test x"$vips_os_win32" = x"yes"; then AM_CONDITIONAL(OS_WIN32, true) else AM_CONDITIONAL(OS_WIN32, false) @@ -218,7 +218,7 @@ case "$host_os" in ;; esac AC_MSG_RESULT([$vips_binary_open]) -if test x"$vips_binary_open" = "xyes"; then +if test x"$vips_binary_open" = x"yes"; then AC_DEFINE(BINARY_OPEN,1,[define to open non-text files in binary mode]) fi @@ -267,8 +267,8 @@ AM_WITH_DMALLOC # without this we get something like # define VIPS_LIBDIR ${exec_prefix}/lib # argh -test "x$prefix" = xNONE && prefix=$ac_default_prefix -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' +test x"$prefix" = x"NONE" && prefix=$ac_default_prefix +test x"$exec_prefix" = x"NONE" && exec_prefix='${prefix}' # set $expanded_value to the fully-expanded value of the argument expand () { @@ -369,7 +369,7 @@ AC_TYPE_SIZE_T # g++/gcc 4.x and 5.x have rather broken vector support ... 5.4.1 seems to # work, but 5.4.0 fails to even compile AC_MSG_CHECKING([for gcc with working vector support]) -if test x$GCC_VERSION_MAJOR != x"4" -a x$GCC_VERSION_MAJOR != x"5"; then +if test x"$GCC_VERSION_MAJOR" != x"4" -a x"$GCC_VERSION_MAJOR" != x"5"; then AC_MSG_RESULT([yes]) else ax_cv_have_var_attribute_vector_size=no @@ -377,7 +377,7 @@ else fi # we need to be able to shuffle vectors in C++ -if test x$ax_cv_have_var_attribute_vector_size = x"yes"; then +if test x"$ax_cv_have_var_attribute_vector_size" = x"yes"; then AC_MSG_CHECKING([for C++ vector shuffle]) AC_LANG_PUSH([C++]) AC_TRY_COMPILE([ @@ -393,14 +393,14 @@ if test x$ax_cv_have_var_attribute_vector_size = x"yes"; then ]) AC_LANG_POP([C++]) - if test x$have_vector_shuffle = x"yes"; then + if test x"$have_vector_shuffle" = x"yes"; then AC_DEFINE_UNQUOTED(HAVE_VECTOR_SHUFFLE, 1, [define if your C++ can shuffle vectors]) fi fi # we also need to be able to mix vector and scalar arithmetic -if test x$have_vector_shuffle = x"yes"; then +if test x"$have_vector_shuffle" = x"yes"; then AC_MSG_CHECKING([for C++ vector arithmetic]) AC_LANG_PUSH([C++]) AC_TRY_COMPILE([ @@ -420,7 +420,7 @@ fi # gcc 7.2 seems to work, but then gets confused by signed constants in # templates -if test x$have_vector_arith = x"yes"; then +if test x"$have_vector_arith" = x"yes"; then AC_MSG_CHECKING([for C++ signed constants in vector templates]) AC_LANG_PUSH([C++]) AC_TRY_COMPILE([ @@ -441,7 +441,7 @@ if test x$have_vector_arith = x"yes"; then ]) AC_LANG_POP([C++]) - if test x$have_vector_arith = x"yes"; then + if test x"$have_vector_arith" = x"yes"; then AC_DEFINE_UNQUOTED(HAVE_VECTOR_ARITH, 1, [define if your C++ can mix vector and scalar arithmetic]) fi @@ -522,7 +522,7 @@ GTK_DOC_CHECK([1.14],[--flavour no-tmpl]) # we need expat ... we'd love to use expat.pc, but sadly this is only available # for recent linuxes, so we have to use the old and horrible expat.m4 AM_WITH_EXPAT -if test x$expat_found = xno; then +if test x"$expat_found" = x"no"; then exit 1 fi @@ -548,7 +548,7 @@ AC_ARG_WITH([gsf], # .27 is known to work well # .26 seems OK but has not been tested much # not sure about 22-25 -if test x"$with_gsf" != "xno"; then +if test x"$with_gsf" != x"no"; then PKG_CHECK_MODULES(GSF, libgsf-1 >= 1.14.26, [AC_DEFINE(HAVE_GSF,1,[define if you have libgsf-1 installed.]) with_gsf=yes @@ -573,7 +573,7 @@ fi AC_ARG_WITH([fftw], AS_HELP_STRING([--without-fftw], [build without fftw (default: test)])) -if test x"$with_fftw" != "xno"; then +if test x"$with_fftw" != x"no"; then PKG_CHECK_MODULES(FFTW, fftw3, [AC_DEFINE(HAVE_FFTW,1,[define if you have fftw3 installed.]) with_fftw=yes @@ -595,7 +595,7 @@ AC_ARG_WITH([magickpackage], # set the default magick package ... very old imagemagicks called it # ImageMagick -if test x"$with_magickpackage" = "x"; then +if test x"$with_magickpackage" = x""; then PKG_CHECK_MODULES(MAGICK_WAND, MagickCore, [with_magickpackage=MagickCore ], @@ -790,7 +790,7 @@ fi AC_ARG_WITH([orc], AS_HELP_STRING([--without-orc], [build without orc (default: test)])) -if test x"$with_orc" != "xno"; then +if test x"$with_orc" != x"no"; then # we use loadpw etc. PKG_CHECK_MODULES(ORC, orc-0.4 >= 0.4.11, [AC_DEFINE(HAVE_ORC,1,[define if you have orc-0.4.11 or later installed.]) @@ -813,7 +813,7 @@ fi AC_ARG_WITH([lcms], AS_HELP_STRING([--without-lcms], [build without lcms (default: test)])) -if test x"$with_lcms" != "xno"; then +if test x"$with_lcms" != x"no"; then PKG_CHECK_MODULES(LCMS, lcms2, [AC_DEFINE(HAVE_LCMS2,1,[define if you have lcms2 installed.]) with_lcms="yes (lcms2)" @@ -830,7 +830,7 @@ AC_ARG_WITH([OpenEXR], AS_HELP_STRING([--without-OpenEXR], [build without OpenEXR (default: test)])) # require 1.2.2 since 1.2.1 has a broken ImfCloseTiledInputFile() -if test x"$with_OpenEXR" != "xno"; then +if test x"$with_OpenEXR" != x"no"; then PKG_CHECK_MODULES(OPENEXR, OpenEXR >= 1.2.2, [AC_DEFINE(HAVE_OPENEXR,1,[define if you have OpenEXR >=1.2.2 installed.]) with_OpenEXR=yes @@ -897,7 +897,7 @@ fi AC_ARG_WITH([zlib], AS_HELP_STRING([--without-zlib], [build without zlib (default: test)])) -if test x"$with_zlib" != "xno"; then +if test x"$with_zlib" != x"no"; then PKG_CHECK_MODULES(ZLIB, zlib >= 0.4, [AC_DEFINE(HAVE_ZLIB,1,[define if you have zlib installed.]) with_zlib=yes @@ -945,7 +945,7 @@ fi AC_ARG_WITH([matio], AS_HELP_STRING([--without-matio], [build without matio (default: test)])) -if test x"$with_matio" != "xno"; then +if test x"$with_matio" != x"no"; then PKG_CHECK_MODULES(MATIO, matio, [AC_DEFINE(HAVE_MATIO,1,[define if you have matio installed.]) with_matio=yes @@ -963,7 +963,7 @@ fi AC_ARG_WITH([ppm], AS_HELP_STRING([--without-ppm], [build without ppm (default: with)])) -if test x"$with_ppm" != "xno"; then +if test x"$with_ppm" != x"no"; then AC_DEFINE(HAVE_PPM,1,[define to build ppm support.]) with_ppm=yes fi @@ -971,7 +971,7 @@ fi AC_ARG_WITH([analyze], AS_HELP_STRING([--without-analyze], [build without analyze (default: with)])) -if test x"$with_analyze" != "xno"; then +if test x"$with_analyze" != x"no"; then AC_DEFINE(HAVE_ANALYZE,1,[define to build analyze support.]) with_analyze=yes fi @@ -979,7 +979,7 @@ fi AC_ARG_WITH([radiance], AS_HELP_STRING([--without-radiance], [build without radiance (default: with)])) -if test x"$with_radiance" != "xno"; then +if test x"$with_radiance" != x"no"; then AC_DEFINE(HAVE_RADIANCE,1,[define to build radiance support.]) with_radiance=yes fi @@ -988,7 +988,7 @@ fi AC_ARG_WITH([cfitsio], AS_HELP_STRING([--without-cfitsio], [build without cfitsio (default: test)])) -if test x"$with_cfitsio" != "xno"; then +if test x"$with_cfitsio" != x"no"; then PKG_CHECK_MODULES(CFITSIO, cfitsio, [AC_DEFINE(HAVE_CFITSIO,1,[define if you have cfitsio installed.]) with_cfitsio=yes @@ -1006,7 +1006,7 @@ fi AC_ARG_WITH([libwebp], AS_HELP_STRING([--without-libwebp], [build without libwebp (default: test)])) -if test x"$with_libwebp" != "xno"; then +if test x"$with_libwebp" != x"no"; then PKG_CHECK_MODULES(LIBWEBP, libwebp >= 0.1.3, [AC_DEFINE(HAVE_LIBWEBP,1,[define if you have libwebp installed.]) with_libwebp=yes @@ -1028,7 +1028,7 @@ fi # we can build with libwebpmux back to 0.3, but it's not until libwebp 0.5 that # we can read that metadata back successfully ... insist on 0.5 so that tests # can work smoothly -if test x"$with_libwebp" != "xno"; then +if test x"$with_libwebp" != x"no"; then PKG_CHECK_MODULES(LIBWEBPMUX, libwebpmux >= 0.5.0, [AC_DEFINE(HAVE_LIBWEBPMUX,1,[define if you have libwebpmux installed.]) with_libwebpmux=yes @@ -1045,7 +1045,7 @@ AC_ARG_WITH([pangoft2], AS_HELP_STRING([--without-pangoft2], [build without pangoft2 (default: test)])) -if test x"$with_pangoft2" != "xno"; then +if test x"$with_pangoft2" != x"no"; then PKG_CHECK_MODULES(PANGOFT2, pangoft2, [AC_DEFINE(HAVE_PANGOFT2,1,[define if you have pangoft2 installed.]) with_pangoft2=yes @@ -1067,7 +1067,7 @@ AC_ARG_ENABLE([pyvips8], ] ) -if test "x$enable_pyvips8" = "xauto"; then +if test x"$enable_pyvips8" = x"auto"; then PKG_CHECK_EXISTS([pygobject-3.0 >= 3.13.0], [enable_pyvips8=yes ], @@ -1096,7 +1096,7 @@ AM_CONDITIONAL(ENABLE_PYVIPS8, test x"$enable_pyvips8" = x"yes") AC_ARG_WITH([tiff], AS_HELP_STRING([--without-tiff], [build without libtiff (default: test)])) -if test x"$with_tiff" != "xno"; then +if test x"$with_tiff" != x"no"; then PKG_CHECK_MODULES(TIFF, libtiff-4, [AC_DEFINE(HAVE_TIFF,1,[define if you have libtiff installed.]) with_tiff="yes (pkg-config libtiff-4)" @@ -1125,7 +1125,7 @@ FIND_GIFLIB( AC_ARG_WITH([png], AS_HELP_STRING([--without-png], [build without libpng (default: test)])) -if test x"$with_png" != "xno"; then +if test x"$with_png" != x"no"; then PKG_CHECK_MODULES(PNG, libpng >= 1.2.9, [AC_DEFINE(HAVE_PNG,1,[define if you have libpng installed.]) with_png="yes (pkg-config libpng >= 1.2.9)" @@ -1146,7 +1146,7 @@ fi AC_ARG_WITH([imagequant], AS_HELP_STRING([--without-imagequant], [build without imagequant (default: test)])) -if test x"$with_imagequant" != "xno" && test x"$with_png" != "xno"; then +if test x"$with_imagequant" != x"no" && test x"$with_png" != x"no"; then PKG_CHECK_MODULES(IMAGEQUANT, imagequant, [AC_DEFINE(HAVE_IMAGEQUANT,1,[define if you have imagequant installed.]) with_imagequant=yes @@ -1185,7 +1185,7 @@ fi # features like trellis quant are exposed as extension parameters ... # mozjpeg 3.2 and later have #define JPEG_C_PARAM_SUPPORTED, but we must # work with earlier versions -if test x"$with_jpeg" != "xno"; then +if test x"$with_jpeg" != x"no"; then save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$JPEG_LIBS $LIBS" @@ -1201,7 +1201,7 @@ fi AC_ARG_WITH([libexif], AS_HELP_STRING([--without-libexif], [build without libexif (default: test)])) -if test x"$with_libexif" != "xno"; then +if test x"$with_libexif" != x"no"; then PKG_CHECK_MODULES(EXIF, libexif >= 0.6, [AC_DEFINE(HAVE_EXIF,1,[define if you have libexif >= 0.6 installed.]) with_libexif=yes @@ -1215,7 +1215,7 @@ fi # some libexif packages need include , some just # how annoying -if test x"$with_libexif" != "xno"; then +if test x"$with_libexif" != x"no"; then # cppflags not cflags because we want the preproc to see the -I as well save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$EXIF_CFLAGS $CPPFLAGS" @@ -1394,6 +1394,7 @@ text rendering with pangoft2: $with_pangoft2 file import/export with libpng: $with_png (requires libpng-1.2.9 or later) support 8bpp PNG quantisation: $with_imagequant + (requires libimagequant) file import/export with libtiff: $with_tiff file import/export with giflib: $with_giflib file import/export with libjpeg: $with_jpeg @@ -1402,7 +1403,7 @@ image pyramid export: $with_gsf use libexif to load/save JPEG metadata: $with_libexif ]) -if test x"$found_introspection" = xyes -a "$VIPS_LIBDIR/girepository-1.0" != "$INTROSPECTION_TYPELIBDIR"; then +if test x"$found_introspection" = x"yes" -a "$VIPS_LIBDIR/girepository-1.0" != "$INTROSPECTION_TYPELIBDIR"; then case "$VIPS_LIBDIR" in /usr/local/Cellar/vips/*) ;; # ignore for homebrew @@ -1418,7 +1419,7 @@ You may need to add this directory to your typelib path, for example: esac fi -if test x"$enable_pyvips8" = xyes; then +if test x"$enable_pyvips8" = x"yes"; then expand $pyexecdir VIPS_PYEXECDIR=$expanded_value case "$VIPS_PYEXECDIR" in @@ -1430,7 +1431,7 @@ import sys sys.path.append('$VIPS_PYEXECDIR') try: import gi; print(gi._overridesdir) except: pass"` - if test x"$syspygipath" = x; then + if test x"$syspygipath" = x""; then AC_MSG_RESULT([dnl Your python gi module could not be loaded. diff --git a/libvips/foreign/pngsave.c b/libvips/foreign/pngsave.c index 2761a291..0033c81e 100644 --- a/libvips/foreign/pngsave.c +++ b/libvips/foreign/pngsave.c @@ -4,6 +4,8 @@ * - wrap a class around the png writer * 16/7/12 * - compression should be 0-9, not 1-10 + * 20/6/18 [felixbuenemann] + * - support png8 palette write with palette, colours, Q, dither */ /* @@ -381,6 +383,10 @@ vips_pngsave( VipsImage *in, const char *filename, ... ) * * @interlace: interlace image * * @profile: ICC profile to embed * * @filter: libpng row filter flag(s) + * * @palette: enable quantisation to 8bpp palette + * * @colours: max number of palette colours for quantisation + * * @Q: quality for 8bpp quantisation (does not exceed @colours) + * * @dither: amount of dithering for 8bpp quantization * * As vips_pngsave(), but save to a memory buffer. * diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index fd9da69e..035118a9 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -67,6 +67,8 @@ * - better @fail handling with truncated PNGs * 9/4/18 * - set interlaced=1 for interlaced images + * 20/6/18 [felixbuenemann] + * - support png8 palette write with palette, colours, Q, dither */ /* @@ -886,36 +888,46 @@ static int quantise_image( VipsImage *in, VipsImage *out, VipsImage *palette_out, int colours, int Q, double dither ) { - /* Ensure input is sRGB. */ + VipsImage *memory; + liq_attr *attr; + liq_image *input_image; + liq_result *quantisation_result; + int i; + + /* Ensure input is sRGB. + */ if( in->Type != VIPS_INTERPRETATION_sRGB) { VipsImage *srgb; + if( vips_colourspace( in, &srgb, VIPS_INTERPRETATION_sRGB, NULL ) ) return( -1 ); in = srgb; VIPS_UNREF( srgb ); } - /* Add alpha channel if missing. */ - if( !vips_image_hasalpha(in) ) { + + /* Add alpha channel if missing. + */ + if( !vips_image_hasalpha( in ) ) { VipsImage *srgba; + if( vips_bandjoin_const1( in, &srgba, 255, NULL ) ) return( -1 ); in = srgba; VIPS_UNREF( srgba ); } - VipsImage *memory; + if( !(memory = vips_image_copy_memory( in )) ) return( -1 ); in = memory; - liq_attr *attr = liq_attr_create(); + attr = liq_attr_create(); liq_set_max_colors( attr, colours ); liq_set_quality( attr, 0, Q ); - liq_image *input_image = liq_image_create_rgba( attr, + input_image = liq_image_create_rgba( attr, VIPS_IMAGE_ADDR( in, 0, 0 ), in->Xsize, in->Ysize, 0 ); - liq_result *quantisation_result; if ( liq_image_quantize( input_image, attr, &quantisation_result ) ) { liq_result_destroy( quantisation_result ); liq_image_destroy( input_image ); @@ -960,9 +972,9 @@ quantise_image( VipsImage *in, VipsImage *out, VipsImage *palette_out, return( -1 ); } - int i; for( i = 0; i < palette->count; i++ ) { unsigned char *p = VIPS_IMAGE_ADDR( palette_out, i, 0 ); + p[0] = palette->entries[i].r; p[1] = palette->entries[i].g; p[2] = palette->entries[i].b; @@ -1048,7 +1060,8 @@ write_vips( Write *write, /* Enable image quantisation to paletted 8bpp PNG if colours is set. */ if( palette ) { - g_assert( colours >= 2 && colours <= 256 ); + g_assert( colours >= 2 && + colours <= 256 ); bit_depth = 8; color_type = PNG_COLOR_TYPE_PALETTE; } @@ -1112,8 +1125,15 @@ write_vips( Write *write, #ifdef HAVE_IMAGEQUANT if( palette ) { - VipsImage *im_quantised = vips_image_new_memory(); - VipsImage *im_palette = vips_image_new_memory(); + VipsImage *im_quantised; + VipsImage *im_palette; + int palette_count; + png_color *png_palette; + png_byte *png_trans; + int trans_count; + + im_quantised = vips_image_new_memory(); + im_palette = vips_image_new_memory(); if( quantise_image( in, im_quantised, im_palette, colours, Q, dither ) ) { vips_error( "vips2png", @@ -1123,19 +1143,20 @@ write_vips( Write *write, return( -1 ); } - int palette_count = im_palette->Xsize; - g_assert( palette_count <= PNG_MAX_PALETTE_LENGTH); + palette_count = im_palette->Xsize; - png_color *png_palette = (png_color *) png_malloc( write->pPng, + g_assert( palette_count <= PNG_MAX_PALETTE_LENGTH ); + + png_palette = (png_color *) png_malloc( write->pPng, palette_count * sizeof( png_color ) ); - png_byte *png_trans = (png_byte *) png_malloc( write->pPng, + png_trans = (png_byte *) png_malloc( write->pPng, palette_count * sizeof( png_byte ) ); - int trans_count = 0; - + trans_count = 0; for( i = 0; i < palette_count; i++ ) { png_byte *p = (png_byte *) VIPS_IMAGE_ADDR( im_palette, i, 0 ); png_color *col = &png_palette[i]; + col->red = p[0]; col->green = p[1]; col->blue = p[2]; @@ -1162,13 +1183,17 @@ write_vips( Write *write, png_set_tRNS( write->pPng, write->pInfo, png_trans, trans_count, NULL ); } - VIPS_UNREF( im_palette ); + png_free( write->pPng, (void *) png_palette ); + png_free( write->pPng, (void *) png_trans ); + VIPS_UNREF( im_palette ); VIPS_UNREF( write->memory ); + write->memory = im_quantised; in = write->memory; } #endif /*HAVE_IMAGEQUANT*/ + png_write_info( write->pPng, write->pInfo ); /* If we're an intel byte order CPU and this is a 16bit image, we need