From cb07fb271224f243ae7391f8acc002e846a877c6 Mon Sep 17 00:00:00 2001 From: lhdjply Date: Thu, 16 Jan 2025 10:26:18 +0800 Subject: [PATCH] feat: update libimagequant to 2.18.0-1 Signed-off-by: lhdjply --- .github/workflows/call-build-deb.yml | 17 + .github/workflows/call-build-tag.yml | 14 + .gitignore | 28 +- .travis.yml | 2 +- CHANGELOG | 43 + CMakeLists.txt | 56 ++ Cargo.toml | 29 +- Makefile | 11 +- README.md | 36 +- benches/bench.rs | 69 ++ blur.h | 4 + configure | 12 +- debian/.gitignore | 6 + debian/changelog | 41 + debian/compat | 1 - debian/control | 10 +- debian/copyright | 5 +- debian/libimagequant0.symbols | 1 + debian/rules | 12 +- debian/salsa-ci.yml | 4 + debian/upstream/metadata | 5 + debian/watch | 3 +- imagequant.pc.in | 4 +- kmeans.c | 52 +- kmeans.h | 2 +- libimagequant-ios.xcodeproj/project.pbxproj | 232 ++++++ libimagequant-mac.xcodeproj/project.pbxproj | 223 +++++ libimagequant.c | 489 ++--------- libimagequant.h | 4 +- libimagequant_private.h | 51 ++ mediancut.c | 121 +-- mediancut.h | 4 + nearest.c | 55 +- nearest.h | 6 + pam.c | 109 ++- pam.h | 91 ++- remap.c | 300 +++++++ remap.h | 7 + rust-api/.gitignore | 2 + rust-api/COPYRIGHT | 635 +++++++++++++++ rust-api/Cargo.toml | 29 + rust-api/README.md | 15 + rust-api/examples/basic.rs | 32 + rust-api/src/lib.rs | 850 ++++++++++++++++++++ {rust => rust-sys}/build.rs | 19 +- {rust => rust-sys}/libimagequant.rs | 62 +- tests/frame-6-a.png | Bin 0 -> 89068 bytes tests/frame-6-bg.png | Bin 0 -> 78886 bytes tests/frame-6-pal.png | Bin 0 -> 855 bytes tests/frame-7-a.png | Bin 0 -> 89068 bytes tests/frame-7-bg.png | Bin 0 -> 18629 bytes tests/frame-7-pal.png | Bin 0 -> 133 bytes tests/tests.rs | 87 ++ version.txt | 1 + 54 files changed, 3257 insertions(+), 634 deletions(-) create mode 100644 .github/workflows/call-build-deb.yml create mode 100644 .github/workflows/call-build-tag.yml create mode 100644 CMakeLists.txt create mode 100644 benches/bench.rs create mode 100644 debian/.gitignore delete mode 100644 debian/compat create mode 100644 debian/salsa-ci.yml create mode 100644 debian/upstream/metadata create mode 100644 libimagequant-ios.xcodeproj/project.pbxproj create mode 100644 libimagequant-mac.xcodeproj/project.pbxproj create mode 100644 libimagequant_private.h create mode 100644 remap.c create mode 100644 remap.h create mode 100644 rust-api/.gitignore create mode 100644 rust-api/COPYRIGHT create mode 100644 rust-api/Cargo.toml create mode 100644 rust-api/README.md create mode 100644 rust-api/examples/basic.rs create mode 100644 rust-api/src/lib.rs rename {rust => rust-sys}/build.rs (77%) rename {rust => rust-sys}/libimagequant.rs (90%) create mode 100644 tests/frame-6-a.png create mode 100644 tests/frame-6-bg.png create mode 100644 tests/frame-6-pal.png create mode 100644 tests/frame-7-a.png create mode 100644 tests/frame-7-bg.png create mode 100644 tests/frame-7-pal.png create mode 100644 tests/tests.rs create mode 100644 version.txt diff --git a/.github/workflows/call-build-deb.yml b/.github/workflows/call-build-deb.yml new file mode 100644 index 0000000..dcbe2ab --- /dev/null +++ b/.github/workflows/call-build-deb.yml @@ -0,0 +1,17 @@ +name: Call build-deb +on: + pull_request_target: + paths-ignore: + - ".github/workflows/**" + types: [ opened, closed, synchronize ] + +concurrency: + group: ${{ github.workflow }}-pull/${{ github.event.number }} + cancel-in-progress: true + +jobs: + check_job: + if: github.event.action != 'closed' || github.event.pull_request.merged + uses: deepin-community/.github/.github/workflows/build-deb.yml@master + secrets: + BridgeToken: ${{ secrets.BridgeToken }} diff --git a/.github/workflows/call-build-tag.yml b/.github/workflows/call-build-tag.yml new file mode 100644 index 0000000..d0a591a --- /dev/null +++ b/.github/workflows/call-build-tag.yml @@ -0,0 +1,14 @@ +name: tag build +on: + push: + tags: "*" + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + uses: deepin-community/.github/.github/workflows/build-tag.yml@master + secrets: + BridgeToken: ${{ secrets.BridgeToken }} diff --git a/.gitignore b/.gitignore index 224e7f0..8551194 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,27 @@ -.pc/ +config.mk +imagequant.pc +*.lo +*.o +*.a +*.so.0 +*.so +*.bz2 +*.dylib +*.dylib.0 +*.jnilib +*.dSYM +org/pngquant/*.class +org/pngquant/*.h +target/ +msvc-dist/org/ +msvc-dist/*.md +msvc-dist/Makefile* +msvc-dist/*.cs +msvc-dist/*.xml +msvc-dist/CHANGELOG +msvc-dist/COPYRIGHT +msvc-dist/configure +msvc-dist/.gitignore +quantized_example.png +example +lodepng.? diff --git a/.travis.yml b/.travis.yml index c6264f3..1a45e51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ matrix: include: - os: linux language: java - jdk: oraclejdk8 + jdk: oraclejdk9 env: CFLAGS="-fPIC" install: true script: make java diff --git a/CHANGELOG b/CHANGELOG index 8eac358..67333a2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,46 @@ +version 4 +--------- + +- rewritten in Rust +- multi-threaded floyd-steinberg dithering gives 2x-3x remapping speed boost +- better handling of remapping on top of backgrounds (for GIFs, gif.ski) +- support for more than 256-colors (compile-time option) +- WASM compatibility +- the C API enables dithering by default + +Newer v3/v4 versions of the library are on crates.io: https://crates.io/crates/imagequant + +version 2.18 +------------ + - improved handling of images with very few pixels with very diverse colors + - added more perceptually-weighed color selection + - dropped problematic omp_set_nested() + - fixed a rare memory leak + +version 2.17 +------------ + - quality improvement + - ARM64 build fix + +version 2.16 +------------ + - fixed LCMS2 error handling + +version 2.15 +------------ + - speed and quality improvements + +version 2.14 +------------ + - improved Rust API + - quality improvements for remapping overlays over a background + +version 2.13 +------------ + - support OpenMP in clang + - dropped old Internet Explorer workarounds + - speed and quality improvements + version 2.12 ------------ - new liq_histogram_add_fixed_color() diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d14f058 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 2.6) +file(READ version.txt VERSION) + +project(imagequant C) + +if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL ARM64) + option(BUILD_WITH_SSE "Use SSE" OFF) +else() + option(BUILD_WITH_SSE "Use SSE" ON) +endif() + +if(BUILD_WITH_SSE) + add_definitions(-DUSE_SSE=1) +endif() + +find_package(OpenMP) +if(OPENMP_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + +include_directories(${CMAKE_SOURCE_DIR}) + +if(CMAKE_COMPILER_IS_GNUCC) + add_compile_options("-std=c99") +endif() + +add_library(imagequant SHARED + libimagequant.c + blur.c + mediancut.c + mempool.c + nearest.c + pam.c + kmeans.c +) + +add_library(imagequant_a STATIC + libimagequant.c + blur.c + mediancut.c + mempool.c + nearest.c + pam.c + kmeans.c +) +set_target_properties(imagequant PROPERTIES SOVERSION 0 + VERSION 0.0) + +set(PREFIX ${CMAKE_INSTALL_PREFIX}) +configure_file(imagequant.pc.in imagequant.pc @ONLY) + +install(TARGETS imagequant LIBRARY DESTINATION ${LIB_INSTALL_DIR}) +install(FILES libimagequant.h DESTINATION include) +install(FILES ${CMAKE_BINARY_DIR}/libimagequant_a.a DESTINATION ${LIB_INSTALL_DIR} RENAME libimagequant.a) +install(FILES ${CMAKE_BINARY_DIR}/imagequant.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) diff --git a/Cargo.toml b/Cargo.toml index d9372b8..789aabb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,29 +1,30 @@ -# libimagequant is a pure C library. -# Rust/Cargo is entirely optional. You can also use ./configure && make +# Please upgrade to v4 of the library [package] +version = "3.1.4+sys2.18.0" authors = ["Kornel Lesiński "] -build = "rust/build.rs" +build = "rust-sys/build.rs" categories = ["external-ffi-bindings"] homepage = "https://pngquant.org/lib" -include = ["COPYRIGHT", "rust/*", "*.c", "*.h", "README.md", "Cargo.toml"] +include = ["COPYRIGHT", "rust-sys/*", "*.c", "*.h", "README.md", "Cargo.toml"] keywords = ["pngquant"] -license = "GPL-3.0+" +license = "GPL-3.0-or-later" links = "imagequant" name = "imagequant-sys" readme = "README.md" repository = "https://github.com/ImageOptim/libimagequant" -version = "2.12.2" description = "Statically linked C part of imagequant library powering tools such as pngquant.\n\nThis library is dual-licensed like pngquant: either GPL or a commercial license. See website for details: https://pngquant.org" +edition = "2018" [build-dependencies] -cc = "1.0.17" +cc = "1.0.71" [dependencies] -rgb = "0.8.9" +rgb = "0.8.29" +bitflags = "1.3.2" [dependencies.openmp-sys] optional = true -version = "0.1.5" +version = "1.2.0" [features] default = ["sse"] @@ -34,5 +35,13 @@ sse = [] [lib] crate-type = ["cdylib", "staticlib", "lib"] name = "imagequant_sys" -path = "rust/libimagequant.rs" +path = "rust-sys/libimagequant.rs" doctest = false + +[dev-dependencies] +lodepng = "3.4.7" +imagequant = { path = "./rust-api" } + +[profile.bench] +debug = 1 +split-debuginfo = 'unpacked' diff --git a/Makefile b/Makefile index 2666b3d..548e2ac 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ JNIDLL=libimagequant.dll JNIDLLIMP=libimagequant_dll.a JNIDLLDEF=libimagequant_dll.def -OBJS = pam.o mediancut.o blur.o mempool.o kmeans.o nearest.o libimagequant.o +OBJS = pam.o mediancut.o blur.o remap.o mempool.o kmeans.o nearest.o libimagequant.o SHAREDOBJS = $(subst .o,.lo,$(OBJS)) JAVACLASSES = org/pngquant/LiqObject.class org/pngquant/PngQuant.class org/pngquant/Image.class org/pngquant/Result.class @@ -65,7 +65,7 @@ libimagequant.dylib: $(SHAREDOBJS) $(OBJS): $(wildcard *.h) config.mk $(JNILIB): $(JAVAHEADERS) $(STATICLIB) org/pngquant/PngQuant.c - $(CC) -g $(CFLAGS) $(LDFLAGS) $(JAVAINCLUDE) -shared -o $@ $(STATICLIB) org/pngquant/PngQuant.c + $(CC) -g $(CFLAGS) $(LDFLAGS) $(JAVAINCLUDE) -shared -o $@ org/pngquant/PngQuant.c $(STATICLIB) $(JNIDLL) $(JNIDLLIMP): $(JAVAHEADERS) $(OBJS) org/pngquant/PngQuant.c $(CC) -fPIC -shared -I. $(JAVAINCLUDE) -o $(JNIDLL) $^ $(LDFLAGS) -Wl,--out-implib,$(JNIDLLIMP),--output-def,$(JNIDLLDEF) @@ -93,7 +93,7 @@ cargo: cargo test example: example.c lodepng.h lodepng.c $(STATICLIB) - $(CC) -g $(CFLAGS) -Wall example.c $(STATICLIB) -o example + $(CC) -g $(CFLAGS) -Wall example.c $(STATICLIB) -o example -lm lodepng.h: curl -o lodepng.h -L https://raw.githubusercontent.com/lvandeve/lodepng/master/lodepng.h @@ -104,6 +104,7 @@ lodepng.c: clean: rm -f $(OBJS) $(SHAREDOBJS) $(SHAREDLIBVER) $(SHAREDLIB) $(STATICLIB) $(TARFILE) $(DLL) '$(DLLIMP)' '$(DLLDEF)' rm -f $(JAVAHEADERS) $(JAVACLASSES) $(JNILIB) example + rm -rf target rust-api/target rust-sys/target distclean: clean rm -f config.mk @@ -114,7 +115,7 @@ install: all $(PKGCONFIG) install -d $(DESTDIR)$(PKGCONFIGDIR) install -d $(DESTDIR)$(INCLUDEDIR) install -m 644 $(STATICLIB) $(DESTDIR)$(LIBDIR)/$(STATICLIB) - install -m 644 $(SHAREDLIBVER) $(DESTDIR)$(LIBDIR)/$(SHAREDLIBVER) + install -m 755 $(SHAREDLIBVER) $(DESTDIR)$(LIBDIR)/$(SHAREDLIBVER) ln -sf $(SHAREDLIBVER) $(DESTDIR)$(LIBDIR)/$(SHAREDLIB) install -m 644 $(PKGCONFIG) $(DESTDIR)$(PKGCONFIGDIR)/$(PKGCONFIG) install -m 644 libimagequant.h $(DESTDIR)$(INCLUDEDIR)/libimagequant.h @@ -133,7 +134,7 @@ ifeq ($(filter %clean %distclean, $(MAKECMDGOALS)), ) endif $(PKGCONFIG): config.mk - sed 's|PREFIX|$(PREFIX)|;s|VERSION|$(VERSION)|' < imagequant.pc.in > $(PKGCONFIG) + sed 's|@PREFIX@|$(PREFIX)|;s|@VERSION@|$(VERSION)|' < imagequant.pc.in > $(PKGCONFIG) .PHONY: all static shared clean dist distclean dll java cargo .DELETE_ON_ERROR: diff --git a/README.md b/README.md index e81606b..dbb8cfe 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,8 @@ It's powering [pngquant2](https://pngquant.org). Libimagequant is dual-licensed: -* For Free/Libre Open Source Software it's available under [GPL v3 or later](https://raw.github.com/ImageOptim/libimagequant/master/COPYRIGHT) with additional copyright notices for older parts of the code. - -* For use in non-GPL software (e.g. closed-source or App Store distribution) please ask kornel@pngquant.org for a commercial license. +* For Free/Libre Open Source Software it's available under GPL v3 or later with additional [copyright notices](https://raw.github.com/ImageOptim/libimagequant/master/COPYRIGHT) for older parts of the code. +* For use in closed-source software, AppStore distribution, and other non-GPL uses, you can [obtain a commercial license](https://supso.org/projects/pngquant). Feel free to ask kornel@pngquant.org for details and custom licensing terms if you need them. ## Download @@ -50,10 +49,23 @@ On Windows run `make java-dll` and it'll create `libimagequant.dll` instead. ### Compiling on Windows/Visual Studio -The library can be compiled with any C compiler that has at least basic support for C99 (GCC, clang, ICC, C++ Builder, even Tiny C Compiler), but Visual Studio 2012 and older are not up to date with the 1999 C standard. There are 2 options for using `libimagequant` on Windows: +The library can be compiled with any C compiler that has at least basic support for C99 (GCC, clang, ICC, C++ Builder, even Tiny C Compiler), but Visual Studio 2012 and older are not up to date with the 1999 C standard. Use Visual Studio **2015** and the [MSVC-compatible branch of the library](https://github.com/ImageOptim/libimagequant/tree/msvc). + +To build on Windows, install CMake and use it to generate a makefile/project for your build system. + +Build instructions + + mkdir build + cd build + cmake .. + cmake --build . - * Use Visual Studio **2015** and an [MSVC-compatible branch of the library](https://github.com/ImageOptim/libimagequant/tree/msvc) - * Or use GCC from [MinGW](http://www.mingw.org) or [MSYS2](http://www.msys2.org/). Use GCC to build `libimagequant.a` (using the instructions above for Unix) and add it along with `libgcc.a` (shipped with the MinGW compiler) to your VC project. +To generate a 64-bit Visual Studio project instead: + + mkdir build + cd build + cmake -G "Visual Studio 15 2017 Win64" .. + cmake --build . ### Building as shared library @@ -303,7 +315,7 @@ Freeing `liq_result` also frees any `liq_palette` obtained from it. liq_error liq_set_speed(liq_attr* attr, int speed); -Higher speed levels disable expensive algorithms and reduce quantization precision. The default speed is `3`. Speed `1` gives marginally better quality at significant CPU cost. Speed `10` has usually 5% lower quality, but is 8 times faster than the default. +Higher speed levels disable expensive algorithms and reduce quantization precision. The default speed is `4`. Speed `1` gives marginally better quality at significant CPU cost. Speed `10` has usually 5% lower quality, but is 8 times faster than the default. High speeds combined with `liq_set_quality()` will use more colors than necessary and will be less likely to meet minimum required quality. @@ -326,15 +338,13 @@ Returns the value set by `liq_set_speed()`. liq_error liq_set_min_opacity(liq_attr* attr, int min); -Alpha values higher than this will be rounded to opaque. This is a workaround for Internet Explorer 6, but because this browser is not used any more, this option is deprecated and will be removed. The default is `255` (no change). - -Returns `LIQ_VALUE_OUT_OF_RANGE` if the value is outside the 0-255 range. +This was a workaround for Internet Explorer 6, but because this browser is not used any more, this option has been deprecated and removed. ---- int liq_get_min_opacity(liq_attr* attr); -Returns the value set by `liq_set_min_opacity()`. +This function has been deprecated. ---- @@ -667,7 +677,9 @@ The library needs to sort unique colors present in the image. Although the sorti ### OpenMP -The library will parallelize some operations if compiled with OpenMP. +The library can parallelize some operations if compiled with OpenMP. + +GCC 9 or later is required for correct OpenMP support. Older compilers *will cause bugs* when OpenMP is enabled. You must not increase number of maximum threads after `liq_image` has been created, as it allocates some per-thread buffers. diff --git a/benches/bench.rs b/benches/bench.rs new file mode 100644 index 0000000..e75a220 --- /dev/null +++ b/benches/bench.rs @@ -0,0 +1,69 @@ +#![feature(test)] + +extern crate test; +use test::Bencher; + +use imagequant::*; + +#[bench] +fn histogram(b: &mut Bencher) { + let img = lodepng::decode32_file("/Users/kornel/Desktop/canvas.png").unwrap(); + let liq = Attributes::new(); + b.iter(move || { + let mut img = liq.new_image(&img.buffer, img.width, img.height, 0.).unwrap(); + let mut hist = Histogram::new(&liq); + hist.add_image(&mut img).unwrap(); + }) +} + +#[bench] +fn remap_ord(b: &mut Bencher) { + let img = lodepng::decode32_file("/Users/kornel/Desktop/canvas.png").unwrap(); + let mut buf = vec![std::mem::MaybeUninit::uninit(); img.width * img.height]; + let mut liq = Attributes::new(); + liq.set_speed(10); + let mut img = liq.new_image(&img.buffer, img.width, img.height, 0.).unwrap(); + let mut res = liq.quantize(&mut img).unwrap(); + res.set_dithering_level(0.); + b.iter(move || { + res.remap_into(&mut img, &mut buf).unwrap(); + res.remap_into(&mut img, &mut buf).unwrap(); + }) +} + +#[bench] +fn remap_floyd(b: &mut Bencher) { + let img = lodepng::decode32_file("/Users/kornel/Desktop/canvas.png").unwrap(); + let mut buf = vec![std::mem::MaybeUninit::uninit(); img.width * img.height]; + let mut liq = Attributes::new(); + liq.set_speed(10); + let mut img = liq.new_image(&img.buffer, img.width, img.height, 0.).unwrap(); + let mut res = liq.quantize(&mut img).unwrap(); + res.set_dithering_level(1.); + b.iter(move || { + res.remap_into(&mut img, &mut buf).unwrap(); + res.remap_into(&mut img, &mut buf).unwrap(); + }) +} + +#[bench] +fn quantize_s8(b: &mut Bencher) { + let img = lodepng::decode32_file("/Users/kornel/Desktop/canvas.png").unwrap(); + let mut liq = Attributes::new(); + liq.set_speed(8); + b.iter(move || { + let mut img = liq.new_image(&img.buffer, img.width, img.height, 0.).unwrap(); + liq.quantize(&mut img).unwrap(); + }) +} + +#[bench] +fn quantize_s1(b: &mut Bencher) { + let img = lodepng::decode32_file("/Users/kornel/Desktop/canvas.png").unwrap(); + let mut liq = Attributes::new(); + liq.set_speed(1); + b.iter(move || { + let mut img = liq.new_image(&img.buffer, img.width, img.height, 0.).unwrap(); + liq.quantize(&mut img).unwrap(); + }) +} diff --git a/blur.h b/blur.h index 06ae8cb..1e77819 100644 --- a/blur.h +++ b/blur.h @@ -1,4 +1,8 @@ +#ifndef BLUR_H +#define BLUR_H LIQ_PRIVATE void liq_blur(unsigned char *src, unsigned char *tmp, unsigned char *dst, unsigned int width, unsigned int height, unsigned int size); LIQ_PRIVATE void liq_max3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height); LIQ_PRIVATE void liq_min3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height); + +#endif diff --git a/configure b/configure index d16a8a5..d701052 100755 --- a/configure +++ b/configure @@ -160,7 +160,7 @@ if [ -z "$DEBUG" ]; then cflags "-O3 -DNDEBUG" status "Debug" "no" else - cflags "-O1 -g" + cflags "-O1 -g -DDEBUG" status "Debug" "yes" fi @@ -213,8 +213,10 @@ fi # Cocoa if [[ "$OSTYPE" =~ "darwin" ]]; then - cflags "-mmacosx-version-min=10.7" - lflags "-mmacosx-version-min=10.7" + if [ -z "${MACOSX_DEPLOYMENT_TARGET+isset}" ]; then + cflags "-mmacosx-version-min=10.9" + lflags "-mmacosx-version-min=10.9" + fi fi if [[ "$OSTYPE" =~ "darwin" ]]; then @@ -223,8 +225,8 @@ if [[ "$OSTYPE" =~ "darwin" ]]; then # Search Developer SDK paths, since Apple seems to have dropped the standard Unixy ones XCODE_CMD="xcode-select" XCODE_PATH=$($XCODE_CMD -p) - DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib") - DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/lib") + DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib") + DIRS+=("$XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include $XCODE_PATH/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/lib") elif [[ "$OSTYPE" =~ "msys" ]]; then SOLIBSUFFIX=dll else diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000..6cd24e7 --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,6 @@ +/*.substvars +/.debhelper/ +/debhelper-build-stamp +/files +/libimagequant-dev/ +/libimagequant0/ diff --git a/debian/changelog b/debian/changelog index f9e8fa4..1236cb7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,44 @@ +libimagequant (2.18.0-1) unstable; urgency=medium + + * New upstream version + * d/watch: + - Make sure to fetch only version 2.x series since 4.x is + rewritten in rust language + - Fix download name + * d/rules: add /usr/share/dpkg/buildtools.mk + Closes: #944439 + * Standards-Version: 4.6.2 (routine-update) + + -- Andreas Tille Tue, 14 Nov 2023 09:37:09 +0100 + +libimagequant (2.17.0-1) unstable; urgency=medium + + [ Barak A. Pearlmutter ] + * Set debhelper-compat version in Build-Depends. + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + * Fix field name typos in debian/copyright (Commenst => Comment, Comments => + Comment). + * Get $(DEB_HOST_MULTIARCH) defined in debian/rules + * Set build-depends-package in debian/*.symbols file + * New upstream version + * Enable openmp (closes: #919757) + * Rules don't require root + * Remove Herbert Parentes Fortes Neto from uploaders (closes: #986943) + - Thanks for your work on Debian, Herbert! + * Merge patch from Helmut Grohne + - Fix FTCBFS: (Closes: #944439) + - Pass a suitable CC to the hand-written configure. + - Force decision for SSE based on HOST arch + + [ Andreas Tille ] + * Add Barak A. Pearlmutter as additional Uploader + * Drop default debian/gbp.conf + * Add salsa-ci file (routine-update) + * Add missing build dependency on dh addon. + + -- Andreas Tille Mon, 10 Jan 2022 16:26:40 +0100 + libimagequant (2.12.2-1.1) unstable; urgency=medium * Non-maintainer upload. diff --git a/debian/compat b/debian/compat deleted file mode 100644 index b4de394..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/debian/control b/debian/control index 28aaf44..52cdab5 100644 --- a/debian/control +++ b/debian/control @@ -1,12 +1,12 @@ Source: libimagequant Maintainer: Debian PhotoTools Maintainers -Uploaders: Herbert Parentes Fortes Neto , - Andreas Tille +Uploaders: Andreas Tille , + Barak A. Pearlmutter Section: graphics Priority: optional -Build-Depends: debhelper (>= 11), - d-shlibs -Standards-Version: 4.2.1 +Build-Depends: debhelper-compat (= 13), d-shlibs, debhelper +Standards-Version: 4.6.2 +Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/debian-phototools-team/libimagequant Vcs-Git: https://salsa.debian.org/debian-phototools-team/libimagequant.git Homepage: https://github.com/ImageOptim/libimagequant diff --git a/debian/copyright b/debian/copyright index 4880e8c..5190aab 100644 --- a/debian/copyright +++ b/debian/copyright @@ -9,13 +9,13 @@ License: GPL-3.0+ Files: pam.h Copyright: 1989, 1991 Jef Poskanzer 1997 Greg Roelofs -Commenst: MIT Old Style License: MIT +Comment: MIT Old Style Files: example.c Copyright: ? -Comments: CC0 public domain License: CC0 +Comment: CC0 public domain Files: debian/* Copyright: 2018 Herbert Parentes Fortes Neto @@ -48,4 +48,3 @@ License: GPL-3.0+ . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". - diff --git a/debian/libimagequant0.symbols b/debian/libimagequant0.symbols index 3cced79..31d603c 100644 --- a/debian/libimagequant0.symbols +++ b/debian/libimagequant0.symbols @@ -1,4 +1,5 @@ libimagequant.so.0 libimagequant0 #MINVER# +* Build-Depends-Package: libimagequant-dev liq_attr_copy@Base 2.11.10 liq_attr_create@Base 2.11.10 liq_attr_create_with_allocator@Base 2.11.10 diff --git a/debian/rules b/debian/rules index 88041d2..c92924a 100755 --- a/debian/rules +++ b/debian/rules @@ -2,20 +2,22 @@ #export DH_VERBOSE = 1 +include /usr/share/dpkg/default.mk + export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_CFLAGS_MAINT_APPEND=-D_FORTIFY_SOURCE=2 +include /usr/share/dpkg/buildtools.mk %: dh $@ -ifeq (,$(filter $(DEB_HOST_ARCH), amd64 x32)) override_dh_auto_configure: - dh_auto_configure -- --disable-sse -endif + dh_auto_configure -- \ + --with-openmp \ + 'CC=$(CC)' --$(if $(filter $(DEB_HOST_ARCH),amd64 x32),en,dis)able-sse -override_dh_install: - dh_install +execute_after_dh_install: d-shlibmove --commit \ --multiarch \ --devunversioned \ diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml new file mode 100644 index 0000000..33c3a64 --- /dev/null +++ b/debian/salsa-ci.yml @@ -0,0 +1,4 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff --git a/debian/upstream/metadata b/debian/upstream/metadata new file mode 100644 index 0000000..6e9fcba --- /dev/null +++ b/debian/upstream/metadata @@ -0,0 +1,5 @@ +--- +Bug-Database: https://github.com/ImageOptim/libimagequant/issues +Bug-Submit: https://github.com/ImageOptim/libimagequant/issues/new +Repository: https://github.com/ImageOptim/libimagequant.git +Repository-Browse: https://github.com/ImageOptim/libimagequant diff --git a/debian/watch b/debian/watch index 033c983..63e3dbb 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,4 @@ version=4 -https://github.com/ImageOptim/libimagequant/releases .*/archive/@ANY_VERSION@@ARCHIVE_EXT@ +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE@-$1.tar.gz%" \ + https://github.com/ImageOptim/@PACKAGE@/tags .*/v?(2[\d.]+)@ARCHIVE_EXT@ diff --git a/imagequant.pc.in b/imagequant.pc.in index 980da8c..16935b7 100644 --- a/imagequant.pc.in +++ b/imagequant.pc.in @@ -1,10 +1,10 @@ -prefix=PREFIX +prefix=@PREFIX@ includedir=${prefix}/include libdir=${prefix}/lib Name: imagequant Description: Small, portable C library for high-quality conversion of RGBA images to 8-bit indexed-color (palette) images. URL: https://pngquant.org/lib/ -Version: VERSION +Version: @VERSION@ Libs: -L${libdir} -limagequant Cflags: -I${includedir} diff --git a/kmeans.c b/kmeans.c index 7ee273d..6d1a122 100644 --- a/kmeans.c +++ b/kmeans.c @@ -51,21 +51,29 @@ LIQ_PRIVATE void kmeans_finalize(colormap *map, const unsigned int max_threads, total += average_color[offset].total; } - if (total && !map->palette[i].fixed) { - map->palette[i].acolor = (f_pixel){ - .a = a / total, - .r = r / total, - .g = g / total, - .b = b / total, - }; + if (!map->palette[i].fixed) { map->palette[i].popularity = total; + if (total) { + map->palette[i].acolor = (f_pixel){ + .a = a / total, + .r = r / total, + .g = g / total, + .b = b / total, + }; + } else { + // if a color is useless, make a new one + // (it was supposed to be random, but Android NDK has problematic stdlib headers) + map->palette[i].acolor.a = map->palette[(i+1)%map->colors].acolor.a; + map->palette[i].acolor.r = map->palette[(i+2)%map->colors].acolor.r; + map->palette[i].acolor.g = map->palette[(i+3)%map->colors].acolor.g; + map->palette[i].acolor.b = map->palette[(i+4)%map->colors].acolor.b; + } } } } -LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kmeans_callback callback) +LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kmeans_callback callback, unsigned int max_threads) { - const unsigned int max_threads = omp_get_max_threads(); LIQ_ARRAY(kmeans_state, average_color, (KMEANS_CACHE_LINE_GAP+map->colors) * max_threads); kmeans_init(map, max_threads, average_color); struct nearest_map *const n = nearest_init(map); @@ -73,17 +81,35 @@ LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kme const int hist_size = hist->size; double total_diff=0; +#if __GNUC__ >= 9 || __clang__ + #pragma omp parallel for if (hist_size > 2000) \ + schedule(static) default(none) shared(achv,average_color,callback,hist_size,map,n) reduction(+:total_diff) +#else #pragma omp parallel for if (hist_size > 2000) \ schedule(static) default(none) shared(average_color,callback) reduction(+:total_diff) +#endif for(int j=0; j < hist_size; j++) { float diff; - unsigned int match = nearest_search(n, &achv[j].acolor, achv[j].tmp.likely_colormap_index, &diff); + const f_pixel px = achv[j].acolor; + const unsigned int match = nearest_search(n, &px, achv[j].tmp.likely_colormap_index, &diff); achv[j].tmp.likely_colormap_index = match; - total_diff += diff * achv[j].perceptual_weight; - kmeans_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, omp_get_thread_num(), average_color); + if (callback) { + // Check how average diff would look like if there was dithering + const f_pixel remapped = map->palette[match].acolor; + nearest_search(n, &(f_pixel){ + .a = px.a + px.a - remapped.a, + .r = px.r + px.r - remapped.r, + .g = px.g + px.g - remapped.g, + .b = px.b + px.b - remapped.b, + }, match, &diff); + + callback(&achv[j], diff); + } + + total_diff += diff * achv[j].perceptual_weight; - if (callback) callback(&achv[j], diff); + kmeans_update_color(px, achv[j].adjusted_weight, map, match, omp_get_thread_num(), average_color); } nearest_free(n); diff --git a/kmeans.h b/kmeans.h index c51d7bb..3216ed3 100644 --- a/kmeans.h +++ b/kmeans.h @@ -14,6 +14,6 @@ typedef void (*kmeans_callback)(hist_item *item, float diff); LIQ_PRIVATE void kmeans_init(const colormap *map, const unsigned int max_threads, kmeans_state state[]); LIQ_PRIVATE void kmeans_update_color(const f_pixel acolor, const float value, const colormap *map, unsigned int match, const unsigned int thread, kmeans_state average_color[]); LIQ_PRIVATE void kmeans_finalize(colormap *map, const unsigned int max_threads, const kmeans_state state[]); -LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kmeans_callback callback); +LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kmeans_callback callback, const unsigned int max_threads); #endif diff --git a/libimagequant-ios.xcodeproj/project.pbxproj b/libimagequant-ios.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6733c0f --- /dev/null +++ b/libimagequant-ios.xcodeproj/project.pbxproj @@ -0,0 +1,232 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5F65D41723A04D7B003E3A5B /* nearest.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41023A04D7B003E3A5B /* nearest.c */; }; + 5F65D41823A04D7B003E3A5B /* pam.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41123A04D7B003E3A5B /* pam.c */; }; + 5F65D41923A04D7B003E3A5B /* mempool.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41223A04D7B003E3A5B /* mempool.c */; }; + 5F65D41A23A04D7B003E3A5B /* mediancut.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41323A04D7B003E3A5B /* mediancut.c */; }; + 5F65D41B23A04D7B003E3A5B /* kmeans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41423A04D7B003E3A5B /* kmeans.c */; }; + 5F65D41C23A04D7B003E3A5B /* libimagequant.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41523A04D7B003E3A5B /* libimagequant.c */; }; + 5F65D41D23A04D7B003E3A5B /* blur.c in Sources */ = {isa = PBXBuildFile; fileRef = 5F65D41623A04D7B003E3A5B /* blur.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5FB37C7723A04C7300942532 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 5F65D41023A04D7B003E3A5B /* nearest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nearest.c; sourceTree = SOURCE_ROOT; }; + 5F65D41123A04D7B003E3A5B /* pam.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pam.c; sourceTree = SOURCE_ROOT; }; + 5F65D41223A04D7B003E3A5B /* mempool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mempool.c; sourceTree = SOURCE_ROOT; }; + 5F65D41323A04D7B003E3A5B /* mediancut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mediancut.c; sourceTree = SOURCE_ROOT; }; + 5F65D41423A04D7B003E3A5B /* kmeans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kmeans.c; sourceTree = SOURCE_ROOT; }; + 5F65D41523A04D7B003E3A5B /* libimagequant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libimagequant.c; sourceTree = SOURCE_ROOT; }; + 5F65D41623A04D7B003E3A5B /* blur.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blur.c; sourceTree = SOURCE_ROOT; }; + 5F65D41E23A04D93003E3A5B /* libimagequant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libimagequant.h; sourceTree = SOURCE_ROOT; }; + 5FB37C7923A04C7300942532 /* libimagequant.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libimagequant.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5FB37C7623A04C7300942532 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5FB37C7023A04C7300942532 = { + isa = PBXGroup; + children = ( + 5FB37C7B23A04C7300942532 /* imagequant */, + 5FB37C7A23A04C7300942532 /* Products */, + ); + sourceTree = ""; + }; + 5FB37C7A23A04C7300942532 /* Products */ = { + isa = PBXGroup; + children = ( + 5FB37C7923A04C7300942532 /* libimagequant.a */, + ); + name = Products; + sourceTree = ""; + }; + 5FB37C7B23A04C7300942532 /* imagequant */ = { + isa = PBXGroup; + children = ( + 5F65D41E23A04D93003E3A5B /* libimagequant.h */, + 5F65D41623A04D7B003E3A5B /* blur.c */, + 5F65D41423A04D7B003E3A5B /* kmeans.c */, + 5F65D41523A04D7B003E3A5B /* libimagequant.c */, + 5F65D41323A04D7B003E3A5B /* mediancut.c */, + 5F65D41223A04D7B003E3A5B /* mempool.c */, + 5F65D41023A04D7B003E3A5B /* nearest.c */, + 5F65D41123A04D7B003E3A5B /* pam.c */, + ); + path = imagequant; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5FB37C7823A04C7300942532 /* imagequant */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5FB37C8223A04C7300942532 /* Build configuration list for PBXNativeTarget "imagequant" */; + buildPhases = ( + 5FB37C7523A04C7300942532 /* Sources */, + 5FB37C7623A04C7300942532 /* Frameworks */, + 5FB37C7723A04C7300942532 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = imagequant; + productName = imagequant; + productReference = 5FB37C7923A04C7300942532 /* libimagequant.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5FB37C7123A04C7300942532 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "ImageOptim Ltd."; + TargetAttributes = { + 5FB37C7823A04C7300942532 = { + CreatedOnToolsVersion = 11.2; + }; + }; + }; + buildConfigurationList = 5FB37C7423A04C7300942532 /* Build configuration list for PBXProject "libimagequant-ios" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5FB37C7023A04C7300942532; + productRefGroup = 5FB37C7A23A04C7300942532 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5FB37C7823A04C7300942532 /* imagequant */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 5FB37C7523A04C7300942532 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F65D41B23A04D7B003E3A5B /* kmeans.c in Sources */, + 5F65D41923A04D7B003E3A5B /* mempool.c in Sources */, + 5F65D41823A04D7B003E3A5B /* pam.c in Sources */, + 5F65D41C23A04D7B003E3A5B /* libimagequant.c in Sources */, + 5F65D41A23A04D7B003E3A5B /* mediancut.c in Sources */, + 5F65D41723A04D7B003E3A5B /* nearest.c in Sources */, + 5F65D41D23A04D7B003E3A5B /* blur.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5FB37C8023A04C7300942532 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5FB37C8123A04C7300942532 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5FB37C8323A04C7300942532 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5FB37C8423A04C7300942532 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5FB37C7423A04C7300942532 /* Build configuration list for PBXProject "libimagequant-ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FB37C8023A04C7300942532 /* Debug */, + 5FB37C8123A04C7300942532 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FB37C8223A04C7300942532 /* Build configuration list for PBXNativeTarget "imagequant" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FB37C8323A04C7300942532 /* Debug */, + 5FB37C8423A04C7300942532 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5FB37C7123A04C7300942532 /* Project object */; +} diff --git a/libimagequant-mac.xcodeproj/project.pbxproj b/libimagequant-mac.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1526116 --- /dev/null +++ b/libimagequant-mac.xcodeproj/project.pbxproj @@ -0,0 +1,223 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5FF4F4CD23A04EF500A3FFB5 /* libimagequant.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FF4F4C523A04EF500A3FFB5 /* libimagequant.h */; }; + 5FF4F4CE23A04EF500A3FFB5 /* libimagequant.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4C623A04EF500A3FFB5 /* libimagequant.c */; }; + 5FF4F4CF23A04EF500A3FFB5 /* kmeans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4C723A04EF500A3FFB5 /* kmeans.c */; }; + 5FF4F4D023A04EF500A3FFB5 /* blur.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4C823A04EF500A3FFB5 /* blur.c */; }; + 5FF4F4D123A04EF500A3FFB5 /* mempool.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4C923A04EF500A3FFB5 /* mempool.c */; }; + 5FF4F4D223A04EF500A3FFB5 /* nearest.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4CA23A04EF500A3FFB5 /* nearest.c */; }; + 5FF4F4D323A04EF500A3FFB5 /* pam.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4CB23A04EF500A3FFB5 /* pam.c */; }; + 5FF4F4D423A04EF500A3FFB5 /* mediancut.c in Sources */ = {isa = PBXBuildFile; fileRef = 5FF4F4CC23A04EF500A3FFB5 /* mediancut.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5FF4F4BE23A04ED500A3FFB5 /* libimagequant.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libimagequant.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 5FF4F4C523A04EF500A3FFB5 /* libimagequant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libimagequant.h; path = ../../www/pngquant/lib/libimagequant.h; sourceTree = ""; }; + 5FF4F4C623A04EF500A3FFB5 /* libimagequant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = libimagequant.c; path = ../../www/pngquant/lib/libimagequant.c; sourceTree = ""; }; + 5FF4F4C723A04EF500A3FFB5 /* kmeans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = kmeans.c; path = ../../www/pngquant/lib/kmeans.c; sourceTree = ""; }; + 5FF4F4C823A04EF500A3FFB5 /* blur.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blur.c; path = ../../www/pngquant/lib/blur.c; sourceTree = ""; }; + 5FF4F4C923A04EF500A3FFB5 /* mempool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mempool.c; path = ../../www/pngquant/lib/mempool.c; sourceTree = ""; }; + 5FF4F4CA23A04EF500A3FFB5 /* nearest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nearest.c; path = ../../www/pngquant/lib/nearest.c; sourceTree = ""; }; + 5FF4F4CB23A04EF500A3FFB5 /* pam.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pam.c; path = ../../www/pngquant/lib/pam.c; sourceTree = ""; }; + 5FF4F4CC23A04EF500A3FFB5 /* mediancut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mediancut.c; path = ../../www/pngquant/lib/mediancut.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5FF4F4BC23A04ED500A3FFB5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5FF4F4B523A04ED500A3FFB5 = { + isa = PBXGroup; + children = ( + 5FF4F4C823A04EF500A3FFB5 /* blur.c */, + 5FF4F4C723A04EF500A3FFB5 /* kmeans.c */, + 5FF4F4C623A04EF500A3FFB5 /* libimagequant.c */, + 5FF4F4C523A04EF500A3FFB5 /* libimagequant.h */, + 5FF4F4CC23A04EF500A3FFB5 /* mediancut.c */, + 5FF4F4C923A04EF500A3FFB5 /* mempool.c */, + 5FF4F4CA23A04EF500A3FFB5 /* nearest.c */, + 5FF4F4CB23A04EF500A3FFB5 /* pam.c */, + 5FF4F4BF23A04ED500A3FFB5 /* Products */, + ); + sourceTree = ""; + }; + 5FF4F4BF23A04ED500A3FFB5 /* Products */ = { + isa = PBXGroup; + children = ( + 5FF4F4BE23A04ED500A3FFB5 /* libimagequant.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 5FF4F4BA23A04ED500A3FFB5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5FF4F4CD23A04EF500A3FFB5 /* libimagequant.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 5FF4F4BD23A04ED500A3FFB5 /* imagequant */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5FF4F4C223A04ED500A3FFB5 /* Build configuration list for PBXNativeTarget "imagequant" */; + buildPhases = ( + 5FF4F4BA23A04ED500A3FFB5 /* Headers */, + 5FF4F4BB23A04ED500A3FFB5 /* Sources */, + 5FF4F4BC23A04ED500A3FFB5 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = imagequant; + productName = imagequant; + productReference = 5FF4F4BE23A04ED500A3FFB5 /* libimagequant.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5FF4F4B623A04ED500A3FFB5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "ImageOptim Ltd."; + TargetAttributes = { + 5FF4F4BD23A04ED500A3FFB5 = { + CreatedOnToolsVersion = 11.2; + }; + }; + }; + buildConfigurationList = 5FF4F4B923A04ED500A3FFB5 /* Build configuration list for PBXProject "imagequant" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5FF4F4B523A04ED500A3FFB5; + productRefGroup = 5FF4F4BF23A04ED500A3FFB5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5FF4F4BD23A04ED500A3FFB5 /* imagequant */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 5FF4F4BB23A04ED500A3FFB5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5FF4F4D323A04EF500A3FFB5 /* pam.c in Sources */, + 5FF4F4D023A04EF500A3FFB5 /* blur.c in Sources */, + 5FF4F4D223A04EF500A3FFB5 /* nearest.c in Sources */, + 5FF4F4CF23A04EF500A3FFB5 /* kmeans.c in Sources */, + 5FF4F4CE23A04EF500A3FFB5 /* libimagequant.c in Sources */, + 5FF4F4D423A04EF500A3FFB5 /* mediancut.c in Sources */, + 5FF4F4D123A04EF500A3FFB5 /* mempool.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5FF4F4C023A04ED500A3FFB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 5FF4F4C123A04ED500A3FFB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Release; + }; + 5FF4F4C323A04ED500A3FFB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 5FF4F4C423A04ED500A3FFB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5FF4F4B923A04ED500A3FFB5 /* Build configuration list for PBXProject "imagequant" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FF4F4C023A04ED500A3FFB5 /* Debug */, + 5FF4F4C123A04ED500A3FFB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FF4F4C223A04ED500A3FFB5 /* Build configuration list for PBXNativeTarget "imagequant" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FF4F4C323A04ED500A3FFB5 /* Debug */, + 5FF4F4C423A04ED500A3FFB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5FF4F4B623A04ED500A3FFB5 /* Project object */; +} diff --git a/libimagequant.c b/libimagequant.c index 3506564..632c242 100644 --- a/libimagequant.c +++ b/libimagequant.c @@ -19,22 +19,14 @@ #error "Ignore torrent of syntax errors that may follow. It's only because compiler is set to use too old C version." #endif -#ifdef _OPENMP -#include -#define LIQ_TEMP_ROW_WIDTH(img_width) (((img_width) | 15) + 1) /* keep alignment & leave space between rows to avoid cache line contention */ -#else -#define LIQ_TEMP_ROW_WIDTH(img_width) (img_width) -#define omp_get_max_threads() 1 -#define omp_get_thread_num() 0 -#endif - #include "libimagequant.h" #include "pam.h" +#include "libimagequant_private.h" #include "mediancut.h" -#include "nearest.h" #include "blur.h" #include "kmeans.h" +#include "remap.h" #define LIQ_HIGH_MEMORY_LIMIT (1<<26) /* avoid allocating buffers larger than 64MB */ @@ -54,7 +46,6 @@ struct liq_attr { void (*free)(void*); double target_mse, max_mse, kmeans_iteration_limit; - float min_opaque_val; unsigned int max_colors, max_histogram_entries; unsigned int min_posterization_output /* user setting */, min_posterization_input /* speed setting */; unsigned int kmeans_iterations, feedback_loop_trials; @@ -72,44 +63,6 @@ struct liq_attr { void *log_flush_callback_user_info; }; -struct liq_image { - const char *magic_header; - void* (*malloc)(size_t); - void (*free)(void*); - - f_pixel *f_pixels; - rgba_pixel **rows; - double gamma; - unsigned int width, height; - unsigned char *importance_map, *edges, *dither_map; - rgba_pixel *pixels, *temp_row; - f_pixel *temp_f_row; - liq_image_get_rgba_row_callback *row_callback; - void *row_callback_user_info; - liq_image *background; - float min_opaque_val; - f_pixel fixed_colors[256]; - unsigned short fixed_colors_count; - bool free_pixels, free_rows, free_rows_internal; -}; - -typedef struct liq_remapping_result { - const char *magic_header; - void* (*malloc)(size_t); - void (*free)(void*); - - unsigned char *pixels; - colormap *palette; - liq_progress_callback_function *progress_callback; - void *progress_callback_user_info; - - liq_palette int_palette; - double gamma, palette_error; - float dither_level; - unsigned char use_dither_map; - unsigned char progress_stage1; -} liq_remapping_result; - struct liq_result { const char *magic_header; void* (*malloc)(size_t); @@ -140,12 +93,9 @@ struct liq_histogram { bool had_image_added; }; -static void modify_alpha(liq_image *input_image, rgba_pixel *const row_pixels) LIQ_NONNULL; static void contrast_maps(liq_image *image) LIQ_NONNULL; static liq_error finalize_histogram(liq_histogram *input_hist, liq_attr *options, histogram **hist_output) LIQ_NONNULL; -static const rgba_pixel *liq_image_get_row_rgba(liq_image *input_image, unsigned int row) LIQ_NONNULL; -static bool liq_image_get_row_f_init(liq_image *img) LIQ_NONNULL; -static const f_pixel *liq_image_get_row_f(liq_image *input_image, unsigned int row) LIQ_NONNULL; +static const liq_color *liq_image_get_row_rgba(liq_image *input_image, unsigned int row) LIQ_NONNULL; static void liq_remapping_result_destroy(liq_remapping_result *result) LIQ_NONNULL; static liq_error pngquant_quantize(histogram *hist, const liq_attr *options, const int fixed_colors_count, const f_pixel fixed_colors[], const double gamma, bool fixed_result_colors, liq_result **) LIQ_NONNULL; static liq_error liq_histogram_quantize_internal(liq_histogram *input_hist, liq_attr *attr, bool fixed_result_colors, liq_result **result_output) LIQ_NONNULL; @@ -186,7 +136,7 @@ LIQ_NONNULL static bool liq_progress(const liq_attr *attr, const float percent) return attr->progress_callback && !attr->progress_callback(percent, attr->progress_callback_user_info); } -LIQ_NONNULL static bool liq_remap_progress(const liq_remapping_result *quant, const float percent) +LIQ_PRIVATE LIQ_NONNULL bool liq_remap_progress(const liq_remapping_result *quant, const float percent) { return quant->progress_callback && !quant->progress_callback(percent, quant->progress_callback_user_info); } @@ -258,7 +208,8 @@ static double quality_to_mse(long quality) // curve fudged to be roughly similar to quality of libjpeg // except lowest 10 for really low number of colors const double extra_low_quality_fudge = MAX(0,0.016/(0.001+quality) - 0.001); - return extra_low_quality_fudge + 2.5/pow(210.0 + quality, 1.2) * (100.1-quality)/100.0; + // LIQ_WEIGHT_MSE is a fudge factor - reminder that colors are not in 0..1 range any more + return LIQ_WEIGHT_MSE * (extra_low_quality_fudge + 2.5/pow(210.0 + quality, 1.2) * (100.1-quality)/100.0); } static unsigned int mse_to_quality(double mse) @@ -274,7 +225,7 @@ static unsigned int mse_to_quality(double mse) /** internally MSE is a sum of all channels with pixels 0..1 range, but other software gives per-RGB-channel MSE for 0..255 range */ static double mse_to_standard_mse(double mse) { - return mse * 65536.0/6.0; + return (mse * 65536.0/6.0) / LIQ_WEIGHT_MSE; } LIQ_EXPORT LIQ_NONNULL liq_error liq_set_quality(liq_attr* attr, int minimum, int target) @@ -384,18 +335,12 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_set_output_gamma(liq_result* res, double ga LIQ_EXPORT LIQ_NONNULL liq_error liq_set_min_opacity(liq_attr* attr, int min) { - if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER; - if (min < 0 || min > 255) return LIQ_VALUE_OUT_OF_RANGE; - - attr->min_opaque_val = (double)min/255.0; return LIQ_OK; } LIQ_EXPORT LIQ_NONNULL int liq_get_min_opacity(const liq_attr *attr) { - if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1; - - return MIN(255.f, 256.f * attr->min_opaque_val); + return 0; } LIQ_EXPORT LIQ_NONNULL void liq_set_last_index_transparent(liq_attr* attr, int is_last) @@ -510,7 +455,6 @@ LIQ_EXPORT liq_attr* liq_attr_create_with_allocator(void* (*custom_malloc)(size_ .malloc = custom_malloc, .free = custom_free, .max_colors = 256, - .min_opaque_val = 1, // whether preserve opaque colors for IE (1.0=no, does not affect alpha) .last_index_transparent = false, // puts transparent color at last index. This is workaround for blu-ray subtitles. .target_mse = 0, .max_mse = MAX_DIFF, @@ -526,7 +470,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_image_add_fixed_color(liq_image *img, liq_c float gamma_lut[256]; to_f_set_gamma(gamma_lut, img->gamma); - img->fixed_colors[img->fixed_colors_count++] = rgba_to_f(gamma_lut, (rgba_pixel){ + img->fixed_colors[img->fixed_colors_count++] = rgba_to_f(gamma_lut, (liq_color){ .r = color.r, .g = color.g, .b = color.b, @@ -549,7 +493,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_histogram_add_fixed_color(liq_histogram *hi float gamma_lut[256]; to_f_set_gamma(gamma_lut, gamma ? gamma : 0.45455); - const f_pixel px = rgba_to_f(gamma_lut, (rgba_pixel){ + const f_pixel px = rgba_to_f(gamma_lut, (liq_color){ .r = color.r, .g = color.g, .b = color.b, @@ -560,16 +504,19 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_histogram_add_fixed_color(liq_histogram *hi LIQ_NONNULL static bool liq_image_use_low_memory(liq_image *img) { + if (img->temp_f_row) { + img->free(img->temp_f_row); + } img->temp_f_row = img->malloc(sizeof(img->f_pixels[0]) * LIQ_TEMP_ROW_WIDTH(img->width) * omp_get_max_threads()); return img->temp_f_row != NULL; } LIQ_NONNULL static bool liq_image_should_use_low_memory(liq_image *img, const bool low_memory_hint) { - return img->width * img->height > (low_memory_hint ? LIQ_HIGH_MEMORY_LIMIT/8 : LIQ_HIGH_MEMORY_LIMIT) / sizeof(f_pixel); // Watch out for integer overflow + return (size_t)img->width * (size_t)img->height > (low_memory_hint ? LIQ_HIGH_MEMORY_LIMIT/8 : LIQ_HIGH_MEMORY_LIMIT) / sizeof(f_pixel); // Watch out for integer overflow } -static liq_image *liq_image_create_internal(const liq_attr *attr, rgba_pixel* rows[], liq_image_get_rgba_row_callback *row_callback, void *row_callback_user_info, int width, int height, double gamma) +static liq_image *liq_image_create_internal(const liq_attr *attr, liq_color* rows[], liq_image_get_rgba_row_callback *row_callback, void *row_callback_user_info, int width, int height, double gamma) { if (gamma < 0 || gamma > 1.0) { liq_log_error(attr, "gamma must be >= 0 and <= 1 (try 1/gamma instead)"); @@ -592,10 +539,9 @@ static liq_image *liq_image_create_internal(const liq_attr *attr, rgba_pixel* ro .rows = rows, .row_callback = row_callback, .row_callback_user_info = row_callback_user_info, - .min_opaque_val = attr->min_opaque_val, }; - if (!rows || attr->min_opaque_val < 1.f) { + if (!rows) { img->temp_row = attr->malloc(sizeof(img->temp_row[0]) * LIQ_TEMP_ROW_WIDTH(width) * omp_get_max_threads()); if (!img->temp_row) return NULL; } @@ -606,10 +552,6 @@ static liq_image *liq_image_create_internal(const liq_attr *attr, rgba_pixel* ro if (!liq_image_use_low_memory(img)) return NULL; } - if (img->min_opaque_val < 1.f) { - verbose_print(attr, " Working around IE6 bug by making image less transparent..."); - } - return img; } @@ -641,13 +583,14 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_image_set_memory_ownership(liq_image *img, } LIQ_NONNULL static void liq_image_free_maps(liq_image *input_image); +LIQ_NONNULL static void liq_image_free_dither_map(liq_image *input_image); LIQ_NONNULL static void liq_image_free_importance_map(liq_image *input_image); LIQ_EXPORT LIQ_NONNULL liq_error liq_image_set_importance_map(liq_image *img, unsigned char importance_map[], size_t buffer_size, enum liq_ownership ownership) { if (!CHECK_STRUCT_TYPE(img, liq_image)) return LIQ_INVALID_POINTER; if (!CHECK_USER_POINTER(importance_map)) return LIQ_INVALID_POINTER; - const size_t required_size = img->width * img->height; + const size_t required_size = (size_t)img->width * (size_t)img->height; if (buffer_size < required_size) { return LIQ_BUFFER_TOO_SMALL; } @@ -686,7 +629,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_image_set_background(liq_image *img, liq_im } img->background = background; - liq_image_free_maps(img); // Force them to be re-analyzed with the background + liq_image_free_dither_map(img); // Force it to be re-analyzed with the background return LIQ_OK; } @@ -702,7 +645,7 @@ LIQ_NONNULL static bool check_image_size(const liq_attr *attr, const int width, return false; } - if (width > INT_MAX/sizeof(rgba_pixel)/height || width > INT_MAX/16/sizeof(f_pixel) || height > INT_MAX/sizeof(size_t)) { + if (width > INT_MAX/sizeof(liq_color)/height || width > INT_MAX/16/sizeof(f_pixel) || height > INT_MAX/sizeof(size_t)) { liq_log_error(attr, "image too large"); return false; } @@ -729,7 +672,7 @@ LIQ_EXPORT liq_image *liq_image_create_rgba_rows(const liq_attr *attr, void *con return NULL; } } - return liq_image_create_internal(attr, (rgba_pixel**)rows, NULL, NULL, width, height, gamma); + return liq_image_create_internal(attr, (liq_color**)rows, NULL, NULL, width, height, gamma); } LIQ_EXPORT LIQ_NONNULL liq_image *liq_image_create_rgba(const liq_attr *attr, const void* bitmap, int width, int height, double gamma) @@ -742,8 +685,8 @@ LIQ_EXPORT LIQ_NONNULL liq_image *liq_image_create_rgba(const liq_attr *attr, co return NULL; } - rgba_pixel *const pixels = (rgba_pixel *const)bitmap; - rgba_pixel **rows = attr->malloc(sizeof(rows[0])*height); + liq_color *const pixels = (liq_color *const)bitmap; + liq_color **rows = attr->malloc(sizeof(rows[0])*height); if (!rows) return NULL; for(int i=0; i < height; i++) { @@ -779,26 +722,23 @@ LIQ_NONNULL inline static bool liq_image_has_rgba_pixels(const liq_image *img) LIQ_NONNULL inline static bool liq_image_can_use_rgba_rows(const liq_image *img) { assert(liq_image_has_rgba_pixels(img)); - - const bool iebug = img->min_opaque_val < 1.f; - return (img->rows && !iebug); + return img->rows; } -LIQ_NONNULL static const rgba_pixel *liq_image_get_row_rgba(liq_image *img, unsigned int row) +LIQ_NONNULL static const liq_color *liq_image_get_row_rgba(liq_image *img, unsigned int row) { if (liq_image_can_use_rgba_rows(img)) { return img->rows[row]; } assert(img->temp_row); - rgba_pixel *temp_row = img->temp_row + LIQ_TEMP_ROW_WIDTH(img->width) * omp_get_thread_num(); + liq_color *temp_row = img->temp_row + LIQ_TEMP_ROW_WIDTH(img->width) * omp_get_thread_num(); if (img->rows) { memcpy(temp_row, img->rows[row], img->width * sizeof(temp_row[0])); } else { liq_executing_user_callback(img->row_callback, (liq_color*)temp_row, row, img->width, img->row_callback_user_info); } - if (img->min_opaque_val < 1.f) modify_alpha(img, temp_row); return temp_row; } @@ -807,14 +747,14 @@ LIQ_NONNULL static void convert_row_to_f(liq_image *img, f_pixel *row_f_pixels, assert(row_f_pixels); assert(!USE_SSE || 0 == ((uintptr_t)row_f_pixels & 15)); - const rgba_pixel *const row_pixels = liq_image_get_row_rgba(img, row); + const liq_color *const row_pixels = liq_image_get_row_rgba(img, row); for(unsigned int col=0; col < img->width; col++) { row_f_pixels[col] = rgba_to_f(gamma_lut, row_pixels[col]); } } -LIQ_NONNULL static bool liq_image_get_row_f_init(liq_image *img) +LIQ_PRIVATE LIQ_NONNULL bool liq_image_get_row_f_init(liq_image *img) { assert(omp_get_thread_num() == 0); if (img->f_pixels) { @@ -839,7 +779,7 @@ LIQ_NONNULL static bool liq_image_get_row_f_init(liq_image *img) return true; } -LIQ_NONNULL static const f_pixel *liq_image_get_row_f(liq_image *img, unsigned int row) +LIQ_PRIVATE LIQ_NONNULL const f_pixel *liq_image_get_row_f(liq_image *img, unsigned int row) { if (!img->f_pixels) { assert(img->temp_f_row); // init should have done that @@ -866,7 +806,16 @@ LIQ_EXPORT LIQ_NONNULL int liq_image_get_height(const liq_image *input_image) typedef void free_func(void*); -LIQ_NONNULL static free_func *get_default_free_func(liq_image *img) +LIQ_NONNULL static free_func *get_default_image_free_func(liq_image *img) +{ + // When default allocator is used then user-supplied pointers must be freed with free() + if (img->free != liq_aligned_free) { + return img->free; + } + return free; +} + +LIQ_NONNULL static free_func *get_default_rows_free_func(liq_image *img) { // When default allocator is used then user-supplied pointers must be freed with free() if (img->free_rows_internal || img->free != liq_aligned_free) { @@ -878,12 +827,12 @@ LIQ_NONNULL static free_func *get_default_free_func(liq_image *img) LIQ_NONNULL static void liq_image_free_rgba_source(liq_image *input_image) { if (input_image->free_pixels && input_image->pixels) { - get_default_free_func(input_image)(input_image->pixels); + get_default_image_free_func(input_image)(input_image->pixels); input_image->pixels = NULL; } if (input_image->free_rows && input_image->rows) { - get_default_free_func(input_image)(input_image->rows); + get_default_rows_free_func(input_image)(input_image->rows); input_image->rows = NULL; } } @@ -902,7 +851,10 @@ LIQ_NONNULL static void liq_image_free_maps(liq_image *input_image) { input_image->free(input_image->edges); input_image->edges = NULL; } + liq_image_free_dither_map(input_image); +} +LIQ_NONNULL static void liq_image_free_dither_map(liq_image *input_image) { if (input_image->dither_map) { input_image->free(input_image->dither_map); input_image->dither_map = NULL; @@ -986,6 +938,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_image_quantize(liq_image *const img, liq_at } liq_error err = liq_histogram_add_image(hist, attr, img); if (LIQ_OK != err) { + liq_histogram_destroy(hist); return err; } @@ -1030,7 +983,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_set_dithering_level(liq_result *res, float res->remapping = NULL; } - if (res->dither_level < 0 || res->dither_level > 1.0f) return LIQ_VALUE_OUT_OF_RANGE; + if (dither_level < 0 || dither_level > 1.0f) return LIQ_VALUE_OUT_OF_RANGE; res->dither_level = dither_level; return LIQ_OK; } @@ -1162,7 +1115,7 @@ LIQ_NONNULL static void sort_palette(colormap *map, const liq_attr *options) */ if (options->last_index_transparent) { for(unsigned int i=0; i < map->colors; i++) { - if (map->palette[i].acolor.a < 1.f/256.f) { + if (map->palette[i].acolor.a < MIN_OPAQUE_A) { const unsigned int old = i, transparent_dest = map->colors-1; SWAP_PALETTE(map, transparent_dest, old); @@ -1185,7 +1138,7 @@ LIQ_NONNULL static void sort_palette(colormap *map, const liq_attr *options) /* move transparent colors to the beginning to shrink trns chunk */ unsigned int num_transparent = 0; for(unsigned int i = 0; i < non_fixed_colors; i++) { - if (map->palette[i].acolor.a < 255.f/256.f) { + if (map->palette[i].acolor.a < 255.f/256.f * LIQ_WEIGHT_A) { // current transparent color is swapped with earlier opaque one if (i != num_transparent) { SWAP_PALETTE(map, num_transparent, i); @@ -1222,7 +1175,7 @@ LIQ_NONNULL static void set_rounded_palette(liq_palette *const dest, colormap *c dest->count = map->colors; for(unsigned int x = 0; x < map->colors; ++x) { - rgba_pixel px = f_to_rgb(gamma, map->palette[x].acolor); + liq_color px = f_to_rgb(gamma, map->palette[x].acolor); px.r = posterize_channel(px.r, posterize); px.g = posterize_channel(px.g, posterize); @@ -1253,268 +1206,6 @@ LIQ_EXPORT LIQ_NONNULL const liq_palette *liq_get_palette(liq_result *result) return &result->int_palette; } -LIQ_NONNULL static float remap_to_palette(liq_image *const input_image, unsigned char *const *const output_pixels, colormap *const map) -{ - const int rows = input_image->height; - const unsigned int cols = input_image->width; - double remapping_error=0; - - if (!liq_image_get_row_f_init(input_image)) { - return -1; - } - if (input_image->background && !liq_image_get_row_f_init(input_image->background)) { - return -1; - } - - const colormap_item *acolormap = map->palette; - - struct nearest_map *const n = nearest_init(map); - const int transparent_index = input_image->background ? nearest_search(n, &(f_pixel){0,0,0,0}, 0, NULL) : 0; - - - const unsigned int max_threads = omp_get_max_threads(); - LIQ_ARRAY(kmeans_state, average_color, (KMEANS_CACHE_LINE_GAP+map->colors) * max_threads); - kmeans_init(map, max_threads, average_color); - - #pragma omp parallel for if (rows*cols > 3000) \ - schedule(static) default(none) shared(acolormap) shared(average_color) reduction(+:remapping_error) - for(int row = 0; row < rows; ++row) { - const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row); - const f_pixel *const bg_pixels = input_image->background && acolormap[transparent_index].acolor.a < 1.f/256.f ? liq_image_get_row_f(input_image->background, row) : NULL; - - unsigned int last_match=0; - for(unsigned int col = 0; col < cols; ++col) { - float diff; - last_match = nearest_search(n, &row_pixels[col], last_match, &diff); - if (bg_pixels && colordifference(bg_pixels[col], acolormap[last_match].acolor) <= diff) { - last_match = transparent_index; - } - output_pixels[row][col] = last_match; - - remapping_error += diff; - kmeans_update_color(row_pixels[col], 1.0, map, last_match, omp_get_thread_num(), average_color); - } - } - - kmeans_finalize(map, max_threads, average_color); - - nearest_free(n); - - return remapping_error / (input_image->width * input_image->height); -} - -inline static f_pixel get_dithered_pixel(const float dither_level, const float max_dither_error, const f_pixel thiserr, const f_pixel px) -{ - /* Use Floyd-Steinberg errors to adjust actual color. */ - const float sr = thiserr.r * dither_level, - sg = thiserr.g * dither_level, - sb = thiserr.b * dither_level, - sa = thiserr.a * dither_level; - - float ratio = 1.0; - const float max_overflow = 1.1f; - const float max_underflow = -0.1f; - - // allowing some overflow prevents undithered bands caused by clamping of all channels - if (px.r + sr > max_overflow) ratio = MIN(ratio, (max_overflow -px.r)/sr); - else { if (px.r + sr < max_underflow) ratio = MIN(ratio, (max_underflow-px.r)/sr); } - if (px.g + sg > max_overflow) ratio = MIN(ratio, (max_overflow -px.g)/sg); - else { if (px.g + sg < max_underflow) ratio = MIN(ratio, (max_underflow-px.g)/sg); } - if (px.b + sb > max_overflow) ratio = MIN(ratio, (max_overflow -px.b)/sb); - else { if (px.b + sb < max_underflow) ratio = MIN(ratio, (max_underflow-px.b)/sb); } - - float a = px.a + sa; - if (a > 1.f) { a = 1.f; } - else if (a < 0) { a = 0; } - - // If dithering error is crazy high, don't propagate it that much - // This prevents crazy geen pixels popping out of the blue (or red or black! ;) - const float dither_error = sr*sr + sg*sg + sb*sb + sa*sa; - if (dither_error > max_dither_error) { - ratio *= 0.8f; - } else if (dither_error < 2.f/256.f/256.f) { - // don't dither areas that don't have noticeable error — makes file smaller - return px; - } - - return (f_pixel) { - .r=px.r + sr * ratio, - .g=px.g + sg * ratio, - .b=px.b + sb * ratio, - .a=a, - }; -} - -/** - Uses edge/noise map to apply dithering only to flat areas. Dithering on edges creates jagged lines, and noisy areas are "naturally" dithered. - - If output_image_is_remapped is true, only pixels noticeably changed by error diffusion will be written to output image. - */ -LIQ_NONNULL static bool remap_to_palette_floyd(liq_image *input_image, unsigned char *const output_pixels[], liq_remapping_result *quant, const float max_dither_error, const bool output_image_is_remapped) -{ - const int rows = input_image->height, cols = input_image->width; - const unsigned char *dither_map = quant->use_dither_map ? (input_image->dither_map ? input_image->dither_map : input_image->edges) : NULL; - - const colormap *map = quant->palette; - const colormap_item *acolormap = map->palette; - - if (!liq_image_get_row_f_init(input_image)) { - return false; - } - if (input_image->background && !liq_image_get_row_f_init(input_image->background)) { - return false; - } - - /* Initialize Floyd-Steinberg error vectors. */ - const size_t errwidth = cols+2; - f_pixel *restrict thiserr = input_image->malloc(errwidth * sizeof(thiserr[0]) * 2); // +2 saves from checking out of bounds access - if (!thiserr) return false; - f_pixel *restrict nexterr = thiserr + errwidth; - memset(thiserr, 0, errwidth * sizeof(thiserr[0])); - - bool ok = true; - struct nearest_map *const n = nearest_init(map); - const int transparent_index = input_image->background ? nearest_search(n, &(f_pixel){0,0,0,0}, 0, NULL) : 0; - - // response to this value is non-linear and without it any value < 0.8 would give almost no dithering - float base_dithering_level = quant->dither_level; - base_dithering_level = 1.f - (1.f-base_dithering_level)*(1.f-base_dithering_level); - - if (dither_map) { - base_dithering_level *= 1.f/255.f; // convert byte to float - } - base_dithering_level *= 15.f/16.f; // prevent small errors from accumulating - - int fs_direction = 1; - unsigned int last_match=0; - for (int row = 0; row < rows; ++row) { - if (liq_remap_progress(quant, quant->progress_stage1 + row * (100.f - quant->progress_stage1) / rows)) { - ok = false; - break; - } - - memset(nexterr, 0, errwidth * sizeof(nexterr[0])); - - int col = (fs_direction > 0) ? 0 : (cols - 1); - const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row); - const f_pixel *const bg_pixels = input_image->background && acolormap[transparent_index].acolor.a < 1.f/256.f ? liq_image_get_row_f(input_image->background, row) : NULL; - - do { - float dither_level = base_dithering_level; - if (dither_map) { - dither_level *= dither_map[row*cols + col]; - } - - const f_pixel spx = get_dithered_pixel(dither_level, max_dither_error, thiserr[col + 1], row_pixels[col]); - - const unsigned int guessed_match = output_image_is_remapped ? output_pixels[row][col] : last_match; - float diff; - last_match = nearest_search(n, &spx, guessed_match, &diff); - f_pixel output_px = acolormap[last_match].acolor; - if (bg_pixels && colordifference(bg_pixels[col], output_px) <= diff) { - output_px = bg_pixels[col]; - output_pixels[row][col] = transparent_index; - } else { - output_pixels[row][col] = last_match; - } - - f_pixel err = { - .r = (spx.r - output_px.r), - .g = (spx.g - output_px.g), - .b = (spx.b - output_px.b), - .a = (spx.a - output_px.a), - }; - - // If dithering error is crazy high, don't propagate it that much - // This prevents crazy geen pixels popping out of the blue (or red or black! ;) - if (err.r*err.r + err.g*err.g + err.b*err.b + err.a*err.a > max_dither_error) { - err.r *= 0.75f; - err.g *= 0.75f; - err.b *= 0.75f; - err.a *= 0.75f; - } - - /* Propagate Floyd-Steinberg error terms. */ - if (fs_direction > 0) { - thiserr[col + 2].a += err.a * (7.f/16.f); - thiserr[col + 2].r += err.r * (7.f/16.f); - thiserr[col + 2].g += err.g * (7.f/16.f); - thiserr[col + 2].b += err.b * (7.f/16.f); - - nexterr[col + 2].a = err.a * (1.f/16.f); - nexterr[col + 2].r = err.r * (1.f/16.f); - nexterr[col + 2].g = err.g * (1.f/16.f); - nexterr[col + 2].b = err.b * (1.f/16.f); - - nexterr[col + 1].a += err.a * (5.f/16.f); - nexterr[col + 1].r += err.r * (5.f/16.f); - nexterr[col + 1].g += err.g * (5.f/16.f); - nexterr[col + 1].b += err.b * (5.f/16.f); - - nexterr[col ].a += err.a * (3.f/16.f); - nexterr[col ].r += err.r * (3.f/16.f); - nexterr[col ].g += err.g * (3.f/16.f); - nexterr[col ].b += err.b * (3.f/16.f); - - } else { - thiserr[col ].a += err.a * (7.f/16.f); - thiserr[col ].r += err.r * (7.f/16.f); - thiserr[col ].g += err.g * (7.f/16.f); - thiserr[col ].b += err.b * (7.f/16.f); - - nexterr[col ].a = err.a * (1.f/16.f); - nexterr[col ].r = err.r * (1.f/16.f); - nexterr[col ].g = err.g * (1.f/16.f); - nexterr[col ].b = err.b * (1.f/16.f); - - nexterr[col + 1].a += err.a * (5.f/16.f); - nexterr[col + 1].r += err.r * (5.f/16.f); - nexterr[col + 1].g += err.g * (5.f/16.f); - nexterr[col + 1].b += err.b * (5.f/16.f); - - nexterr[col + 2].a += err.a * (3.f/16.f); - nexterr[col + 2].r += err.r * (3.f/16.f); - nexterr[col + 2].g += err.g * (3.f/16.f); - nexterr[col + 2].b += err.b * (3.f/16.f); - } - - // remapping is done in zig-zag - col += fs_direction; - if (fs_direction > 0) { - if (col >= cols) break; - } else { - if (col < 0) break; - } - } while(1); - - f_pixel *const temperr = thiserr; - thiserr = nexterr; - nexterr = temperr; - fs_direction = -fs_direction; - } - - input_image->free(MIN(thiserr, nexterr)); // MIN because pointers were swapped - nearest_free(n); - - return ok; -} - -/* fixed colors are always included in the palette, so it would be wasteful to duplicate them in palette from histogram */ -LIQ_NONNULL static void remove_fixed_colors_from_histogram(histogram *hist, const int fixed_colors_count, const f_pixel fixed_colors[], const float target_mse) -{ - const float max_difference = MAX(target_mse/2.f, 2.f/256.f/256.f); - if (fixed_colors_count) { - for(int j=0; j < hist->size; j++) { - for(unsigned int i=0; i < fixed_colors_count; i++) { - if (colordifference(hist->achv[j].acolor, fixed_colors[i]) < max_difference) { - hist->achv[j] = hist->achv[--hist->size]; // remove color from histogram by overwriting with the last entry - j--; break; // continue searching histogram - } - } - } - } -} - LIQ_EXPORT LIQ_NONNULL liq_error liq_histogram_add_colors(liq_histogram *input_hist, const liq_attr *options, const liq_histogram_entry entries[], int num_entries, double gamma) { if (!CHECK_STRUCT_TYPE(options, liq_attr)) return LIQ_INVALID_POINTER; @@ -1545,7 +1236,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_histogram_add_colors(liq_histogram *input_h const unsigned int hash_size = input_hist->acht->hash_size; for(int i=0; i < num_entries; i++) { - const rgba_pixel rgba = { + const liq_color rgba = { .r = entries[i].color.r, .g = entries[i].color.g, .b = entries[i].color.b, @@ -1613,10 +1304,10 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_histogram_add_image(liq_histogram *input_hi for(unsigned int row=0; row < rows; row++) { bool added_ok; if (all_rows_at_once) { - added_ok = pam_computeacolorhash(input_hist->acht, (const rgba_pixel *const *)input_image->rows, cols, rows, input_image->importance_map); + added_ok = pam_computeacolorhash(input_hist->acht, (const liq_color *const *)input_image->rows, cols, rows, input_image->importance_map); if (added_ok) break; } else { - const rgba_pixel* rows_p[1] = { liq_image_get_row_rgba(input_image, row) }; + const liq_color* rows_p[1] = { liq_image_get_row_rgba(input_image, row) }; added_ok = pam_computeacolorhash(input_hist->acht, rows_p, cols, 1, input_image->importance_map ? &input_image->importance_map[row * cols] : NULL); } if (!added_ok) { @@ -1665,29 +1356,6 @@ LIQ_NONNULL static liq_error finalize_histogram(liq_histogram *input_hist, liq_a return LIQ_OK; } -LIQ_NONNULL static void modify_alpha(liq_image *input_image, rgba_pixel *const row_pixels) -{ - /* IE6 makes colors with even slightest transparency completely transparent, - thus to improve situation in IE, make colors that are less than ~10% transparent - completely opaque */ - - const float min_opaque_val = input_image->min_opaque_val; - const float almost_opaque_val = min_opaque_val * 169.f/256.f; - const unsigned int almost_opaque_val_int = (min_opaque_val * 169.f/256.f)*255.f; - - for(unsigned int col = 0; col < input_image->width; col++) { - const rgba_pixel px = row_pixels[col]; - - /* ie bug: to avoid visible step caused by forced opaqueness, linearily raise opaqueness of almost-opaque colors */ - if (px.a >= almost_opaque_val_int) { - float al = px.a / 255.f; - al = almost_opaque_val + (al-almost_opaque_val) * (1.f-almost_opaque_val) / (min_opaque_val-almost_opaque_val); - al *= 256.f; - row_pixels[col].a = al >= 255.f ? 255 : al; - } - } -} - /** Builds two maps: importance_map - approximation of areas with high-frequency noise, except straight edges. 1=flat, 0=noisy. @@ -1750,7 +1418,7 @@ LIQ_NONNULL static void contrast_maps(liq_image *image) z *= z; // noise is amplified z *= z; // 85 is about 1/3rd of weight (not 0, because noisy pixels still need to be included, just not as precisely). - const unsigned int z_int = 85 + (unsigned int)(z * 171.f); + const unsigned int z_int = 80 + (unsigned int)(z * 176.f); noise[j*cols+i] = MIN(z_int, 255); const int e_int = 255 - (int)(edge * 256.f); edges[j*cols+i] = e_int > 0 ? MIN(e_int, 255) : 0; @@ -1798,7 +1466,7 @@ LIQ_NONNULL static void update_dither_map(liq_image *input_image, unsigned char for(unsigned int col=1; col < width; col++) { const unsigned char px = row_pointers[row][col]; - if (input_image->background && map->palette[px].acolor.a < 1.f/256.f) { + if (input_image->background && map->palette[px].acolor.a < MIN_OPAQUE_A) { // Transparency may or may not create an edge. When there's an explicit background set, assume no edge. continue; } @@ -1858,7 +1526,7 @@ static colormap *add_fixed_colors_to_palette(colormap *palette, const int max_co LIQ_NONNULL static void adjust_histogram_callback(hist_item *item, float diff) { - item->adjusted_weight = (item->perceptual_weight+item->adjusted_weight) * (sqrtf(1.f+diff)); + item->adjusted_weight = (item->perceptual_weight + 2.f * item->adjusted_weight) * (0.5f + diff); } /** @@ -1882,6 +1550,7 @@ static colormap *find_best_palette(histogram *hist, const liq_attr *options, con double least_error = MAX_DIFF; double target_mse_overshoot = feedback_loop_trials>0 ? 1.05 : 1.0; const float total_trials = (float)(feedback_loop_trials>0?feedback_loop_trials:1); + int fails_in_a_row=0; do { colormap *newmap; @@ -1906,7 +1575,7 @@ static colormap *find_best_palette(histogram *hist, const liq_attr *options, con // and histogram weights are adjusted based on remapping error to give more weight to poorly matched colors const bool first_run_of_target_mse = !acolormap && target_mse > 0; - double total_error = kmeans_do_iteration(hist, newmap, first_run_of_target_mse ? NULL : adjust_histogram_callback); + double total_error = kmeans_do_iteration(hist, newmap, first_run_of_target_mse ? NULL : adjust_histogram_callback, omp_get_max_threads()); // goal is to increase quality or to reduce number of colors used if quality is good enough if (!acolormap || total_error < least_error || (total_error <= target_mse && newmap->colors < max_colors)) { @@ -1926,15 +1595,13 @@ static colormap *find_best_palette(histogram *hist, const liq_attr *options, con max_colors = MIN(newmap->colors+1, max_colors); feedback_loop_trials -= 1; // asymptotic improvement could make it go on forever + fails_in_a_row = 0; } else { - for(unsigned int j=0; j < hist->size; j++) { - hist->achv[j].adjusted_weight = (hist->achv[j].perceptual_weight + hist->achv[j].adjusted_weight)/2.0; - } - + fails_in_a_row++; target_mse_overshoot = 1.0; - feedback_loop_trials -= 6; + // if error is really bad, it's unlikely to improve, so end sooner - if (total_error > least_error*4) feedback_loop_trials -= 3; + feedback_loop_trials -= 5 + fails_in_a_row; pam_freecolormap(newmap); } @@ -1948,18 +1615,6 @@ static colormap *find_best_palette(histogram *hist, const liq_attr *options, con return acolormap; } -static colormap *histogram_to_palette(const histogram *hist, const liq_attr *options) { - if (!hist->size) { - return NULL; - } - colormap *acolormap = pam_colormap(hist->size, options->malloc, options->free); - for(unsigned int i=0; i < hist->size; i++) { - acolormap->palette[i].acolor = hist->achv[i].acolor; - acolormap->palette[i].popularity = hist->achv[i].perceptual_weight; - } - return acolormap; -} - LIQ_NONNULL static liq_error pngquant_quantize(histogram *hist, const liq_attr *options, const int fixed_colors_count, const f_pixel fixed_colors[], const double gamma, bool fixed_result_colors, liq_result **result_output) { colormap *acolormap; @@ -1974,7 +1629,8 @@ LIQ_NONNULL static liq_error pngquant_quantize(histogram *hist, const liq_attr * // If image has few colors to begin with (and no quality degradation is required) // then it's possible to skip quantization entirely if (few_input_colors && options->target_mse == 0) { - acolormap = add_fixed_colors_to_palette(histogram_to_palette(hist, options), options->max_colors, fixed_colors, fixed_colors_count, options->malloc, options->free); + colormap *hist_pal = histogram_to_palette(hist, options->malloc, options->free); + acolormap = add_fixed_colors_to_palette(hist_pal, options->max_colors, fixed_colors, fixed_colors_count, options->malloc, options->free); palette_error = 0; } else { const double max_mse = options->max_mse * (few_input_colors ? 0.33 : 1.0); // when degrading image that's already paletted, require much higher improvement, since pal2pal often looks bad and there's little gain @@ -1991,11 +1647,7 @@ LIQ_NONNULL static liq_error pngquant_quantize(histogram *hist, const liq_attr * if (iterations) { // likely_colormap_index (used and set in kmeans_do_iteration) can't point to index outside colormap - if (acolormap->colors < 256) for(unsigned int j=0; j < hist->size; j++) { - if (hist->achv[j].tmp.likely_colormap_index >= acolormap->colors) { - hist->achv[j].tmp.likely_colormap_index = 0; // actual value doesn't matter, as the guess is out of date anyway - } - } + hist_reset_colors(hist, acolormap->colors); if (hist->size > 5000) {iterations = (iterations*3 + 3)/4;} if (hist->size > 25000) {iterations = (iterations*3 + 3)/4;} @@ -2007,7 +1659,7 @@ LIQ_NONNULL static liq_error pngquant_quantize(histogram *hist, const liq_attr * double previous_palette_error = MAX_DIFF; for(unsigned int i=0; i < iterations; i++) { - palette_error = kmeans_do_iteration(hist, acolormap, NULL); + palette_error = kmeans_do_iteration(hist, acolormap, NULL, omp_get_max_threads()); if (liq_progress(options, options->progress_stage1 + options->progress_stage2 + (i * options->progress_stage3 * 0.9f) / iterations)) { break; @@ -2078,17 +1730,20 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_write_remapped_image(liq_result *result, li return LIQ_INVALID_POINTER; } - const size_t required_size = input_image->width * input_image->height; + const size_t required_size = (size_t)input_image->width * (size_t)input_image->height; if (buffer_size < required_size) { return LIQ_BUFFER_TOO_SMALL; } - LIQ_ARRAY(unsigned char *, rows, input_image->height); + unsigned char **rows = input_image->malloc(input_image->height * sizeof(unsigned char *)); unsigned char *buffer_bytes = buffer; for(unsigned int i=0; i < input_image->height; i++) { rows[i] = &buffer_bytes[input_image->width * i]; } - return liq_write_remapped_image_rows(result, input_image, rows); + + liq_error err = liq_write_remapped_image_rows(result, input_image, rows); + input_image->free(rows); + return err; } LIQ_EXPORT LIQ_NONNULL liq_error liq_write_remapped_image_rows(liq_result *quant, liq_image *input_image, unsigned char **row_pointers) @@ -2139,7 +1794,7 @@ LIQ_EXPORT LIQ_NONNULL liq_error liq_write_remapped_image_rows(liq_result *quant // remapping above was the last chance to do K-Means iteration, hence the final palette is set after remapping set_rounded_palette(&result->int_palette, result->palette, result->gamma, quant->min_posterization_output); - if (!remap_to_palette_floyd(input_image, row_pointers, result, MAX(remapping_error*2.4, 16.f/256.f), generate_dither_map)) { + if (!remap_to_palette_floyd(input_image, row_pointers, result, MAX(remapping_error*2.4f, 8.f/256.f), generate_dither_map)) { return LIQ_ABORTED; } } diff --git a/libimagequant.h b/libimagequant.h index c8f84b5..e4763ab 100644 --- a/libimagequant.h +++ b/libimagequant.h @@ -13,8 +13,8 @@ #define LIQ_EXPORT extern #endif -#define LIQ_VERSION 21200 -#define LIQ_VERSION_STRING "2.12.2" +#define LIQ_VERSION 21800 +#define LIQ_VERSION_STRING "2.18.0" #ifndef LIQ_PRIVATE #if defined(__GNUC__) || defined (__llvm__) diff --git a/libimagequant_private.h b/libimagequant_private.h new file mode 100644 index 0000000..1919692 --- /dev/null +++ b/libimagequant_private.h @@ -0,0 +1,51 @@ + +#ifdef _OPENMP +#include +#define LIQ_TEMP_ROW_WIDTH(img_width) (((img_width) | 15) + 1) /* keep alignment & leave space between rows to avoid cache line contention */ +#else +#define LIQ_TEMP_ROW_WIDTH(img_width) (img_width) +#define omp_get_max_threads() 1 +#define omp_get_thread_num() 0 +#endif + +struct liq_image { + const char *magic_header; + void* (*malloc)(size_t); + void (*free)(void*); + + f_pixel *f_pixels; + liq_color **rows; + double gamma; + unsigned int width, height; + unsigned char *importance_map, *edges, *dither_map; + liq_color *pixels, *temp_row; + f_pixel *temp_f_row; + liq_image_get_rgba_row_callback *row_callback; + void *row_callback_user_info; + liq_image *background; + f_pixel fixed_colors[256]; + unsigned short fixed_colors_count; + bool free_pixels, free_rows, free_rows_internal; +}; + +typedef struct liq_remapping_result { + const char *magic_header; + void* (*malloc)(size_t); + void (*free)(void*); + + unsigned char *pixels; + colormap *palette; + liq_progress_callback_function *progress_callback; + void *progress_callback_user_info; + + liq_palette int_palette; + double gamma, palette_error; + float dither_level; + unsigned char use_dither_map; + unsigned char progress_stage1; +} liq_remapping_result; + + +LIQ_PRIVATE bool liq_image_get_row_f_init(liq_image *img) LIQ_NONNULL; +LIQ_PRIVATE const f_pixel *liq_image_get_row_f(liq_image *input_image, unsigned int row) LIQ_NONNULL; +LIQ_PRIVATE bool liq_remap_progress(const liq_remapping_result *quant, const float percent) LIQ_NONNULL; diff --git a/mediancut.c b/mediancut.c index 447a4af..cc241b8 100644 --- a/mediancut.c +++ b/mediancut.c @@ -25,34 +25,26 @@ struct box { unsigned int colors; }; -ALWAYS_INLINE static double variance_diff(double val, const double good_enough); -inline static double variance_diff(double val, const double good_enough) -{ - val *= val; - if (val < good_enough*good_enough) return val*0.25; - return val; -} - /** Weighted per-channel variance of the box. It's used to decide which channel to split by */ static f_pixel box_variance(const hist_item achv[], const struct box *box) { - f_pixel mean = box->color; + const f_pixel mean = box->color; double variancea=0, variancer=0, varianceg=0, varianceb=0; for(unsigned int i = 0; i < box->colors; ++i) { const f_pixel px = achv[box->ind + i].acolor; double weight = achv[box->ind + i].adjusted_weight; - variancea += variance_diff(mean.a - px.a, 2.0/256.0)*weight; - variancer += variance_diff(mean.r - px.r, 1.0/256.0)*weight; - varianceg += variance_diff(mean.g - px.g, 1.0/256.0)*weight; - varianceb += variance_diff(mean.b - px.b, 1.0/256.0)*weight; + variancea += (mean.a - px.a)*(mean.a - px.a)*weight; + variancer += (mean.r - px.r)*(mean.r - px.r)*weight; + varianceg += (mean.g - px.g)*(mean.g - px.g)*weight; + varianceb += (mean.b - px.b)*(mean.b - px.b)*weight; } return (f_pixel){ - .a = variancea*(4.0/16.0), - .r = variancer*(7.0/16.0), - .g = varianceg*(9.0/16.0), - .b = varianceb*(5.0/16.0), + .a = variancea, + .r = variancer, + .g = varianceg, + .b = varianceb, }; } @@ -133,35 +125,37 @@ static void hist_item_sort_range(hist_item base[], unsigned int len, unsigned in } } -/** sorts array to make sum of weights lower than halfvar one side, returns edge between halfvar parts of the set */ -static hist_item *hist_item_sort_halfvar(hist_item base[], unsigned int len, double *const lowervar, const double halfvar) +/** sorts array to make sum of weights lower than halfvar one side, returns index of the edge between halfvar parts of the set */ +static unsigned int hist_item_sort_halfvar(hist_item base[], unsigned int len, double halfvar) { + unsigned int base_idx = 0; // track base-index do { const unsigned int l = qsort_partition(base, len), r = l+1; // check if sum of left side is smaller than half, // if it is, then it doesn't need to be sorted - unsigned int t = 0; double tmpsum = *lowervar; - while (t <= l && tmpsum < halfvar) tmpsum += base[t++].color_weight; + double tmpsum = 0.; + for(unsigned int t = 0; t <= l && tmpsum < halfvar; ++t) tmpsum += base[t].color_weight; - if (tmpsum < halfvar) { - *lowervar = tmpsum; - } else { + // the split is on the left part + if (tmpsum >= halfvar) { if (l > 0) { - hist_item *res = hist_item_sort_halfvar(base, l, lowervar, halfvar); - if (res) return res; + len = l; + continue; } else { - // End of left recursion. This will be executed in order from the first element. - *lowervar += base[0].color_weight; - if (*lowervar > halfvar) return &base[0]; + // reached the end of left part + return base_idx; } } - + // process the right part + halfvar -= tmpsum; if (len > r) { - base += r; len -= r; // tail-recursive "call" + base += r; + base_idx += r; + len -= r; // tail-recursive "call" } else { - *lowervar += base[r].color_weight; - return (*lowervar > halfvar) ? &base[r] : NULL; + // reached the end of the right part + return base_idx + len; } } while(1); } @@ -195,8 +189,13 @@ static double prepare_sort(struct box *b, hist_item achv[]) const unsigned int ind1 = b->ind; const unsigned int colors = b->colors; +#if __GNUC__ >= 9 || __clang__ + #pragma omp parallel for if (colors > 25000) \ + schedule(static) default(none) shared(achv, channels, colors, ind1) +#else #pragma omp parallel for if (colors > 25000) \ schedule(static) default(none) shared(achv, channels) +#endif for(unsigned int i=0; i < colors; i++) { const float *chans = (const float *)&achv[ind1 + i].acolor; // Only the first channel really matters. When trying median cut many times @@ -305,15 +304,16 @@ static bool total_box_error_below_target(double target_mse, struct box bv[], uns } static void box_init(struct box *box, const hist_item *achv, const unsigned int ind, const unsigned int colors, const double sum) { + assert(colors > 0); + assert(sum > 0); + box->ind = ind; box->colors = colors; box->sum = sum; box->total_error = -1; box->color = averagepixels(colors, &achv[ind]); - #pragma omp task if (colors > 5000) box->variance = box_variance(achv, box); - #pragma omp task if (colors > 8000) box->max_error = box_max_error(achv, box); } @@ -325,23 +325,35 @@ static void box_init(struct box *box, const hist_item *achv, const unsigned int LIQ_PRIVATE colormap *mediancut(histogram *hist, unsigned int newcolors, const double target_mse, const double max_mse, void* (*malloc)(size_t), void (*free)(void*)) { hist_item *achv = hist->achv; - LIQ_ARRAY(struct box, bv, newcolors); - unsigned int boxes = 1; + struct box bv[newcolors+16]; + + assert(hist->boxes[0].begin == 0); + assert(hist->boxes[LIQ_MAXCLUSTER-1].end == hist->size); + + unsigned int boxes = 0; + for(int b=0; b < LIQ_MAXCLUSTER; b++) { + int begin = hist->boxes[b].begin; + int end = hist->boxes[b].end; + if (begin == end) { + continue; + } + + if (boxes >= newcolors/3) { + boxes = 0; + begin = 0; + end = hist->boxes[LIQ_MAXCLUSTER-1].end; + b = LIQ_MAXCLUSTER; + } - /* - ** Set up the initial box. - */ - #pragma omp parallel - #pragma omp single - { double sum = 0; - for(unsigned int i=0; i < hist->size; i++) { + for(int i=begin; i < end; i++) { sum += achv[i].adjusted_weight; } - #pragma omp taskgroup - { - box_init(&bv[0], achv, 0, hist->size, sum); - } + box_init(&bv[boxes], achv, begin, end-begin, sum); + boxes++; + } + + assert(boxes < newcolors); /* @@ -372,12 +384,11 @@ LIQ_PRIVATE colormap *mediancut(histogram *hist, unsigned int newcolors, const d */ const double halfvar = prepare_sort(&bv[bi], achv); - double lowervar=0; // hist_item_sort_halfvar sorts and sums lowervar at the same time // returns item to break at …minus one, which does smell like an off-by-one error. - hist_item *break_p = hist_item_sort_halfvar(&achv[indx], clrs, &lowervar, halfvar); - unsigned int break_at = MIN(clrs-1, break_p - &achv[indx] + 1); + unsigned int break_at = hist_item_sort_halfvar(&achv[indx], clrs, halfvar); + break_at = MIN(clrs-1, break_at + 1); /* ** Split the box. @@ -386,11 +397,8 @@ LIQ_PRIVATE colormap *mediancut(histogram *hist, unsigned int newcolors, const d double lowersum = 0; for(unsigned int i=0; i < break_at; i++) lowersum += achv[indx + i].adjusted_weight; - #pragma omp taskgroup - { - box_init(&bv[bi], achv, indx, break_at, lowersum); - box_init(&bv[boxes], achv, indx + break_at, clrs - break_at, sm - lowersum); - } + box_init(&bv[bi], achv, indx, break_at, lowersum); + box_init(&bv[boxes], achv, indx + break_at, clrs - break_at, sm - lowersum); ++boxes; @@ -398,7 +406,6 @@ LIQ_PRIVATE colormap *mediancut(histogram *hist, unsigned int newcolors, const d break; } } - } colormap *map = pam_colormap(boxes, malloc, free); set_colormap_from_boxes(map, bv, boxes, achv); diff --git a/mediancut.h b/mediancut.h index d97696c..9a4cb53 100644 --- a/mediancut.h +++ b/mediancut.h @@ -1,2 +1,6 @@ +#ifndef MEDIANCUT_H +#define MEDIANCUT_H LIQ_PRIVATE colormap *mediancut(histogram *hist, unsigned int newcolors, const double target_mse, const double max_mse, void* (*malloc)(size_t), void (*free)(void*)); + +#endif diff --git a/nearest.c b/nearest.c index aeb4dc1..7c8ee6a 100644 --- a/nearest.c +++ b/nearest.c @@ -19,15 +19,23 @@ typedef struct vp_sort_tmp { typedef struct vp_search_tmp { float distance; + float distance_squared; unsigned int idx; int exclude; } vp_search_tmp; +struct leaf { + f_pixel color; + unsigned int idx; +}; + typedef struct vp_node { struct vp_node *near, *far; f_pixel vantage_point; - float radius; - unsigned int idx; + float radius, radius_squared; + struct leaf *rest; + unsigned short idx; + unsigned short restcount; } vp_node; struct nearest_map { @@ -79,6 +87,7 @@ static vp_node *vp_create_node(mempoolptr *m, vp_sort_tmp indexes[], int num_ind .vantage_point = items[indexes[0].idx].acolor, .idx = indexes[0].idx, .radius = MAX_DIFF, + .radius_squared = MAX_DIFF, }; return node; } @@ -99,9 +108,19 @@ static vp_node *vp_create_node(mempoolptr *m, vp_sort_tmp indexes[], int num_ind .vantage_point = items[ref_idx].acolor, .idx = ref_idx, .radius = sqrtf(indexes[half_idx].distance_squared), + .radius_squared = indexes[half_idx].distance_squared, }; - node->near = vp_create_node(m, indexes, half_idx, items); - node->far = vp_create_node(m, &indexes[half_idx], num_indexes - half_idx, items); + if (num_indexes < 7) { + node->rest = mempool_alloc(m, sizeof(node->rest[0]) * num_indexes, 0); + node->restcount = num_indexes; + for(int i=0; i < num_indexes; i++) { + node->rest[i].idx = indexes[i].idx; + node->rest[i].color = items[indexes[i].idx].acolor; + } + } else { + node->near = vp_create_node(m, indexes, half_idx, items); + node->far = vp_create_node(m, &indexes[half_idx], num_indexes - half_idx, items); + } return node; } @@ -126,10 +145,11 @@ LIQ_PRIVATE struct nearest_map *nearest_init(const colormap *map) { for(unsigned int i=0; i < map->colors; i++) { vp_search_tmp best = { .distance = MAX_DIFF, + .distance_squared = MAX_DIFF, .exclude = i, }; vp_search_node(root, &map->palette[i].acolor, &best); - handle->nearest_other_color_dist[i] = best.distance * best.distance / 4.0; // half of squared distance + handle->nearest_other_color_dist[i] = best.distance * best.distance / 4.f; // half of squared distance } return handle; @@ -137,15 +157,29 @@ LIQ_PRIVATE struct nearest_map *nearest_init(const colormap *map) { static void vp_search_node(const vp_node *node, const f_pixel *const needle, vp_search_tmp *const best_candidate) { do { - const float distance = sqrtf(colordifference(node->vantage_point, *needle)); + const float distance_squared = colordifference(node->vantage_point, *needle); + const float distance = sqrtf(distance_squared); - if (distance < best_candidate->distance && best_candidate->exclude != node->idx) { + if (distance_squared < best_candidate->distance_squared && best_candidate->exclude != node->idx) { best_candidate->distance = distance; + best_candidate->distance_squared = distance_squared; best_candidate->idx = node->idx; } + if (node->restcount) { + for(int i=0; i < node->restcount; i++) { + const float distance_squared = colordifference(node->rest[i].color, *needle); + if (distance_squared < best_candidate->distance_squared && best_candidate->exclude != node->rest[i].idx) { + best_candidate->distance = sqrtf(distance_squared); + best_candidate->distance_squared = distance_squared; + best_candidate->idx = node->rest[i].idx; + } + } + return; + } + // Recurse towards most likely candidate first to narrow best candidate's distance as soon as possible - if (distance < node->radius) { + if (distance_squared < node->radius_squared) { if (node->near) { vp_search_node(node->near, needle, best_candidate); } @@ -155,7 +189,7 @@ static void vp_search_node(const vp_node *node, const f_pixel *const needle, vp_ if (node->far && distance >= node->radius - best_candidate->distance) { node = node->far; // Fast tail recursion } else { - break; + return; } } else { if (node->far) { @@ -164,7 +198,7 @@ static void vp_search_node(const vp_node *node, const f_pixel *const needle, vp_ if (node->near && distance <= node->radius + best_candidate->distance) { node = node->near; // Fast tail recursion } else { - break; + return; } } } while(true); @@ -179,6 +213,7 @@ LIQ_PRIVATE unsigned int nearest_search(const struct nearest_map *handle, const vp_search_tmp best_candidate = { .distance = sqrtf(guess_diff), + .distance_squared = guess_diff, .idx = likely_colormap_index, .exclude = -1, }; diff --git a/nearest.h b/nearest.h index e20233b..10a0a2c 100644 --- a/nearest.h +++ b/nearest.h @@ -2,7 +2,13 @@ // nearest.h // pngquant // + +#ifndef NEAREST_H +#define NEAREST_H + struct nearest_map; LIQ_PRIVATE struct nearest_map *nearest_init(const colormap *palette); LIQ_PRIVATE unsigned int nearest_search(const struct nearest_map *map, const f_pixel *px, const int palette_index_guess, float *diff); LIQ_PRIVATE void nearest_free(struct nearest_map *map); + +#endif diff --git a/pam.c b/pam.c index 660f829..5d955e1 100644 --- a/pam.c +++ b/pam.c @@ -14,7 +14,7 @@ #include "pam.h" #include "mempool.h" -LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const rgba_pixel *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map) +LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const liq_color *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map) { const unsigned int ignorebits = acht->ignorebits; const unsigned int channel_mask = 255U>>ignorebits<> (8-ignorebits)); // fancier hashing algorithms didn't improve much @@ -52,13 +44,20 @@ LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const rgba } else { boost = 255; } + } else { + // "dirty alpha" has different RGBA values that end up being the same fully transparent color + px.l=0; hash=0; + + boost = 2000; + if (importance_map) { + importance_map++; + } } if (!pam_add_to_hash(acht, hash, boost, px, row, rows)) { return false; } } - } acht->cols = cols; acht->rows += rows; @@ -176,14 +175,18 @@ LIQ_PRIVATE struct acolorhash_table *pam_allocacolorhash(unsigned int maxcolors, return t; } -ALWAYS_INLINE static float pam_add_to_hist(const float *gamma_lut, hist_item *achv, unsigned int *j, const struct acolorhist_arr_item *entry, const float max_perceptual_weight) +ALWAYS_INLINE static float pam_add_to_hist(struct temp_hist_item achv[], unsigned int *j, const struct acolorhist_arr_item *entry, const float max_perceptual_weight, int counts[]) { - if (entry->perceptual_weight == 0) { + if (entry->perceptual_weight == 0 && *j > 0) { return 0; } - const float w = MIN(entry->perceptual_weight/128.f, max_perceptual_weight); - achv[*j].adjusted_weight = achv[*j].perceptual_weight = w; - achv[*j].acolor = rgba_to_f(gamma_lut, entry->color.rgba); + const liq_color px = entry->color.rgba; + achv[*j].color = px; + const short cluster = ((px.r>>7)<<3) | ((px.g>>7)<<2) | ((px.b>>7)<<1) | (px.a>>7); + counts[cluster]++; + achv[*j].cluster = cluster; + const float w = MIN(entry->perceptual_weight/170.f, max_perceptual_weight); + achv[*j].weight = w; *j += 1; return w; } @@ -200,8 +203,9 @@ LIQ_PRIVATE histogram *pam_acolorhashtoacolorhist(const struct acolorhash_table }; if (!hist->achv) return NULL; - float gamma_lut[256]; - to_f_set_gamma(gamma_lut, gamma); + /// Clusters form initial boxes for quantization, to ensure extreme colors are better represented + int counts[LIQ_MAXCLUSTER] = {}; + struct temp_hist_item *temp = malloc(MAX(1, acht->colors) * sizeof(temp[0])); /* Limit perceptual weight to 1/10th of the image surface area to prevent a single color from dominating all others. */ @@ -212,23 +216,47 @@ LIQ_PRIVATE histogram *pam_acolorhashtoacolorhist(const struct acolorhash_table for(unsigned int i=0; i < acht->hash_size; ++i) { const struct acolorhist_arr_head *const achl = &acht->buckets[i]; if (achl->used) { - total_weight += pam_add_to_hist(gamma_lut, hist->achv, &j, &achl->inline1, max_perceptual_weight); + total_weight += pam_add_to_hist(temp, &j, &achl->inline1, max_perceptual_weight, counts); if (achl->used > 1) { - total_weight += pam_add_to_hist(gamma_lut, hist->achv, &j, &achl->inline2, max_perceptual_weight); + total_weight += pam_add_to_hist(temp, &j, &achl->inline2, max_perceptual_weight, counts); for(unsigned int k=0; k < achl->used-2; k++) { - total_weight += pam_add_to_hist(gamma_lut, hist->achv, &j, &achl->other_items[k], max_perceptual_weight); + total_weight += pam_add_to_hist(temp, &j, &achl->other_items[k], max_perceptual_weight, counts); } } } } + hist->total_perceptual_weight = total_weight; + + int begin = 0; + for(int i=0; i < LIQ_MAXCLUSTER; i++) { + hist->boxes[i].begin = begin; + hist->boxes[i].end = begin; + begin = begin + counts[i]; + } + hist->size = j; hist->total_perceptual_weight = total_weight; + for(unsigned int k=0; k < hist->size; k++) { + hist->achv[k].tmp.likely_colormap_index = 0; + } if (!j) { + free(temp); pam_freeacolorhist(hist); return NULL; } + + float gamma_lut[256]; + to_f_set_gamma(gamma_lut, gamma); + for(int i=0; i < hist->size; i++) { + int j = hist->boxes[temp[i].cluster].end++; + hist->achv[j].acolor = rgba_to_f(gamma_lut, temp[i].color); + hist->achv[j].perceptual_weight = temp[i].weight; + hist->achv[j].adjusted_weight = temp[i].weight; + } + free(temp); + return hist; } @@ -246,7 +274,7 @@ LIQ_PRIVATE void pam_freeacolorhist(histogram *hist) hist->free(hist); } -LIQ_PRIVATE colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*)) +LIQ_PRIVATE LIQ_NONNULL colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*)) { assert(colors > 0 && colors < 65536); @@ -284,3 +312,40 @@ LIQ_PRIVATE void to_f_set_gamma(float gamma_lut[], const double gamma) } } + +/* fixed colors are always included in the palette, so it would be wasteful to duplicate them in palette from histogram */ +LIQ_PRIVATE LIQ_NONNULL void remove_fixed_colors_from_histogram(histogram *hist, const int fixed_colors_count, const f_pixel fixed_colors[], const float target_mse) +{ + const float max_difference = MAX(target_mse/2.f, 2.f/256.f/256.f); + if (fixed_colors_count) { + for(int j=0; j < hist->size; j++) { + for(unsigned int i=0; i < fixed_colors_count; i++) { + if (colordifference(hist->achv[j].acolor, fixed_colors[i]) < max_difference) { + hist->achv[j] = hist->achv[--hist->size]; // remove color from histogram by overwriting with the last entry + j--; break; // continue searching histogram + } + } + } + } +} + +LIQ_PRIVATE LIQ_NONNULL colormap *histogram_to_palette(const histogram *hist, void* (*malloc)(size_t), void (*free)(void*)) { + if (!hist->size) { + return NULL; + } + colormap *acolormap = pam_colormap(hist->size, malloc, free); + for(unsigned int i=0; i < hist->size; i++) { + acolormap->palette[i].acolor = hist->achv[i].acolor; + acolormap->palette[i].popularity = hist->achv[i].perceptual_weight; + } + return acolormap; +} + +LIQ_PRIVATE LIQ_NONNULL void hist_reset_colors(const histogram *hist, const unsigned int colors) { + // likely_colormap_index (used and set in kmeans_do_iteration) can't point to index outside colormap + if (colors < 256) for(unsigned int j=0; j < hist->size; j++) { + if (hist->achv[j].tmp.likely_colormap_index >= colors) { + hist->achv[j].tmp.likely_colormap_index = 0; // actual value doesn't matter, as the guess is out of date anyway + } + } +} diff --git a/pam.h b/pam.h index 2ca4327..4ab4e0d 100644 --- a/pam.h +++ b/pam.h @@ -16,6 +16,12 @@ #ifndef PAM_H #define PAM_H +// accidental debug assertions make color search much slower, +// so force assertions off if there's no explicit setting +#if !defined(NDEBUG) && !defined(DEBUG) +#define NDEBUG +#endif + #include #include #include @@ -83,45 +89,48 @@ /* from pam.h */ -typedef struct { - unsigned char r, g, b, a; -} rgba_pixel; - typedef struct { float a, r, g, b; } SSE_ALIGN f_pixel; -static const float internal_gamma = 0.5499f; +static const float internal_gamma = 0.57f; LIQ_PRIVATE void to_f_set_gamma(float gamma_lut[], const double gamma); +#define MIN_OPAQUE_A (1.f / 256.f * LIQ_WEIGHT_A) + +#define LIQ_WEIGHT_A 0.625f +#define LIQ_WEIGHT_R 0.5f +#define LIQ_WEIGHT_G 1.0f +#define LIQ_WEIGHT_B 0.45f +#define LIQ_WEIGHT_MSE 0.45 // fudge factor for compensating that colors aren't 0..1 range + /** Converts 8-bit color to internal gamma and premultiplied alpha. (premultiplied color space is much better for blending of semitransparent colors) */ -ALWAYS_INLINE static f_pixel rgba_to_f(const float gamma_lut[], const rgba_pixel px); -inline static f_pixel rgba_to_f(const float gamma_lut[], const rgba_pixel px) +ALWAYS_INLINE static f_pixel rgba_to_f(const float gamma_lut[], const liq_color px); +inline static f_pixel rgba_to_f(const float gamma_lut[], const liq_color px) { float a = px.a/255.f; return (f_pixel) { - .a = a, - .r = gamma_lut[px.r]*a, - .g = gamma_lut[px.g]*a, - .b = gamma_lut[px.b]*a, + .a = a * LIQ_WEIGHT_A, + .r = gamma_lut[px.r] * LIQ_WEIGHT_R * a, + .g = gamma_lut[px.g] * LIQ_WEIGHT_G * a, + .b = gamma_lut[px.b] * LIQ_WEIGHT_B * a, }; } -inline static rgba_pixel f_to_rgb(const float gamma, const f_pixel px) +inline static liq_color f_to_rgb(const float gamma, const f_pixel px) { - if (px.a < 1.f/256.f) { - return (rgba_pixel){0,0,0,0}; + if (px.a < MIN_OPAQUE_A) { + return (liq_color){0,0,0,0}; } - float r = px.r / px.a, - g = px.g / px.a, - b = px.b / px.a, - a = px.a; + float r = (LIQ_WEIGHT_A / LIQ_WEIGHT_R) * px.r / px.a, + g = (LIQ_WEIGHT_A / LIQ_WEIGHT_G) * px.g / px.a, + b = (LIQ_WEIGHT_A / LIQ_WEIGHT_B) * px.b / px.a; r = powf(r, gamma/internal_gamma); g = powf(g, gamma/internal_gamma); @@ -131,9 +140,9 @@ inline static rgba_pixel f_to_rgb(const float gamma, const f_pixel px) r *= 256.f; g *= 256.f; b *= 256.f; - a *= 256.f; + float a = (256.f / LIQ_WEIGHT_A) * px.a; - return (rgba_pixel){ + return (liq_color){ .r = r>=255.f ? 255 : r, .g = g>=255.f ? 255 : g, .b = b>=255.f ? 255 : b, @@ -141,12 +150,12 @@ inline static rgba_pixel f_to_rgb(const float gamma, const f_pixel px) }; } -ALWAYS_INLINE static double colordifference_ch(const double x, const double y, const double alphas); -inline static double colordifference_ch(const double x, const double y, const double alphas) +ALWAYS_INLINE static float colordifference_ch(const float x, const float y, const float alphas); +inline static float colordifference_ch(const float x, const float y, const float alphas) { // maximum of channel blended on white, and blended on black // premultiplied alpha and backgrounds 0/1 shorten the formula - const double black = x-y, white = black+alphas; + const float black = x-y, white = black+alphas; return MAX(black*black, white*white); } @@ -166,7 +175,7 @@ inline static float colordifference_stdc(const f_pixel px, const f_pixel py) // (px.rgb - px.a) - (py.rgb - py.a) // (px.rgb - py.rgb) + (py.a - px.a) - const double alphas = py.a-px.a; + const float alphas = py.a-px.a; return colordifference_ch(px.r, py.r, alphas) + colordifference_ch(px.g, py.g, alphas) + colordifference_ch(px.b, py.b, alphas); @@ -176,8 +185,17 @@ ALWAYS_INLINE static float colordifference(f_pixel px, f_pixel py); inline static float colordifference(f_pixel px, f_pixel py) { #if USE_SSE +#ifdef _MSC_VER + /* In MSVC we cannot use the align attribute in parameters. + * This is used a lot, so we just use an unaligned load. + * Also the compiler incorrectly inlines vpx and vpy without + * the volatile when optimization is applied for x86_64. */ + const volatile __m128 vpx = _mm_loadu_ps((const float*)&px); + const volatile __m128 vpy = _mm_loadu_ps((const float*)&py); +#else const __m128 vpx = _mm_load_ps((const float*)&px); const __m128 vpy = _mm_load_ps((const float*)&py); +#endif // y.a - x.a __m128 alphas = _mm_sub_ss(vpy, vpx); @@ -205,7 +223,7 @@ inline static float colordifference(f_pixel px, f_pixel py) /* from pamcmap.h */ union rgba_as_int { - rgba_pixel rgba; + liq_color rgba; unsigned int l; }; @@ -221,12 +239,25 @@ typedef struct { } tmp; } hist_item; +#define LIQ_MAXCLUSTER 16 + +struct temp_hist_item { + liq_color color; + float weight; + short cluster; +}; + +struct histogram_box { + int begin, end; +}; + typedef struct { hist_item *achv; void (*free)(void*); double total_perceptual_weight; unsigned int size; unsigned int ignorebits; + struct histogram_box boxes[LIQ_MAXCLUSTER]; } histogram; typedef struct { @@ -265,13 +296,17 @@ struct acolorhash_table { LIQ_PRIVATE void pam_freeacolorhash(struct acolorhash_table *acht); LIQ_PRIVATE struct acolorhash_table *pam_allocacolorhash(unsigned int maxcolors, unsigned int surface, unsigned int ignorebits, void* (*malloc)(size_t), void (*free)(void*)); LIQ_PRIVATE histogram *pam_acolorhashtoacolorhist(const struct acolorhash_table *acht, const double gamma, void* (*malloc)(size_t), void (*free)(void*)); -LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const rgba_pixel *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map); +LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const liq_color *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map); LIQ_PRIVATE bool pam_add_to_hash(struct acolorhash_table *acht, unsigned int hash, unsigned int boost, union rgba_as_int px, unsigned int row, unsigned int rows); LIQ_PRIVATE void pam_freeacolorhist(histogram *h); -LIQ_PRIVATE colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*)); -LIQ_PRIVATE colormap *pam_duplicate_colormap(colormap *map); +LIQ_PRIVATE colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*)) LIQ_NONNULL; +LIQ_PRIVATE colormap *pam_duplicate_colormap(colormap *map) LIQ_NONNULL; LIQ_PRIVATE void pam_freecolormap(colormap *c); +LIQ_PRIVATE void remove_fixed_colors_from_histogram(histogram *hist, const int fixed_colors_count, const f_pixel fixed_colors[], const float target_mse) LIQ_NONNULL; +LIQ_PRIVATE colormap *histogram_to_palette(const histogram *hist, void* (*malloc)(size_t), void (*free)(void*)) LIQ_NONNULL; +LIQ_PRIVATE void hist_reset_colors(const histogram *hist, const unsigned int colors) LIQ_NONNULL; + #endif diff --git a/remap.c b/remap.c new file mode 100644 index 0000000..4495810 --- /dev/null +++ b/remap.c @@ -0,0 +1,300 @@ +#include +#include + +#include "libimagequant.h" +#include "pam.h" +#include "libimagequant_private.h" + +#include "nearest.h" +#include "kmeans.h" + +LIQ_PRIVATE LIQ_NONNULL float remap_to_palette(liq_image *const input_image, unsigned char *const *const output_pixels, colormap *const map) +{ + const int rows = input_image->height; + const unsigned int cols = input_image->width; + double remapping_error=0; + + if (!liq_image_get_row_f_init(input_image)) { + return -1; + } + if (input_image->background && !liq_image_get_row_f_init(input_image->background)) { + return -1; + } + + const colormap_item *acolormap = map->palette; + + struct nearest_map *const n = nearest_init(map); + liq_image *background = input_image->background; + const int transparent_index = background ? nearest_search(n, &(f_pixel){0,0,0,0}, 0, NULL) : -1; + if (background && acolormap[transparent_index].acolor.a > 1.f/256.f) { + // palette unsuitable for using the bg + background = NULL; + } + + + const unsigned int max_threads = omp_get_max_threads(); + LIQ_ARRAY(kmeans_state, average_color, (KMEANS_CACHE_LINE_GAP+map->colors) * max_threads); + kmeans_init(map, max_threads, average_color); + +#if __GNUC__ >= 9 || __clang__ + #pragma omp parallel for if (rows*cols > 3000) \ + schedule(static) default(none) shared(background,acolormap,average_color,cols,input_image,map,n,output_pixels,rows,transparent_index) reduction(+:remapping_error) +#endif + for(int row = 0; row < rows; ++row) { + const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row); + const f_pixel *const bg_pixels = background && acolormap[transparent_index].acolor.a < MIN_OPAQUE_A ? liq_image_get_row_f(background, row) : NULL; + + unsigned int last_match=0; + for(unsigned int col = 0; col < cols; ++col) { + float diff; + last_match = nearest_search(n, &row_pixels[col], last_match, &diff); + if (bg_pixels) { + float bg_diff = colordifference(bg_pixels[col], acolormap[last_match].acolor); + if (bg_diff <= diff) { + diff = bg_diff; + last_match = transparent_index; + } + } + output_pixels[row][col] = last_match; + + remapping_error += diff; + if (last_match != transparent_index) { + kmeans_update_color(row_pixels[col], 1.0, map, last_match, omp_get_thread_num(), average_color); + } + } + } + + kmeans_finalize(map, max_threads, average_color); + + nearest_free(n); + + return remapping_error / (input_image->width * input_image->height); +} + +inline static f_pixel get_dithered_pixel(const float dither_level, const float max_dither_error, const f_pixel thiserr, const f_pixel px) +{ + /* Use Floyd-Steinberg errors to adjust actual color. */ + const float sr = thiserr.r * dither_level, + sg = thiserr.g * dither_level, + sb = thiserr.b * dither_level, + sa = thiserr.a * dither_level; + + float ratio = 1.0; + const float max_overflow = 1.1f; + const float max_underflow = -0.1f; + + // allowing some overflow prevents undithered bands caused by clamping of all channels + if (px.r + sr > max_overflow) ratio = MIN(ratio, (max_overflow -px.r)/sr); + else { if (px.r + sr < max_underflow) ratio = MIN(ratio, (max_underflow-px.r)/sr); } + if (px.g + sg > max_overflow) ratio = MIN(ratio, (max_overflow -px.g)/sg); + else { if (px.g + sg < max_underflow) ratio = MIN(ratio, (max_underflow-px.g)/sg); } + if (px.b + sb > max_overflow) ratio = MIN(ratio, (max_overflow -px.b)/sb); + else { if (px.b + sb < max_underflow) ratio = MIN(ratio, (max_underflow-px.b)/sb); } + + float a = px.a + sa; + if (a > 1.f) { a = 1.f; } + else if (a < 0) { a = 0; } + + // If dithering error is crazy high, don't propagate it that much + // This prevents crazy geen pixels popping out of the blue (or red or black! ;) + const float dither_error = sr*sr + sg*sg + sb*sb + sa*sa; + if (dither_error > max_dither_error) { + ratio *= 0.8f; + } else if (dither_error < 2.f/256.f/256.f) { + // don't dither areas that don't have noticeable error — makes file smaller + return px; + } + + return (f_pixel) { + .r=px.r + sr * ratio, + .g=px.g + sg * ratio, + .b=px.b + sb * ratio, + .a=a, + }; +} + +/** + Uses edge/noise map to apply dithering only to flat areas. Dithering on edges creates jagged lines, and noisy areas are "naturally" dithered. + + If output_image_is_remapped is true, only pixels noticeably changed by error diffusion will be written to output image. + */ +LIQ_PRIVATE LIQ_NONNULL bool remap_to_palette_floyd(liq_image *input_image, unsigned char *const output_pixels[], liq_remapping_result *quant, const float max_dither_error, const bool output_image_is_remapped) +{ + const int rows = input_image->height, cols = input_image->width; + const unsigned char *dither_map = quant->use_dither_map ? (input_image->dither_map ? input_image->dither_map : input_image->edges) : NULL; + + const colormap *map = quant->palette; + const colormap_item *acolormap = map->palette; + + if (!liq_image_get_row_f_init(input_image)) { + return false; + } + if (input_image->background && !liq_image_get_row_f_init(input_image->background)) { + return false; + } + + /* Initialize Floyd-Steinberg error vectors. */ + const size_t errwidth = cols+2; + f_pixel *restrict thiserr = input_image->malloc(errwidth * sizeof(thiserr[0]) * 2); // +2 saves from checking out of bounds access + if (!thiserr) return false; + f_pixel *restrict nexterr = thiserr + errwidth; + memset(thiserr, 0, errwidth * sizeof(thiserr[0])); + + bool ok = true; + struct nearest_map *const n = nearest_init(map); + liq_image *background = input_image->background; + const int transparent_index = background ? nearest_search(n, &(f_pixel){0,0,0,0}, 0, NULL) : -1; + if (background && acolormap[transparent_index].acolor.a > 1.f/256.f) { + // palette unsuitable for using the bg + background = NULL; + } + + // response to this value is non-linear and without it any value < 0.8 would give almost no dithering + float base_dithering_level = quant->dither_level; + base_dithering_level = 1.f - (1.f-base_dithering_level)*(1.f-base_dithering_level); + + if (dither_map) { + base_dithering_level *= 1.f/255.f; // convert byte to float + } + base_dithering_level *= 15.f/16.f; // prevent small errors from accumulating + + int fs_direction = 1; + unsigned int last_match=0; + for (int row = 0; row < rows; ++row) { + if (liq_remap_progress(quant, quant->progress_stage1 + row * (100.f - quant->progress_stage1) / rows)) { + ok = false; + break; + } + + memset(nexterr, 0, errwidth * sizeof(nexterr[0])); + + int col = (fs_direction > 0) ? 0 : (cols - 1); + const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row); + const f_pixel *const bg_pixels = background && acolormap[transparent_index].acolor.a < MIN_OPAQUE_A ? liq_image_get_row_f(background, row) : NULL; + int undithered_bg_used = 0; + + do { + float dither_level = base_dithering_level; + if (dither_map) { + dither_level *= dither_map[row*cols + col]; + } + + const f_pixel spx = get_dithered_pixel(dither_level, max_dither_error, thiserr[col + 1], row_pixels[col]); + + const unsigned int guessed_match = output_image_is_remapped ? output_pixels[row][col] : last_match; + float dither_diff; + last_match = nearest_search(n, &spx, guessed_match, &dither_diff); + f_pixel output_px = acolormap[last_match].acolor; + // this is for animgifs + if (bg_pixels) { + // if the background makes better match *with* dithering, it's a definitive win + float bg_for_dither_diff = colordifference(spx, bg_pixels[col]); + if (bg_for_dither_diff <= dither_diff) { + output_px = bg_pixels[col]; + last_match = transparent_index; + } else if (undithered_bg_used > 1) { + // the undithered fallback can cause artifacts when too many undithered pixels accumulate a big dithering error + // so periodically ignore undithered fallback to prevent that + undithered_bg_used = 0; + } else { + // if dithering is not applied, there's a high risk of creating artifacts (flat areas, error accumulating badly), + // OTOH poor dithering disturbs static backgrounds and creates oscilalting frames that break backgrounds + // back and forth in two differently bad ways + float max_diff = colordifference(row_pixels[col], bg_pixels[col]); + float dithered_diff = colordifference(row_pixels[col], output_px); + // if dithering is worse than natural difference between frames + // (this rule dithers moving areas, but does not dither static areas) + if (dithered_diff > max_diff) { + // then see if an undithered color is closer to the ideal + float undithered_diff = colordifference(row_pixels[col], acolormap[guessed_match].acolor); + if (undithered_diff < max_diff) { + undithered_bg_used++; + output_px = acolormap[guessed_match].acolor; + last_match = guessed_match; + } + } + } + } + + output_pixels[row][col] = last_match; + + f_pixel err = { + .r = (spx.r - output_px.r), + .g = (spx.g - output_px.g), + .b = (spx.b - output_px.b), + .a = (spx.a - output_px.a), + }; + + // If dithering error is crazy high, don't propagate it that much + // This prevents crazy geen pixels popping out of the blue (or red or black! ;) + if (err.r*err.r + err.g*err.g + err.b*err.b + err.a*err.a > max_dither_error) { + err.r *= 0.75f; + err.g *= 0.75f; + err.b *= 0.75f; + err.a *= 0.75f; + } + + /* Propagate Floyd-Steinberg error terms. */ + if (fs_direction > 0) { + thiserr[col + 2].a += err.a * (7.f/16.f); + thiserr[col + 2].r += err.r * (7.f/16.f); + thiserr[col + 2].g += err.g * (7.f/16.f); + thiserr[col + 2].b += err.b * (7.f/16.f); + + nexterr[col + 2].a = err.a * (1.f/16.f); + nexterr[col + 2].r = err.r * (1.f/16.f); + nexterr[col + 2].g = err.g * (1.f/16.f); + nexterr[col + 2].b = err.b * (1.f/16.f); + + nexterr[col + 1].a += err.a * (5.f/16.f); + nexterr[col + 1].r += err.r * (5.f/16.f); + nexterr[col + 1].g += err.g * (5.f/16.f); + nexterr[col + 1].b += err.b * (5.f/16.f); + + nexterr[col ].a += err.a * (3.f/16.f); + nexterr[col ].r += err.r * (3.f/16.f); + nexterr[col ].g += err.g * (3.f/16.f); + nexterr[col ].b += err.b * (3.f/16.f); + + } else { + thiserr[col ].a += err.a * (7.f/16.f); + thiserr[col ].r += err.r * (7.f/16.f); + thiserr[col ].g += err.g * (7.f/16.f); + thiserr[col ].b += err.b * (7.f/16.f); + + nexterr[col ].a = err.a * (1.f/16.f); + nexterr[col ].r = err.r * (1.f/16.f); + nexterr[col ].g = err.g * (1.f/16.f); + nexterr[col ].b = err.b * (1.f/16.f); + + nexterr[col + 1].a += err.a * (5.f/16.f); + nexterr[col + 1].r += err.r * (5.f/16.f); + nexterr[col + 1].g += err.g * (5.f/16.f); + nexterr[col + 1].b += err.b * (5.f/16.f); + + nexterr[col + 2].a += err.a * (3.f/16.f); + nexterr[col + 2].r += err.r * (3.f/16.f); + nexterr[col + 2].g += err.g * (3.f/16.f); + nexterr[col + 2].b += err.b * (3.f/16.f); + } + + // remapping is done in zig-zag + col += fs_direction; + if (fs_direction > 0) { + if (col >= cols) break; + } else { + if (col < 0) break; + } + } while(1); + + f_pixel *const temperr = thiserr; + thiserr = nexterr; + nexterr = temperr; + fs_direction = -fs_direction; + } + + input_image->free(MIN(thiserr, nexterr)); // MIN because pointers were swapped + nearest_free(n); + + return ok; +} diff --git a/remap.h b/remap.h new file mode 100644 index 0000000..59d509b --- /dev/null +++ b/remap.h @@ -0,0 +1,7 @@ +#ifndef REMAP_H +#define REMAP_H + +LIQ_PRIVATE float remap_to_palette(liq_image *const input_image, unsigned char *const *const output_pixels, colormap *const map) LIQ_NONNULL; +LIQ_PRIVATE bool remap_to_palette_floyd(liq_image *input_image, unsigned char *const output_pixels[], liq_remapping_result *quant, const float max_dither_error, const bool output_image_is_remapped) LIQ_NONNULL; + +#endif diff --git a/rust-api/.gitignore b/rust-api/.gitignore new file mode 100644 index 0000000..2c96eb1 --- /dev/null +++ b/rust-api/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/rust-api/COPYRIGHT b/rust-api/COPYRIGHT new file mode 100644 index 0000000..f247798 --- /dev/null +++ b/rust-api/COPYRIGHT @@ -0,0 +1,635 @@ +https://raw.githubusercontent.com/ImageOptim/libimagequant/master/COPYRIGHT + +libimagequant © 2009-2016 by Kornel Lesiński. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +© 1989, 1991 by Jef Poskanzer. +© 1997, 2000, 2002 by Greg Roelofs. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. This software is provided "as is" without express or +implied warranty. diff --git a/rust-api/Cargo.toml b/rust-api/Cargo.toml new file mode 100644 index 0000000..f28bd09 --- /dev/null +++ b/rust-api/Cargo.toml @@ -0,0 +1,29 @@ +[package] +categories = ["multimedia::images"] +description = "Convert 24/32-bit images to 8-bit palette with alpha channel.\nBindings for libimagequant that powers pngquant lossy PNG compressor.\n\nDual-licensed like pngquant. See https://pngquant.org for details." +documentation = "https://docs.rs/imagequant" +homepage = "https://pngquant.org/lib/" +include = ["src/*", "examples/*", "COPYRIGHT", "Cargo.toml", "README.md"] +keywords = ["quantization", "palette", "image", "pngquant", "compression"] +authors = [ "Kornel " ] +license = "GPL-3.0-or-later" +name = "imagequant" +readme = "README.md" +repository = "https://github.com/ImageOptim/libimagequant" +version = "3.2.0" +edition = "2018" + +[dependencies] +fallible_collections = "0.4.3" +imagequant-sys = { version = "3.1.2", path = "../" } +libc = "0.2.102" +rgb = "0.8.27" + +[features] +default = ["sse"] +sse = ["imagequant-sys/sse"] +openmp = ["imagequant-sys/openmp"] +openmp-static = ["openmp", "imagequant-sys/openmp-static"] + +[lib] +name = "imagequant" diff --git a/rust-api/README.md b/rust-api/README.md new file mode 100644 index 0000000..22e412a --- /dev/null +++ b/rust-api/README.md @@ -0,0 +1,15 @@ +# [libimagequant](https://pngquant.org/lib/) bindings for [Rust](https://www.rust-lang.org/) + +Imagequant library converts RGBA images to 8-bit indexed images with palette, *including* alpha component. +It's ideal for generating tiny PNG images (although [image I/O](https://github.com/kornelski/lodepng-rust) isn't handled by the library itself). + +This wrapper makes the library usable from Rust. + +Rust API closely follows the C API, but is slightly OO-ified: + + liq_set_dithering_level(result, 1.0); + ↓ + result.set_dithering_level(1.0); + +For more details see [libimagequant documentation](https://pngquant.org/lib/) and [Rust function reference](https://kornelski.github.io/libimagequant-rust/imagequant/). + diff --git a/rust-api/examples/basic.rs b/rust-api/examples/basic.rs new file mode 100644 index 0000000..7f26866 --- /dev/null +++ b/rust-api/examples/basic.rs @@ -0,0 +1,32 @@ +// Don't forget to add -L . (or whatever dir has .rlib) to rustc! + +fn main() { + // Image loading/saving is outside scope of this library + let width = 10usize; + let height = 10usize; + let fakebitmap = vec![imagequant::RGBA {r:0, g:0, b:0, a:0}; width * height]; + + // http://pngquant.org/lib/ + + // Configure the library + let mut liq = imagequant::new(); + liq.set_speed(5); + liq.set_quality(70, 99); + + // Describe the bitmap + let ref mut img = liq.new_image(&fakebitmap[..], width, height, 0.0).unwrap(); + + // The magic happens in quantize() + let mut res = match liq.quantize(img) { + Ok(res) => res, + Err(err) => panic!("Quantization failed, because: {:?}", err), + }; + + // Enable dithering for subsequent remappings + res.set_dithering_level(1.0); + + // You can reuse the result to generate several images with the same palette + let (palette, pixels) = res.remapped(img).unwrap(); + + println!("Done! Got palette {:?} and {} pixels with {}% quality", palette, pixels.len(), res.quantization_quality()); +} diff --git a/rust-api/src/lib.rs b/rust-api/src/lib.rs new file mode 100644 index 0000000..1ccc6d2 --- /dev/null +++ b/rust-api/src/lib.rs @@ -0,0 +1,850 @@ +//! https://pngquant.org/lib/ +//! +//! Converts RGBA images to 8-bit with alpha channel. +//! +//! This is based on imagequant library, which generates very high quality images. +//! +//! See `examples/` directory for example code. +#![doc(html_logo_url = "https://pngquant.org/pngquant-logo.png")] +#![warn(missing_docs)] + +pub use crate::ffi::liq_error; +pub use crate::ffi::liq_error::*; + +use fallible_collections::FallibleVec; +use imagequant_sys as ffi; +use std::ffi::CStr; +use std::fmt; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use std::mem; +use std::os::raw::{c_int, c_void, c_char}; +use std::ptr; +use std::ptr::NonNull; + +pub use rgb::RGBA8 as RGBA; + +/// Allocates all memory used by the library, like [`libc::malloc`]. +/// +/// Must return properly aligned memory (16-bytes on x86, pointer size on other architectures). +pub type MallocUnsafeFn = unsafe extern "C" fn(size: usize) -> *mut c_void; + +/// Frees all memory used by the library, like [`libc::free`]. +pub type FreeUnsafeFn = unsafe extern "C" fn(*mut c_void); + +/// 8-bit RGBA. This is the only color format used by the library. +pub type Color = ffi::liq_color; + +/// Number of pixels in a given color +/// +/// Used if you're building histogram manually. Otherwise see `add_image()` +pub type HistogramEntry = ffi::liq_histogram_entry; + +/// Print messages +pub type LogCallbackFn = Box; + +/// Result of [`ProgressCallbackFn`] +#[repr(C)] +pub enum ControlFlow { + /// Continue processing as normal + Continue = 1, + /// Abort processing and fail + Break = 0, +} + +/// Check progress and optionally abort +pub type ProgressCallbackFn = Box ControlFlow + Send>; + +/// Settings for the conversion process. Start here. +pub struct Attributes { + handle: NonNull, + malloc: MallocUnsafeFn, + free: FreeUnsafeFn, + log_callback: Option>, // Double boxed, because it's a fat ptr, and Attributes can be moved + progress_callback: Option>, +} + +/// Describes image dimensions for the library. +pub struct Image<'a> { + handle: NonNull, + /// Holds row pointers for images with stride + _marker: PhantomData<&'a [u8]>, +} + +/// Palette inside. +pub struct QuantizationResult { + handle: NonNull, +} + +/// Generate one shared palette for multiple images. +pub struct Histogram<'a> { + attr: &'a Attributes, + handle: NonNull, +} + +impl Drop for Attributes { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::liq_attr_destroy(self.handle.as_mut()); + } + } +} + +impl<'a> Drop for Image<'a> { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::liq_image_destroy(self.handle.as_mut()); + } + } +} + +impl Drop for QuantizationResult { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::liq_result_destroy(self.handle.as_mut()); + } + } +} + +impl<'a> Drop for Histogram<'a> { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::liq_histogram_destroy(self.handle.as_mut()); + } + } +} + +impl Clone for Attributes { + /// NB: it doesn't clone the log/progress callbacks! + #[inline] + fn clone(&self) -> Attributes { + unsafe { + let mut handle = NonNull::new(ffi::liq_attr_copy(self.handle.as_ref())).unwrap(); + if self.log_callback.is_some() { // can't be cloned + ffi::liq_set_log_callback(handle.as_mut(), None, ptr::null_mut()); + } + if self.progress_callback.is_some() { // can't be cloned + ffi::liq_attr_set_progress_callback(handle.as_mut(), None, ptr::null_mut()); + } + Attributes { + handle, + malloc: self.malloc, + free: self.free, + log_callback: None, + progress_callback: None, + } + } + } +} + +impl Default for Attributes { + #[inline(always)] + fn default() -> Attributes { + Attributes::new() + } +} + +impl Attributes { + /// New handle for library configuration + /// + /// See also `new_image()` + #[inline] + #[must_use] + pub fn new() -> Self { + let handle = unsafe { ffi::liq_attr_create() }; + Attributes { + handle: NonNull::new(handle).expect("SSE-capable CPU is required for this build."), + malloc: libc::malloc, + free: libc::free, + log_callback: None, + progress_callback: None, + } + } + + /// New handle for library configuration, with specified custom allocator for internal use. + /// + /// See also `new_image()` + /// + /// # Safety + /// + /// * `malloc` and `free` must behave according to their corresponding C specification. + /// * `malloc` must return properly aligned memory (16-bytes on x86, pointer-sized on other architectures). + #[inline] + #[must_use] + pub unsafe fn with_allocator(malloc: MallocUnsafeFn, free: FreeUnsafeFn) -> Self { + let handle = ffi::liq_attr_create_with_allocator(malloc, free); + Attributes { + handle: NonNull::new(handle).expect("SSE-capable CPU is required for this build."), + malloc, free, + log_callback: None, + progress_callback: None, + } + } + + /// It's better to use `set_quality()` + #[inline] + pub fn set_max_colors(&mut self, value: i32) -> liq_error { + unsafe { ffi::liq_set_max_colors(self.handle.as_mut(), value) } + } + + /// Number of least significant bits to ignore. + /// + /// Useful for generating palettes for VGA, 15-bit textures, or other retro platforms. + #[inline] + pub fn set_min_posterization(&mut self, value: i32) -> liq_error { + unsafe { ffi::liq_set_min_posterization(self.handle.as_mut(), value) } + } + + /// Returns number of bits of precision truncated + #[inline] + pub fn min_posterization(&mut self) -> i32 { + unsafe { ffi::liq_get_min_posterization(self.handle.as_ref()) } + } + + /// Range 0-100, roughly like JPEG. + /// + /// If minimum quality can't be met, quantization will fail. + /// + /// Default is min 0, max 100. + #[inline] + pub fn set_quality(&mut self, min: u32, max: u32) -> liq_error { + unsafe { ffi::liq_set_quality(self.handle.as_mut(), min as c_int, max as c_int) } + } + + /// Reads values set with `set_quality` + #[inline] + pub fn quality(&mut self) -> (u32, u32) { + unsafe { + (ffi::liq_get_min_quality(self.handle.as_ref()) as u32, + ffi::liq_get_max_quality(self.handle.as_ref()) as u32) + } + } + + /// 1-10. + /// + /// Faster speeds generate images of lower quality, but may be useful + /// for real-time generation of images. + #[inline] + pub fn set_speed(&mut self, value: i32) -> liq_error { + unsafe { ffi::liq_set_speed(self.handle.as_mut(), value) } + } + + /// Move transparent color to the last entry in the palette + /// + /// This is less efficient for PNG, but required by some broken software + #[inline] + pub fn set_last_index_transparent(&mut self, value: bool) { + unsafe { ffi::liq_set_last_index_transparent(self.handle.as_mut(), value as c_int) } + } + + /// Return currently set speed/quality trade-off setting + #[inline(always)] + #[must_use] + pub fn speed(&mut self) -> i32 { + unsafe { ffi::liq_get_speed(self.handle.as_ref()) } + } + + /// Return max number of colors set + #[inline(always)] + #[must_use] + pub fn max_colors(&mut self) -> i32 { + unsafe { ffi::liq_get_max_colors(self.handle.as_ref()) } + } + + /// Describe dimensions of a slice of RGBA pixels + /// + /// Use 0.0 for gamma if the image is sRGB (most images are). + #[inline] + pub fn new_image<'a>(&self, bitmap: &'a [RGBA], width: usize, height: usize, gamma: f64) -> Result, liq_error> { + Image::new(self, bitmap, width, height, gamma) + } + + /// Stride is in pixels. Allows defining regions of larger images or images with padding without copying. + #[inline] + pub fn new_image_stride<'a>(&self, bitmap: &'a [RGBA], width: usize, height: usize, stride: usize, gamma: f64) -> Result, liq_error> { + Image::new_stride(self, bitmap, width, height, stride, gamma) + } + + /// Like `new_image_stride`, but makes a copy of the pixels + #[inline] + pub fn new_image_stride_copy(&self, bitmap: &[RGBA], width: usize, height: usize, stride: usize, gamma: f64) -> Result, liq_error> { + Image::new_stride_copy(self, bitmap, width, height, stride, gamma) + } + + /// Create new histogram + /// + /// Use to make one palette suitable for many images + #[inline(always)] + #[must_use] + pub fn new_histogram(&self) -> Histogram<'_> { + Histogram::new(&self) + } + + /// Generate palette for the image + pub fn quantize(&mut self, image: &Image<'_>) -> Result { + unsafe { + let mut h = ptr::null_mut(); + match ffi::liq_image_quantize(image.handle.as_ref(), self.handle.as_ref(), &mut h) { + liq_error::LIQ_OK if !h.is_null() => Ok(QuantizationResult { handle: NonNull::new_unchecked(h) }), + err => Err(err), + } + } + } + + /// Set callback function to be called every time the library wants to print a message. + /// + /// To share data with the callback, use `Arc` or `Atomic*` types and `move ||` closures. + #[inline(always)] + pub fn set_log_callback(&mut self, callback: F) { + self._set_log_callback(Box::new(callback)) + } + + /// Set callback function to be called every time the library makes a progress. + /// It can be used to cancel operation early. + /// + /// To share data with the callback, use `Arc` or `Atomic*` types and `move ||` closures. + #[inline(always)] + pub fn set_progress_callback ControlFlow + Send + 'static>(&mut self, callback: F) { + self._set_progress_callback(Box::new(callback)) + } + + fn _set_log_callback(&mut self, callback: LogCallbackFn) { + let mut log_callback = Box::new(callback); + let log_callback_ref: &mut LogCallbackFn = &mut *log_callback; + unsafe { + ffi::liq_set_log_callback(self.handle.as_mut(), Some(call_log_callback), log_callback_ref as *mut LogCallbackFn as *mut c_void); + } + self.log_callback = Some(log_callback); + } + + fn _set_progress_callback(&mut self, callback: ProgressCallbackFn) { + let mut progress_callback = Box::new(callback); + let progress_callback_ref: &mut ProgressCallbackFn = &mut *progress_callback; + unsafe { + ffi::liq_attr_set_progress_callback(self.handle.as_mut(), Some(call_progress_callback), progress_callback_ref as *mut ProgressCallbackFn as *mut c_void); + } + self.progress_callback = Some(progress_callback); + } +} + +extern "C" fn call_log_callback(_liq: &ffi::liq_attr, msg: *const c_char, user_data: *mut c_void) { + unsafe { + let cb: &mut LogCallbackFn = match (user_data as *mut LogCallbackFn).as_mut() { + Some(cb) => cb, + None => return, + }; + match CStr::from_ptr(msg).to_str() { + Ok(msg) => cb(msg), + Err(_) => return, + }; + } +} + +extern "C" fn call_progress_callback(perc: f32, user_data: *mut c_void) -> c_int { + unsafe { + match (user_data as *mut ProgressCallbackFn).as_mut() { + Some(cb) => cb(perc) as _, + None => ControlFlow::Break as _, + } + } +} + +/// Start here: creates new handle for library configuration +#[inline(always)] +#[must_use] +pub fn new() -> Attributes { + Attributes::new() +} + +impl<'a> Histogram<'a> { + /// Creates histogram object that will be used to collect color statistics from multiple images. + /// + /// All options should be set on `attr` before the histogram object is created. Options changed later may not have effect. + #[inline] + #[must_use] + pub fn new(attr: &'a Attributes) -> Self { + Histogram { + attr, + handle: unsafe { NonNull::new(ffi::liq_histogram_create(attr.handle.as_ref())).unwrap() }, + } + } + + /// "Learns" colors from the image, which will be later used to generate the palette. + /// + /// Fixed colors added to the image are also added to the histogram. If total number of fixed colors exceeds 256, this function will fail with `LIQ_BUFFER_TOO_SMALL`. + #[inline] + pub fn add_image(&mut self, image: &mut Image<'_>) -> liq_error { + unsafe { ffi::liq_histogram_add_image(self.handle.as_mut(), self.attr.handle.as_ref(), image.handle.as_mut()) } + } + + /// Alternative to `add_image()`. Intead of counting colors in an image, it directly takes an array of colors and their counts. + /// + /// This function is only useful if you already have a histogram of the image from another source. + #[inline] + pub fn add_colors(&mut self, colors: &[HistogramEntry], gamma: f64) -> liq_error { + unsafe { + ffi::liq_histogram_add_colors(self.handle.as_mut(), self.attr.handle.as_ref(), colors.as_ptr(), colors.len() as c_int, gamma) + } + } + + /// Generate palette for all images/colors added to the histogram. + /// + /// Palette generated using this function won't be improved during remapping. + /// If you're generating palette for only one image, it's better not to use the `Histogram`. + #[inline] + pub fn quantize(&mut self) -> Result { + unsafe { + let mut h = ptr::null_mut(); + match ffi::liq_histogram_quantize(self.handle.as_ref(), self.attr.handle.as_ref(), &mut h) { + liq_error::LIQ_OK if !h.is_null() => Ok(QuantizationResult { handle: NonNull::new_unchecked(h) }), + err => Err(err), + } + } + } +} + +/// Generate image row on the fly +/// +/// `output_row` is an array `width` RGBA elements wide. +/// `y` is the row (0-indexed) to write to the `output_row` +/// `user_data` is the data given to `Image::new_unsafe_fn()` +pub type ConvertRowUnsafeFn = unsafe extern "C" fn(output_row: *mut Color, y: c_int, width: c_int, user_data: *mut UserData); + +impl<'bitmap> Image<'bitmap> { + /// Describe dimensions of a slice of RGBA pixels. + /// + /// `bitmap` must be either `&[u8]` or a slice with one element per pixel (`&[RGBA]`). + /// + /// Use `0.` for gamma if the image is sRGB (most images are). + #[inline(always)] + pub fn new(attr: &Attributes, bitmap: &'bitmap [RGBA], width: usize, height: usize, gamma: f64) -> Result { + Self::new_stride(attr, bitmap, width, height, width, gamma) + } + + /// Generate rows on demand using a callback function. + /// + /// The callback function must be cheap (e.g. just byte-swap pixels). + /// It will be called multiple times per row. May be called in any order from any thread. + /// + /// The user data must be compatible with a primitive pointer + /// (i.e. not a slice, not a Trait object. `Box` it if you must). + #[inline] + pub fn new_unsafe_fn(attr: &Attributes, convert_row_fn: ConvertRowUnsafeFn, user_data: *mut CustomData, width: usize, height: usize, gamma: f64) -> Result { + let handle = NonNull::new(unsafe { + ffi::liq_image_create_custom(attr.handle.as_ref(), mem::transmute(convert_row_fn), user_data.cast(), width as c_int, height as c_int, gamma) + }).ok_or(LIQ_INVALID_POINTER)?; + Ok(Image { handle, _marker: PhantomData }) + } + + /// Stride is in pixels. Allows defining regions of larger images or images with padding without copying. + #[inline(always)] + pub fn new_stride(attr: &Attributes, bitmap: &'bitmap [RGBA], width: usize, height: usize, stride: usize, gamma: f64) -> Result { + // Type definition preserves the lifetime, so it's not unsafe + unsafe { Self::new_stride_internal(attr, bitmap, width, height, stride, gamma, false) } + } + + /// Create new image by copying `bitmap` to an internal buffer, so that it makes a self-contained type. + #[inline(always)] + pub fn new_stride_copy(attr: &Attributes, bitmap: &[RGBA], width: usize, height: usize, stride: usize, gamma: f64) -> Result, liq_error> { + // copy guarantees the image doesn't reference the bitmap any more + unsafe { Self::new_stride_internal(attr, bitmap, width, height, stride, gamma, true) } + } + + unsafe fn new_stride_internal<'varies>(attr: &Attributes, bitmap: &[RGBA], width: usize, height: usize, stride: usize, gamma: f64, copy: bool) -> Result, liq_error> { + if bitmap.len() < (stride * height + width - stride) { + eprintln!("Buffer length is {} bytes, which is not enough for {}×{}×4 RGBA bytes", bitmap.len()*4, stride, height); + return Err(LIQ_BUFFER_TOO_SMALL); + } + let (bitmap, ownership) = if copy { + let copied = (attr.malloc)(4 * bitmap.len()) as *mut RGBA; + ptr::copy_nonoverlapping(bitmap.as_ptr(), copied, bitmap.len()); + (copied as *const _, ffi::liq_ownership::LIQ_OWN_ROWS | ffi::liq_ownership::LIQ_OWN_PIXELS) + } else { + (bitmap.as_ptr(), ffi::liq_ownership::LIQ_OWN_ROWS) + }; + let rows = Self::malloc_image_rows(bitmap, stride, height, attr.malloc); + let h = NonNull::new(ffi::liq_image_create_rgba_rows(attr.handle.as_ref(), rows, width as c_int, height as c_int, gamma)); + let img = match h { + None => { + (attr.free)(rows.cast()); + return Err(LIQ_INVALID_POINTER); + } + Some(h) => { + Image { + handle: h, + _marker: PhantomData, + } + } + }; + match ffi::liq_image_set_memory_ownership(img.handle.as_ref(), ownership) { + LIQ_OK => Ok(img), + err => { + drop(img); + (attr.free)(rows.cast()); + Err(err) + }, + } + } + + /// For arbitrary stride libimagequant requires rows. It's most convenient if they're allocated using libc, + /// so they can be owned and freed automatically by the C library. + unsafe fn malloc_image_rows(bitmap: *const RGBA, stride: usize, height: usize, malloc: MallocUnsafeFn) -> *mut *const u8 { + let mut byte_ptr = bitmap as *const u8; + let stride_bytes = stride * 4; + let rows = malloc(mem::size_of::<*const u8>() * height) as *mut *const u8; + for y in 0..height { + *rows.add(y) = byte_ptr; + byte_ptr = byte_ptr.add(stride_bytes); + } + rows + } + + /// Width of the image in pixels + #[inline] + #[must_use] + pub fn width(&self) -> usize { + unsafe { ffi::liq_image_get_width(self.handle.as_ref()) as usize } + } + + /// Height of the image in pixels + #[inline] + #[must_use] + pub fn height(&self) -> usize { + unsafe { ffi::liq_image_get_height(self.handle.as_ref()) as usize } + } + + /// Reserves a color in the output palette created from this image. It behaves as if the given color was used in the image and was very important. + /// + /// RGB values of liq_color are assumed to have the same gamma as the image. + /// + /// It must be called before the image is quantized. + /// + /// Returns error if more than 256 colors are added. If image is quantized to fewer colors than the number of fixed colors added, then excess fixed colors will be ignored. + #[inline] + pub fn add_fixed_color(&mut self, color: ffi::liq_color) -> liq_error { + unsafe { ffi::liq_image_add_fixed_color(self.handle.as_mut(), color) } + } + + /// Remap pixels assuming they will be displayed on this background. + /// + /// Pixels that match the background color will be made transparent if there's a fully transparent color available in the palette. + /// + /// The background image's pixels must outlive this image + #[inline] + pub fn set_background<'own, 'bg: 'own>(&'own mut self, background: Image<'bg>) -> Result<(), liq_error> { + unsafe { + ffi::liq_image_set_background(self.handle.as_mut(), background.into_raw()).ok() + } + } + + /// Set which pixels are more important (and more likely to get a palette entry) + /// + /// The map must be `width`×`height` pixels large. Higher numbers = more important. + #[inline] + pub fn set_importance_map(&mut self, map: &[u8]) -> Result<(), liq_error> { + unsafe { + ffi::liq_image_set_importance_map(self.handle.as_mut(), map.as_ptr() as *mut _, map.len(), ffi::liq_ownership::LIQ_COPY_PIXELS).ok() + } + } + + #[inline] + fn into_raw(self) -> *mut ffi::liq_image { + let handle = self.handle; + mem::forget(self); + handle.as_ptr() + } +} + +impl QuantizationResult { + /// Set to 1.0 to get nice smooth image + #[inline] + pub fn set_dithering_level(&mut self, value: f32) -> liq_error { + unsafe { ffi::liq_set_dithering_level(self.handle.as_mut(), value) } + } + + /// The default is sRGB gamma (~1/2.2) + #[inline] + pub fn set_output_gamma(&mut self, value: f64) -> liq_error { + unsafe { ffi::liq_set_output_gamma(self.handle.as_mut(), value) } + } + + /// Approximate gamma correction value used for the output + /// + /// Colors are converted from input gamma to this gamma + #[inline] + #[must_use] + pub fn output_gamma(&mut self) -> f64 { + unsafe { ffi::liq_get_output_gamma(self.handle.as_ref()) } + } + + /// Number 0-100 guessing how nice the input image will look if remapped to this palette + #[inline] + #[must_use] + pub fn quantization_quality(&self) -> i32 { + unsafe { ffi::liq_get_quantization_quality(self.handle.as_ref()) as i32 } + } + + /// Approximate mean square error of the palette + #[inline] + #[must_use] + pub fn quantization_error(&self) -> Option { + match unsafe { ffi::liq_get_quantization_error(self.handle.as_ref()) } { + x if x < 0. => None, + x => Some(x), + } + } + + /// Final palette + /// + /// It's slighly better if you get palette from the `remapped()` call instead + #[must_use] + pub fn palette(&mut self) -> Vec { + let pal = self.palette_ref(); + let mut out: Vec = FallibleVec::try_with_capacity(pal.len()).unwrap(); + out.extend_from_slice(pal); + out + } + + /// Final palette (as a temporary slice) + /// + /// It's slighly better if you get palette from the `remapped()` call instead + /// + /// Use when ownership of the palette colors is not needed + #[inline] + pub fn palette_ref(&mut self) -> &[Color] { + unsafe { + let pal = &*ffi::liq_get_palette(self.handle.as_mut()); + std::slice::from_raw_parts(pal.entries.as_ptr(), (pal.count as usize).min(pal.entries.len())) + } + } + + /// Remap image into a `Vec` + /// + /// Returns the palette and a 1-byte-per-pixel uncompressed bitmap + pub fn remapped(&mut self, image: &mut Image<'_>) -> Result<(Vec, Vec), liq_error> { + let len = image.width() * image.height(); + // Capacity is essential here, as it creates uninitialized buffer + unsafe { + let mut buf: Vec = FallibleVec::try_with_capacity(len).map_err(|_| liq_error::LIQ_OUT_OF_MEMORY)?; + let uninit_slice = std::slice::from_raw_parts_mut(buf.as_ptr() as *mut MaybeUninit, buf.capacity()); + self.remap_into(image, uninit_slice)?; + buf.set_len(uninit_slice.len()); + Ok((self.palette(), buf)) + } + } + + /// Remap image into an existing buffer. + /// + /// This is a low-level call for use when existing memory has to be reused. Use `remapped()` if possible. + /// + /// Writes 1-byte-per-pixel uncompressed bitmap into the pre-allocated buffer. + /// + /// You should call `palette()` or `palette_ref()` _after_ this call, but not before it, + /// because remapping changes the palette. + #[inline] + pub fn remap_into(&mut self, image: &mut Image<'_>, output_buf: &mut [MaybeUninit]) -> Result<(), liq_error> { + unsafe { + match ffi::liq_write_remapped_image(self.handle.as_mut(), image.handle.as_mut(), output_buf.as_mut_ptr().cast(), output_buf.len()) { + LIQ_OK => Ok(()), + err => Err(err), + } + } + } +} + +impl fmt::Debug for QuantizationResult { + #[cold] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "QuantizationResult(q={})", self.quantization_quality()) + } +} + +unsafe impl Send for Attributes {} +unsafe impl Send for QuantizationResult {} +unsafe impl<'bitmap> Send for Image<'bitmap> {} +unsafe impl<'a> Send for Histogram<'a> {} + +#[test] +fn copy_img() { + let tmp = vec![RGBA::new(1,2,3,4); 10*100]; + let liq = Attributes::new(); + let _ = liq.new_image_stride_copy(&tmp, 10, 100, 10, 0.).unwrap(); +} + +#[test] +fn takes_rgba() { + let liq = Attributes::new(); + + use rgb::RGBA8 as RGBA; + let img = vec![RGBA {r:0, g:0, b:0, a:0}; 8]; + + + liq.new_image(&img, 1, 1, 0.0).unwrap(); + liq.new_image(&img, 4, 2, 0.0).unwrap(); + liq.new_image(&img, 8, 1, 0.0).unwrap(); + assert!(liq.new_image(&img, 9, 1, 0.0).is_err()); + assert!(liq.new_image(&img, 4, 3, 0.0).is_err()); +} + +#[test] +fn histogram() { + let attr = Attributes::new(); + let mut hist = attr.new_histogram(); + + let bitmap1 = vec![RGBA {r:0, g:0, b:0, a:0}; 1]; + let mut image1 = attr.new_image(&bitmap1[..], 1, 1, 0.0).unwrap(); + hist.add_image(&mut image1); + + let bitmap2 = vec![RGBA {r:255, g:255, b:255, a:255}; 1]; + let mut image2 = attr.new_image(&bitmap2[..], 1, 1, 0.0).unwrap(); + hist.add_image(&mut image2); + + hist.add_colors(&[HistogramEntry{ + color: Color::new(255,128,255,128), + count: 10, + }], 0.0); + + let mut res = hist.quantize().unwrap(); + let pal = res.palette(); + assert_eq!(3, pal.len()); +} + +#[test] +fn poke_it() { + let width = 10usize; + let height = 10usize; + let mut fakebitmap = vec![RGBA::new(255,255,255,255); width*height]; + + fakebitmap[0].r = 0x55; + fakebitmap[0].g = 0x66; + fakebitmap[0].b = 0x77; + + // Configure the library + let mut liq = Attributes::new(); + liq.set_speed(5); + liq.set_quality(70, 99); + liq.set_min_posterization(1); + assert_eq!(1, liq.min_posterization()); + liq.set_min_posterization(0); + + use std::sync::atomic::Ordering::SeqCst; + use std::sync::atomic::AtomicBool; + use std::sync::Arc; + + let log_called = Arc::new(AtomicBool::new(false)); + let log_called2 = log_called.clone(); + liq.set_log_callback(move |_msg| { + log_called2.store(true, SeqCst); + }); + + let prog_called = Arc::new(AtomicBool::new(false)); + let prog_called2 = prog_called.clone(); + liq.set_progress_callback(move |_perc| { + prog_called2.store(true, SeqCst); + ControlFlow::Continue + }); + + // Describe the bitmap + let ref mut img = liq.new_image(&fakebitmap[..], width, height, 0.0).unwrap(); + + // The magic happens in quantize() + let mut res = match liq.quantize(img) { + Ok(res) => res, + Err(err) => panic!("Quantization failed, because: {:?}", err), + }; + + // Enable dithering for subsequent remappings + res.set_dithering_level(1.0); + + // You can reuse the result to generate several images with the same palette + let (palette, pixels) = res.remapped(img).unwrap(); + + assert_eq!(width * height, pixels.len()); + assert_eq!(100, res.quantization_quality()); + assert_eq!(Color { r: 255, g: 255, b: 255, a: 255 }, palette[0]); + assert_eq!(Color { r: 0x55, g: 0x66, b: 0x77, a: 255 }, palette[1]); + + assert!(log_called.load(SeqCst)); + assert!(prog_called.load(SeqCst)); +} + +#[test] +fn set_importance_map() { + use crate::ffi::liq_color as RGBA; + let mut liq = new(); + let bitmap = &[RGBA::new(255, 0, 0, 255), RGBA::new(0u8, 0, 255, 255)]; + let ref mut img = liq.new_image(&bitmap[..], 2, 1, 0.).unwrap(); + let map = &[255, 0]; + img.set_importance_map(map).unwrap(); + let mut res = liq.quantize(img).unwrap(); + let pal = res.palette(); + assert_eq!(1, pal.len()); + assert_eq!(bitmap[0], pal[0]); +} + +#[test] +fn thread() { + let liq = Attributes::new(); + std::thread::spawn(move || { + let b = vec![RGBA::new(0,0,0,0);1]; + liq.new_image(&b, 1, 1, 0.).unwrap(); + }).join().unwrap(); +} + +#[test] +fn callback_test() { + let mut called = 0; + let mut res = { + let mut a = new(); + unsafe extern "C" fn get_row(output_row: *mut Color, y: c_int, width: c_int, user_data: *mut i32) { + assert!(y >= 0 && y < 5); + assert_eq!(123, width); + for i in 0..width as isize { + let n = i as u8; + *output_row.offset(i as isize) = Color::new(n,n,n,n); + } + *user_data += 1; + } + let mut img = Image::new_unsafe_fn(&a, get_row, &mut called, 123, 5, 0.).unwrap(); + a.quantize(&mut img).unwrap() + }; + assert!(called > 5 && called < 50); + assert_eq!(123, res.palette().len()); +} + +#[test] +fn custom_allocator_test() { + // SAFETY: This is all in one thread. + static mut ALLOC_COUNTR: usize = 0; + static mut FREE_COUNTR: usize = 0; + + unsafe extern "C" fn test_malloc(size: usize) -> *mut c_void { + ALLOC_COUNTR += 1; + libc::malloc(size) + } + + unsafe extern "C" fn test_free(ptr: *mut c_void) { + FREE_COUNTR += 1; + libc::free(ptr) + } + + let liq = unsafe { Attributes::with_allocator(test_malloc, test_free) }; + assert_eq!(unsafe { ALLOC_COUNTR }, 1); + assert_eq!(unsafe { FREE_COUNTR }, 0); + + let liq2 = liq.clone(); + assert_eq!(liq.malloc, liq2.malloc); + assert_eq!(liq.free, liq2.free); + + drop(liq); + assert_eq!(unsafe { ALLOC_COUNTR }, 2); + assert_eq!(unsafe { FREE_COUNTR }, 1); + + drop(liq2); + assert_eq!(unsafe { ALLOC_COUNTR }, 2); + assert_eq!(unsafe { FREE_COUNTR }, 2); +} diff --git a/rust/build.rs b/rust-sys/build.rs similarity index 77% rename from rust/build.rs rename to rust-sys/build.rs index ed7a781..35b9de3 100644 --- a/rust/build.rs +++ b/rust-sys/build.rs @@ -4,20 +4,23 @@ extern crate cc; use std::env; -use std::path::PathBuf; use std::fs::canonicalize; +use std::path::PathBuf; fn main() { let mut cc = cc::Build::new(); let compiler = cc.get_compiler(); cc.warnings(false); - if env::var("PROFILE").map(|p|p != "debug").unwrap_or(true) { + if env::var("PROFILE").map(|p| p != "debug").unwrap_or(true) { cc.define("NDEBUG", Some("1")); + } else { + cc.define("DEBUG", Some("1")); } if cfg!(feature = "openmp") { - cc.flag(&env::var("DEP_OPENMP_FLAG").unwrap()); + env::var("DEP_OPENMP_FLAG").expect("openmp-sys failed") + .split(" ").for_each(|f| { cc.flag(f); }); } let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("Needs CARGO_CFG_TARGET_ARCH"); @@ -38,6 +41,7 @@ fn main() { .file("msvc-dist/mediancut.c") .file("msvc-dist/mempool.c") .file("msvc-dist/pam.c") + .file("msvc-dist/remap.c") .file("msvc-dist/blur.c"); } else { // This is so that I don't forget to publish MSVC version as well @@ -54,8 +58,17 @@ fn main() { .file("mediancut.c") .file("mempool.c") .file("pam.c") + .file("remap.c") .file("blur.c"); } cc.compile("libimagequant.a"); + + if cfg!(feature = "openmp") { + if let Some(link) = env::var_os("DEP_OPENMP_CARGO_LINK_INSTRUCTIONS") { + for i in env::split_paths(&link) { + println!("cargo:{}", i.display()); + } + } + } } diff --git a/rust/libimagequant.rs b/rust-sys/libimagequant.rs similarity index 90% rename from rust/libimagequant.rs rename to rust-sys/libimagequant.rs index 6e195ea..c2aa625 100644 --- a/rust/libimagequant.rs +++ b/rust-sys/libimagequant.rs @@ -31,17 +31,14 @@ //! //! Note that "image" here means raw uncompressed pixels. If you have a compressed image file, such as PNG, you must use another library (e.g. lodepng) to decode it first. - #![allow(non_camel_case_types)] -extern crate rgb; #[cfg(feature = "openmp")] extern crate openmp_sys; -use std::os::raw::{c_int, c_uint, c_char, c_void}; use std::error; use std::fmt; -use std::error::Error; +use std::os::raw::{c_char, c_int, c_uint, c_void}; pub enum liq_attr {} pub enum liq_image {} @@ -63,12 +60,16 @@ pub enum liq_error { LIQ_UNSUPPORTED, } -#[repr(C)] -#[derive(Copy, Clone)] -pub enum liq_ownership { - LIQ_OWN_ROWS = 4, - LIQ_OWN_PIXELS = 8, - LIQ_COPY_PIXELS = 16, +bitflags::bitflags! { + #[repr(C)] + pub struct liq_ownership: c_int { + /// Moves ownership of the rows array. It will free it using `free()` or custom allocator. + const LIQ_OWN_ROWS = 4; + /// Moves ownership of the pixel data. It will free it using `free()` or custom allocator. + const LIQ_OWN_PIXELS = 8; + /// Makes a copy of the pixels, so the `liq_image` is not tied to pixel's lifetime. + const LIQ_COPY_PIXELS = 16; + } } #[repr(C)] @@ -84,25 +85,21 @@ pub struct liq_histogram_entry { pub count: c_uint, } -impl error::Error for liq_error { - fn description(&self) -> &str { - match *self { +impl error::Error for liq_error {} + +impl fmt::Display for liq_error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { liq_error::LIQ_OK => "OK", - liq_error::LIQ_QUALITY_TOO_LOW => "LIQ_QUALITY_TOO_LOW", + liq_error::LIQ_QUALITY_TOO_LOW => "QUALITY_TOO_LOW", liq_error::LIQ_VALUE_OUT_OF_RANGE => "VALUE_OUT_OF_RANGE", liq_error::LIQ_OUT_OF_MEMORY => "OUT_OF_MEMORY", - liq_error::LIQ_ABORTED => "LIQ_ABORTED", + liq_error::LIQ_ABORTED => "ABORTED", liq_error::LIQ_BITMAP_NOT_AVAILABLE => "BITMAP_NOT_AVAILABLE", liq_error::LIQ_BUFFER_TOO_SMALL => "BUFFER_TOO_SMALL", liq_error::LIQ_INVALID_POINTER => "INVALID_POINTER", - liq_error::LIQ_UNSUPPORTED => "LIQ_UNSUPPORTED", - } - } -} - -impl fmt::Display for liq_error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + liq_error::LIQ_UNSUPPORTED => "UNSUPPORTED", + }) } } @@ -142,12 +139,11 @@ impl liq_error { } } -pub type liq_log_callback_function = Option; -pub type liq_log_flush_callback_function = Option; +pub type liq_log_callback_function = Option; +pub type liq_log_flush_callback_function = Option; pub type liq_progress_callback_function = Option c_int>; pub type liq_image_get_rgba_row_callback = unsafe extern "C" fn(row_out: *mut liq_color, row: c_int, width: c_int, user_info: *mut c_void); -#[link(name="imagequant", kind="static")] extern "C" { /// Returns object that will hold initial settings (attributes) for the library. @@ -155,6 +151,7 @@ extern "C" { /// The object should be freed using `liq_attr_destroy()` after it's no longer needed. /// Returns `NULL` in the unlikely case that the library cannot run on the current machine (e.g. the library has been compiled for SSE-capable x86 CPU and run on VIA C3 CPU). pub fn liq_attr_create() -> *mut liq_attr; + pub fn liq_attr_create_with_allocator(malloc: unsafe extern "C" fn(usize) -> *mut c_void, free: unsafe extern "C" fn(*mut c_void)) -> *mut liq_attr; pub fn liq_attr_copy(orig: &liq_attr) -> *mut liq_attr; pub fn liq_attr_destroy(attr: &mut liq_attr); @@ -203,10 +200,10 @@ extern "C" { /// unsafe: It will crash if the owned memory wasn't allocated using `libc::malloc()` (or whatever allocator C side is using) pub fn liq_image_set_memory_ownership(image: &liq_image, own: liq_ownership) -> liq_error; - pub fn liq_set_log_callback(arg1: &mut liq_attr, arg2: liq_log_callback_function, user_info: *mut c_void); - pub fn liq_set_log_flush_callback(arg1: &mut liq_attr, arg2: liq_log_flush_callback_function, user_info: *mut c_void); - pub fn liq_attr_set_progress_callback(arg1: &mut liq_attr, arg2: liq_progress_callback_function, user_info: *mut c_void); - pub fn liq_result_set_progress_callback(arg1: &mut liq_result, arg2: liq_progress_callback_function, user_info: *mut c_void); + pub fn liq_set_log_callback(liq: &mut liq_attr, cb: liq_log_callback_function, user_info: *mut c_void); + pub fn liq_set_log_flush_callback(liq: &mut liq_attr, cb: liq_log_flush_callback_function, user_info: *mut c_void); + pub fn liq_attr_set_progress_callback(liq: &mut liq_attr, cb: liq_progress_callback_function, user_info: *mut c_void); + pub fn liq_result_set_progress_callback(arg1: &mut liq_result, cb: liq_progress_callback_function, user_info: *mut c_void); pub fn liq_image_create_custom(attr: &liq_attr, row_callback: liq_image_get_rgba_row_callback, user_info: *mut c_void, width: c_int, height: c_int, gamma: f64) -> *mut liq_image; /// Remap assuming the image will be always presented exactly on top of this background. /// @@ -291,6 +288,11 @@ extern "C" { pub fn liq_version() -> c_int; } +#[test] +fn ownership_bitflags() { + assert_eq!(4+16, (liq_ownership::LIQ_OWN_ROWS | liq_ownership::LIQ_COPY_PIXELS).bits()); +} + #[test] fn links_and_runs() { use std::ptr; diff --git a/tests/frame-6-a.png b/tests/frame-6-a.png new file mode 100644 index 0000000000000000000000000000000000000000..8539d898aa30684f685ad4b76766f3f813a5b7f8 GIT binary patch literal 89068 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 XEw`#Ir<8LW00000NkvXXu0mjf^S9j` literal 0 HcmV?d00001 diff --git a/tests/frame-6-bg.png b/tests/frame-6-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..8a97993c2b102004190493218afad71273829438 GIT binary patch literal 78886 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 z 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

9o3ps$4n#deCCZu(hlR2d+u6mPWNU9Sz)@`w9 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 literal 0 HcmV?d00001 diff --git a/tests/frame-6-pal.png b/tests/frame-6-pal.png new file mode 100644 index 0000000000000000000000000000000000000000..9aea8d6b938a3457bf10779ce63c4c3c70b51601 GIT binary patch literal 855 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 XEw`#Ir<8LW00000NkvXXu0mjf^S9j` literal 0 HcmV?d00001 diff --git a/tests/frame-7-bg.png b/tests/frame-7-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..8b1730c2a3005866aaaddec7a9448a21e96e9342 GIT binary patch literal 18629 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

!-t-L9md-Sn}F*X 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 literal 0 HcmV?d00001 diff --git a/tests/frame-7-pal.png b/tests/frame-7-pal.png new file mode 100644 index 0000000000000000000000000000000000000000..265e4df4197d33bce012cc8b82a07713a63a56d5 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~j!3HF+SL($BDIZT4$B>FSjE)TZ{xbsk4055X z|Nr^;kU>g2mO5)6N5cQf$tYcl-!^@4#>OqxML*oxuibP0l+XkK$K@x1 literal 0 HcmV?d00001 diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..6c10bcb --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,87 @@ +use rgb::ComponentMap; +use imagequant::*; + + +#[test] +fn remap_bg6() { + let fg1 = lodepng::decode32_file("tests/frame-6-a.png").unwrap(); + let bg1 = lodepng::decode32_file("tests/frame-6-bg.png").unwrap(); + let pal = lodepng::decode32_file("tests/frame-6-pal.png").unwrap(); + + let mut attr = new(); + let mut fg = attr.new_image_stride(&fg1.buffer, fg1.width, fg1.height, fg1.width, 0.).unwrap(); + let bg = attr.new_image_stride(&bg1.buffer, bg1.width, bg1.height, bg1.width, 0.).unwrap(); + fg.set_background(bg).unwrap(); + for c in &pal.buffer { + fg.add_fixed_color(*c).unwrap(); + } + attr.set_max_colors(pal.buffer.len() as _).unwrap(); + let mut res = attr.quantize(&mut fg).unwrap(); + res.set_dithering_level(1.).unwrap(); + let (pal, idx) = res.remapped(&mut fg).unwrap(); + + let buf: Vec<_> = idx.iter().zip(bg1.buffer.iter()).map(|(px, bg)| { + let palpx = pal[*px as usize]; + if palpx.a > 0 { + palpx + } else { + *bg + } + }).collect(); + lodepng::encode32_file("/tmp/testr2-r6.png", &buf, fg.width(), fg.height()).unwrap(); + + assert!(idx.iter().zip(bg1.buffer.iter()).map(|(px, bg)| { + let palpx = pal[*px as usize]; + if palpx.a > 0 { + palpx + } else { + *bg + } + }).zip(&fg1.buffer).all(|(px, fg)| { + let d = px.map(|c| c as i16) - fg.map(|c| c as i16); + d.map(|c| (c as i32).pow(2) as u32); + d.r + d.g + d.b + d.a < 120 + })); +} + +#[test] +fn remap_bg7() { + let fg1 = lodepng::decode32_file("tests/frame-7-a.png").unwrap(); + let bg1 = lodepng::decode32_file("tests/frame-7-bg.png").unwrap(); + let pal = lodepng::decode32_file("tests/frame-7-pal.png").unwrap(); + + let mut attr = new(); + let mut fg = attr.new_image_stride(&fg1.buffer, fg1.width, fg1.height, fg1.width, 0.).unwrap(); + let bg = attr.new_image_stride(&bg1.buffer, bg1.width, bg1.height, bg1.width, 0.).unwrap(); + fg.set_background(bg).unwrap(); + for c in &pal.buffer { + fg.add_fixed_color(*c).unwrap(); + } + attr.set_max_colors(pal.buffer.len() as _).unwrap(); + let mut res = attr.quantize(&mut fg).unwrap(); + res.set_dithering_level(0.).unwrap(); + let (pal, idx) = res.remapped(&mut fg).unwrap(); + + let buf: Vec<_> = idx.iter().zip(bg1.buffer.iter()).map(|(px, bg)| { + let palpx = pal[*px as usize]; + if palpx.a > 0 { + palpx + } else { + *bg + } + }).collect(); + lodepng::encode32_file("/tmp/testr2-r7.png", &buf, fg.width(), fg.height()).unwrap(); + + assert!(idx.iter().zip(bg1.buffer.iter()).map(|(px, bg)| { + let palpx = pal[*px as usize]; + if palpx.a > 0 { + palpx + } else { + *bg + } + }).zip(&fg1.buffer).all(|(px, fg)| { + let d = px.map(|c| c as i16) - fg.map(|c| c as i16); + d.map(|c| (c as i32).pow(2) as u32); + d.r + d.g + d.b + d.a < 160 + })); +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..3f8eb71 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +2.17.1