├── .gitignore ├── .travis.sh ├── .travis.yml ├── BUILD ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── WORKSPACE ├── appveyor.yml ├── external ├── png.BUILD └── zlib.BUILD ├── fuzz_target.cc ├── guetzli.make ├── guetzli.sln ├── guetzli.svg ├── guetzli.vcxproj ├── guetzli.vcxproj.filters ├── guetzli ├── butteraugli_comparator.cc ├── butteraugli_comparator.h ├── color_transform.h ├── comparator.h ├── dct_double.cc ├── dct_double.h ├── debug_print.cc ├── debug_print.h ├── entropy_encode.cc ├── entropy_encode.h ├── fast_log.h ├── fdct.cc ├── fdct.h ├── gamma_correct.cc ├── gamma_correct.h ├── guetzli.cc ├── idct.cc ├── idct.h ├── jpeg_bit_writer.h ├── jpeg_data.cc ├── jpeg_data.h ├── jpeg_data_decoder.cc ├── jpeg_data_decoder.h ├── jpeg_data_encoder.cc ├── jpeg_data_encoder.h ├── jpeg_data_reader.cc ├── jpeg_data_reader.h ├── jpeg_data_writer.cc ├── jpeg_data_writer.h ├── jpeg_error.h ├── jpeg_huffman_decode.cc ├── jpeg_huffman_decode.h ├── order.inc ├── output_image.cc ├── output_image.h ├── preprocess_downsample.cc ├── preprocess_downsample.h ├── processor.cc ├── processor.h ├── quality.cc ├── quality.h ├── quantize.cc ├── quantize.h ├── score.cc ├── score.h └── stats.h ├── guetzli_static.make ├── guetzli_static.vcxproj ├── guetzli_static.vcxproj.filters ├── premake5.lua ├── snapcraft.yaml ├── tests ├── bees.png ├── golden_checksums.txt ├── golden_test.sh ├── png_checksums.txt └── smoke_test.sh ├── third_party └── butteraugli │ ├── BUILD │ ├── LICENSE │ ├── README.md │ ├── WORKSPACE │ ├── butteraugli │ ├── Makefile │ ├── butteraugli.cc │ ├── butteraugli.h │ └── butteraugli_main.cc │ ├── jpeg.BUILD │ ├── png.BUILD │ └── zlib.BUILD └── tools └── guetzli-compare.py /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /bazel-* 4 | 5 | # Visual Studio 2015 cache/options directory 6 | .vs/ 7 | 8 | # Visual C++ cache files 9 | ipch/ 10 | *.aps 11 | *.ncb 12 | *.opendb 13 | *.opensdf 14 | *.sdf 15 | *.cachefile 16 | *.VC.db 17 | *.VC.VC.opendb 18 | -------------------------------------------------------------------------------- /.travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | case "$1" in 4 | "install") 5 | case "${TRAVIS_OS_NAME}" in 6 | "linux") 7 | ;; 8 | "osx") 9 | brew update 10 | brew install netpbm 11 | ;; 12 | esac 13 | case "${BUILD_SYSTEM}" in 14 | "bazel") 15 | case "${TRAVIS_OS_NAME}" in 16 | "linux") 17 | sudo apt-get remove openjdk-9-jdk oracle-java9-installer # Conflicts with Bazel. 18 | wget https://github.com/bazelbuild/bazel/releases/download/1.1.0/bazel_1.1.0-linux-x86_64.deb 19 | echo '138b47ffd54924e3c0264c65d31d3927803fb9025db4d5b18107df79ee3bda95 bazel_1.1.0-linux-x86_64.deb' | sha256sum -c --strict || exit 1 20 | sudo dpkg -i bazel_1.1.0-linux-x86_64.deb 21 | ;; 22 | "osx") 23 | brew cask install homebrew/cask-versions/adoptopenjdk8 24 | brew install bazel 25 | ;; 26 | esac 27 | ;; 28 | "make") 29 | ;; 30 | esac 31 | ;; 32 | "script") 33 | case "${BUILD_SYSTEM}" in 34 | "bazel") 35 | bazel build -c opt ...:all 36 | GUETZLI_BIN=bazel-bin/guetzli 37 | ;; 38 | "make") 39 | make 40 | GUETZLI_BIN=bin/Release/guetzli 41 | ;; 42 | esac 43 | tests/smoke_test.sh $GUETZLI_BIN 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: false 3 | matrix: 4 | include: 5 | - os: linux 6 | dist: trusty 7 | sudo: required 8 | env: BUILD_SYSTEM=bazel 9 | addons: 10 | apt: 11 | sources: 12 | - ubuntu-toolchain-r-test 13 | packages: 14 | - libjpeg-progs 15 | - netpbm # For pngtopnm in smoke_test.sh. 16 | - wget 17 | 18 | - os: osx 19 | env: BUILD_SYSTEM=bazel 20 | 21 | - os: linux 22 | dist: trusty 23 | env: BUILD_SYSTEM=make 24 | addons: 25 | apt: 26 | sources: 27 | - ubuntu-toolchain-r-test 28 | packages: 29 | - libjpeg-progs 30 | - libpng-dev 31 | - netpbm # For pngtopnm in smoke_test.sh. 32 | - pkg-config 33 | - wget 34 | 35 | - os: osx 36 | env: BUILD_SYSTEM=make 37 | 38 | 39 | install: 40 | - ./.travis.sh install 41 | script: 42 | - ./.travis.sh script 43 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | # Description: 2 | # Bazel build file for Guetzli. 3 | 4 | cc_library( 5 | name = "guetzli_lib", 6 | srcs = glob( 7 | [ 8 | "guetzli/*.h", 9 | "guetzli/*.cc", 10 | "guetzli/*.inc", 11 | ], 12 | exclude = ["guetzli/guetzli.cc"], 13 | ), 14 | copts = [ "-Wno-sign-compare" ], 15 | deps = [ 16 | "@butteraugli//:butteraugli_lib", 17 | ], 18 | ) 19 | 20 | cc_binary( 21 | name = "guetzli", 22 | srcs = ["guetzli/guetzli.cc"], 23 | deps = [ 24 | ":guetzli_lib", 25 | "@png_archive//:png", 26 | ], 27 | ) 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute bugfixes or non-output-modifying changes (e.g. speedups)? 2 | Great! First, read this page (including the small print at the end). Want to 3 | contribute changes that modify the generated JPEG file? Talk to us first. 4 | 5 | ### Before you contribute 6 | Before we can use your code, you must sign the 7 | [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) 8 | (CLA), which you can do online. The CLA is necessary mainly because you own the 9 | copyright to your changes, even after your contribution becomes part of our 10 | codebase, so we need your permission to use and distribute your code. We also 11 | need to be sure of various other things—for instance that you'll tell us if you 12 | know that your code infringes on other people's patents. You don't have to sign 13 | the CLA until after you've submitted your code for review and a member has 14 | approved it, but you must do it before we can put your code into our codebase. 15 | Before you start working on a larger contribution, you should get in touch with 16 | us first through the issue tracker with your idea so that we can help out and 17 | possibly guide you. Coordinating up front makes it much easier to avoid 18 | frustration later on. 19 | 20 | ### Code reviews 21 | All submissions, including submissions by project members, require review. We 22 | use Github pull requests for this purpose. 23 | 24 | ### The small print 25 | Contributions made by corporations are covered by a different agreement than 26 | the one above, the 27 | [Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # GNU Make workspace makefile autogenerated by Premake 2 | 3 | ifndef config 4 | config=release 5 | endif 6 | 7 | ifndef verbose 8 | SILENT = @ 9 | endif 10 | 11 | ifeq ($(config),release) 12 | guetzli_static_config = release 13 | guetzli_config = release 14 | endif 15 | ifeq ($(config),debug) 16 | guetzli_static_config = debug 17 | guetzli_config = debug 18 | endif 19 | 20 | PROJECTS := guetzli_static guetzli 21 | 22 | .PHONY: all clean help $(PROJECTS) 23 | 24 | all: $(PROJECTS) 25 | 26 | guetzli_static: 27 | ifneq (,$(guetzli_static_config)) 28 | @echo "==== Building guetzli_static ($(guetzli_static_config)) ====" 29 | @${MAKE} --no-print-directory -C . -f guetzli_static.make config=$(guetzli_static_config) 30 | endif 31 | 32 | guetzli: 33 | ifneq (,$(guetzli_config)) 34 | @echo "==== Building guetzli ($(guetzli_config)) ====" 35 | @${MAKE} --no-print-directory -C . -f guetzli.make config=$(guetzli_config) 36 | endif 37 | 38 | clean: 39 | @${MAKE} --no-print-directory -C . -f guetzli_static.make clean 40 | @${MAKE} --no-print-directory -C . -f guetzli.make clean 41 | 42 | help: 43 | @echo "Usage: make [config=name] [target]" 44 | @echo "" 45 | @echo "CONFIGURATIONS:" 46 | @echo " release" 47 | @echo " debug" 48 | @echo "" 49 | @echo "TARGETS:" 50 | @echo " all (default)" 51 | @echo " clean" 52 | @echo " guetzli_static" 53 | @echo " guetzli" 54 | @echo "" 55 | @echo "For more information, see http://industriousone.com/premake/quick-start" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Guetzli

2 | 3 | # Introduction 4 | 5 | Guetzli is a JPEG encoder that aims for excellent compression density at high 6 | visual quality. Guetzli-generated images are typically 20-30% smaller than 7 | images of equivalent quality generated by libjpeg. Guetzli generates only 8 | sequential (nonprogressive) JPEGs due to faster decompression speeds they offer. 9 | 10 | [![Build Status](https://travis-ci.org/google/guetzli.svg?branch=master)](https://travis-ci.org/google/guetzli) 11 | 12 | # Building 13 | 14 | ## On POSIX systems 15 | 16 | 1. Get a copy of the source code, either by cloning this repository, or by 17 | downloading an 18 | [archive](https://github.com/google/guetzli/archive/master.zip) and 19 | unpacking it. 20 | 2. Install [libpng](http://www.libpng.org/pub/png/libpng.html). 21 | If using your operating system 22 | package manager, install development versions of the packages if the 23 | distinction exists. 24 | * On Ubuntu, do `apt-get install libpng-dev`. 25 | * On Fedora, do `dnf install libpng-devel`. 26 | * On Arch Linux, do `pacman -S libpng`. 27 | * On Alpine Linux, do `apk add libpng-dev`. 28 | 3. Run `make` and expect the binary to be created in `bin/Release/guetzli`. 29 | 30 | ## On Windows 31 | 32 | 1. Get a copy of the source code, either by cloning this repository, or by 33 | downloading an 34 | [archive](https://github.com/google/guetzli/archive/master.zip) and 35 | unpacking it. 36 | 2. Install [Visual Studio 2015](https://www.visualstudio.com) and 37 | [vcpkg](https://github.com/Microsoft/vcpkg) 38 | 3. Install `libpng` using vcpkg: `.\vcpkg install libpng`. 39 | 4. Cause the installed packages to be available system-wide: `.\vcpkg integrate 40 | install`. If you prefer not to do this, refer to [vcpkg's 41 | documentation](https://github.com/Microsoft/vcpkg/blob/master/docs/EXAMPLES.md#example-1-2). 42 | 5. Open the Visual Studio project enclosed in the repository and build it. 43 | 44 | ## On macOS 45 | 46 | To install using [Homebrew](https://brew.sh/): 47 | 1. Install [Homebrew](https://brew.sh/) 48 | 2. `brew install guetzli` 49 | 50 | To install using the repository: 51 | 1. Get a copy of the source code, either by cloning this repository, or by 52 | downloading an 53 | [archive](https://github.com/google/guetzli/archive/master.zip) and 54 | unpacking it. 55 | 2. Install [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/) 56 | 3. Install `libpng` 57 | * Using [Homebrew](https://brew.sh/): `brew install libpng`. 58 | * Using [MacPorts](https://www.macports.org/): `port install libpng` (You may need to use `sudo`). 59 | 4. Run the following command to build the binary in `bin/Release/guetzli`. 60 | * If you installed using [Homebrew](https://brew.sh/) simply use `make` 61 | * If you installed using [MacPorts](https://www.macports.org/) use `CFLAGS='-I/opt/local/include' LDFLAGS='-L/opt/local/lib' make` 62 | 63 | ## With Bazel 64 | 65 | There's also a [Bazel](https://bazel.build) build configuration provided. If you 66 | have Bazel installed, you can also compile Guetzli by running `bazel build -c opt //:guetzli`. 67 | 68 | # Using 69 | 70 | **Note:** Guetzli uses a large amount of memory. You should provide 300MB of 71 | memory per 1MPix of the input image. 72 | 73 | **Note:** Guetzli uses a significant amount of CPU time. You should count on 74 | using about 1 minute of CPU per 1 MPix of input image. 75 | 76 | **Note:** Guetzli assumes that input is in **sRGB profile** with a **gamma of 77 | 2.2**. Guetzli will ignore any color-profile metadata in the image. 78 | 79 | To try out Guetzli you need to [build](#building) or 80 | [download](https://github.com/google/guetzli/releases) the Guetzli binary. The 81 | binary reads a PNG or JPEG image and creates an optimized JPEG image: 82 | 83 | ```bash 84 | guetzli [--quality Q] [--verbose] original.png output.jpg 85 | guetzli [--quality Q] [--verbose] original.jpg output.jpg 86 | ``` 87 | 88 | Note that Guetzli is designed to work on high quality images. You should always 89 | prefer providing uncompressed input images (e.g. that haven't been already 90 | compressed with any JPEG encoders, including Guetzli). While it will work on other 91 | images too, results will be poorer. You can try compressing an enclosed [sample 92 | high quality 93 | image](https://github.com/google/guetzli/releases/download/v0/bees.png). 94 | 95 | You can pass a `--quality Q` parameter to set quality in units equivalent to 96 | libjpeg quality. You can also pass a `--verbose` flag to see a trace of encoding 97 | attempts made. 98 | 99 | Please note that JPEG images do not support alpha channel (transparency). If the 100 | input is a PNG with an alpha channel, it will be overlaid on black background 101 | before encoding. 102 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # Description: 2 | # Bazel workspace file for Guetzli. 3 | 4 | workspace(name = "guetzli") 5 | 6 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 7 | 8 | http_archive( 9 | name = "png_archive", 10 | build_file = "png.BUILD", 11 | sha256 = "a941dc09ca00148fe7aaf4ecdd6a67579c293678ed1e1cf633b5ffc02f4f8cf7", 12 | strip_prefix = "libpng-1.2.57", 13 | url = "http://github.com/glennrp/libpng/archive/v1.2.57.zip", 14 | ) 15 | 16 | http_archive( 17 | name = "zlib_archive", 18 | build_file = "zlib.BUILD", 19 | sha256 = "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017", 20 | strip_prefix = "zlib-1.2.10", 21 | url = "http://zlib.net/fossils/zlib-1.2.10.tar.gz", 22 | ) 23 | 24 | local_repository( 25 | name = "butteraugli", 26 | path = "third_party/butteraugli/", 27 | ) 28 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '1.0.1#{build}' 2 | 3 | shallow_clone: true 4 | 5 | os: 6 | - Visual Studio 2015 7 | 8 | environment: 9 | matrix: 10 | - TOOLSET: vs2015 11 | 12 | install: 13 | - ps: Start-FileDownload 'https://github.com/premake/premake-core/releases/download/v5.0.0-alpha11/premake-5.0.0-alpha11-windows.zip' 'premake.zip' 14 | - 7z x premake.zip 15 | - premake5.exe %TOOLSET% 16 | - git clone https://github.com/Microsoft/vcpkg 17 | - md vcpkg\downloads\nuget-3.5.0 18 | - appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -FileName %appveyor_build_folder%\vcpkg\downloads\nuget-3.5.0\nuget.exe 19 | - appveyor DownloadFile https://cmake.org/files/v3.8/cmake-3.8.0-rc1-win32-x86.zip -FileName %appveyor_build_folder%\vcpkg\downloads\cmake-3.8.0-rc1-win32-x86.zip 20 | - 7z x %appveyor_build_folder%\vcpkg\downloads\cmake-3.8.0-rc1-win32-x86.zip 21 | - cd vcpkg 22 | - powershell -exec bypass -File scripts\bootstrap.ps1 23 | - vcpkg integrate install 24 | - vcpkg install libpng 25 | - cd .. 26 | 27 | configuration: 28 | - Debug 29 | - Release 30 | 31 | build: 32 | project: guetzli.sln 33 | -------------------------------------------------------------------------------- /external/png.BUILD: -------------------------------------------------------------------------------- 1 | # Description: 2 | # libpng is the official PNG reference library. 3 | 4 | licenses(["notice"]) # BSD/MIT-like license 5 | 6 | cc_library( 7 | name = "png", 8 | srcs = [ 9 | "png.c", 10 | "pngerror.c", 11 | "pngget.c", 12 | "pngmem.c", 13 | "pngpread.c", 14 | "pngread.c", 15 | "pngrio.c", 16 | "pngrtran.c", 17 | "pngrutil.c", 18 | "pngset.c", 19 | "pngtrans.c", 20 | "pngwio.c", 21 | "pngwrite.c", 22 | "pngwtran.c", 23 | "pngwutil.c", 24 | ], 25 | hdrs = [ 26 | "png.h", 27 | "pngconf.h", 28 | ], 29 | includes = ["."], 30 | linkopts = ["-lm"], 31 | visibility = ["//visibility:public"], 32 | deps = ["@zlib_archive//:zlib"], 33 | ) 34 | -------------------------------------------------------------------------------- /external/zlib.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | licenses(["notice"]) # BSD/MIT-like license (for zlib) 4 | 5 | cc_library( 6 | name = "zlib", 7 | srcs = [ 8 | "adler32.c", 9 | "compress.c", 10 | "crc32.c", 11 | "crc32.h", 12 | "deflate.c", 13 | "deflate.h", 14 | "gzclose.c", 15 | "gzguts.h", 16 | "gzlib.c", 17 | "gzread.c", 18 | "gzwrite.c", 19 | "infback.c", 20 | "inffast.c", 21 | "inffast.h", 22 | "inffixed.h", 23 | "inflate.c", 24 | "inflate.h", 25 | "inftrees.c", 26 | "inftrees.h", 27 | "trees.c", 28 | "trees.h", 29 | "uncompr.c", 30 | "zconf.h", 31 | "zutil.c", 32 | "zutil.h", 33 | ], 34 | hdrs = ["zlib.h"], 35 | includes = ["."], 36 | ) 37 | -------------------------------------------------------------------------------- /fuzz_target.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "guetzli/jpeg_data.h" 3 | #include "guetzli/jpeg_data_reader.h" 4 | #include "guetzli/processor.h" 5 | 6 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 7 | std::string jpeg_data(reinterpret_cast(data), size); 8 | 9 | // Ignore large images, to prevent timeouts. 10 | guetzli::JPEGData jpg_header; 11 | if (!guetzli::ReadJpeg(data, size, guetzli::JPEG_READ_HEADER, &jpg_header)) { 12 | return 0; 13 | } 14 | static constexpr int kMaxPixels = 10000; 15 | if (static_cast(jpg_header.width) * jpg_header.height > kMaxPixels) { 16 | return 0; 17 | } 18 | 19 | // TODO(robryk): Use nondefault parameters. 20 | guetzli::Params params; 21 | std::string jpeg_out; 22 | (void)guetzli::Process(params, nullptr, jpeg_data, &jpeg_out); 23 | // TODO(robryk): Verify output distance if Process() succeeded. 24 | return 0; 25 | } 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /guetzli.make: -------------------------------------------------------------------------------- 1 | # GNU Make project makefile autogenerated by Premake 2 | 3 | ifndef config 4 | config=release 5 | endif 6 | 7 | ifndef verbose 8 | SILENT = @ 9 | endif 10 | 11 | .PHONY: clean prebuild prelink 12 | 13 | ifeq ($(config),release) 14 | RESCOMP = windres 15 | TARGETDIR = bin/Release 16 | TARGET = $(TARGETDIR)/guetzli 17 | OBJDIR = obj/Release/guetzli 18 | DEFINES += 19 | INCLUDES += -I. -Ithird_party/butteraugli 20 | FORCE_INCLUDE += 21 | ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) 22 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O3 -g `pkg-config --cflags libpng || libpng-config --cflags` 23 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O3 -g -std=c++11 `pkg-config --cflags libpng || libpng-config --cflags` 24 | ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) 25 | LIBS += 26 | LDDEPS += 27 | ALL_LDFLAGS += $(LDFLAGS) `pkg-config --libs libpng || libpng-config --ldflags` 28 | LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) 29 | define PREBUILDCMDS 30 | endef 31 | define PRELINKCMDS 32 | endef 33 | define POSTBUILDCMDS 34 | endef 35 | all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) 36 | @: 37 | 38 | endif 39 | 40 | ifeq ($(config),debug) 41 | RESCOMP = windres 42 | TARGETDIR = bin/Debug 43 | TARGET = $(TARGETDIR)/guetzli 44 | OBJDIR = obj/Debug/guetzli 45 | DEFINES += 46 | INCLUDES += -I. -Ithird_party/butteraugli 47 | FORCE_INCLUDE += 48 | ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) 49 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g `pkg-config --cflags libpng || libpng-config --cflags` 50 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11 `pkg-config --cflags libpng || libpng-config --cflags` 51 | ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) 52 | LIBS += 53 | LDDEPS += 54 | ALL_LDFLAGS += $(LDFLAGS) `pkg-config --libs libpng || libpng-config --ldflags` 55 | LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) 56 | define PREBUILDCMDS 57 | endef 58 | define PRELINKCMDS 59 | endef 60 | define POSTBUILDCMDS 61 | endef 62 | all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) 63 | @: 64 | 65 | endif 66 | 67 | OBJECTS := \ 68 | $(OBJDIR)/butteraugli_comparator.o \ 69 | $(OBJDIR)/dct_double.o \ 70 | $(OBJDIR)/debug_print.o \ 71 | $(OBJDIR)/entropy_encode.o \ 72 | $(OBJDIR)/fdct.o \ 73 | $(OBJDIR)/gamma_correct.o \ 74 | $(OBJDIR)/guetzli.o \ 75 | $(OBJDIR)/idct.o \ 76 | $(OBJDIR)/jpeg_data.o \ 77 | $(OBJDIR)/jpeg_data_decoder.o \ 78 | $(OBJDIR)/jpeg_data_encoder.o \ 79 | $(OBJDIR)/jpeg_data_reader.o \ 80 | $(OBJDIR)/jpeg_data_writer.o \ 81 | $(OBJDIR)/jpeg_huffman_decode.o \ 82 | $(OBJDIR)/output_image.o \ 83 | $(OBJDIR)/preprocess_downsample.o \ 84 | $(OBJDIR)/processor.o \ 85 | $(OBJDIR)/quality.o \ 86 | $(OBJDIR)/quantize.o \ 87 | $(OBJDIR)/score.o \ 88 | $(OBJDIR)/butteraugli.o \ 89 | 90 | RESOURCES := \ 91 | 92 | CUSTOMFILES := \ 93 | 94 | SHELLTYPE := msdos 95 | ifeq (,$(ComSpec)$(COMSPEC)) 96 | SHELLTYPE := posix 97 | endif 98 | ifeq (/bin,$(findstring /bin,$(SHELL))) 99 | SHELLTYPE := posix 100 | endif 101 | 102 | $(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES) 103 | @echo Linking guetzli 104 | $(SILENT) $(LINKCMD) 105 | $(POSTBUILDCMDS) 106 | 107 | $(TARGETDIR): 108 | @echo Creating $(TARGETDIR) 109 | ifeq (posix,$(SHELLTYPE)) 110 | $(SILENT) mkdir -p $(TARGETDIR) 111 | else 112 | $(SILENT) mkdir $(subst /,\\,$(TARGETDIR)) 113 | endif 114 | 115 | $(OBJDIR): 116 | @echo Creating $(OBJDIR) 117 | ifeq (posix,$(SHELLTYPE)) 118 | $(SILENT) mkdir -p $(OBJDIR) 119 | else 120 | $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) 121 | endif 122 | 123 | clean: 124 | @echo Cleaning guetzli 125 | ifeq (posix,$(SHELLTYPE)) 126 | $(SILENT) rm -f $(TARGET) 127 | $(SILENT) rm -rf $(OBJDIR) 128 | else 129 | $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) 130 | $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) 131 | endif 132 | 133 | prebuild: 134 | $(PREBUILDCMDS) 135 | 136 | prelink: 137 | $(PRELINKCMDS) 138 | 139 | ifneq (,$(PCH)) 140 | $(OBJECTS): $(GCH) $(PCH) 141 | $(GCH): $(PCH) 142 | @echo $(notdir $<) 143 | $(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<" 144 | endif 145 | 146 | $(OBJDIR)/butteraugli_comparator.o: guetzli/butteraugli_comparator.cc 147 | @echo $(notdir $<) 148 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 149 | $(OBJDIR)/dct_double.o: guetzli/dct_double.cc 150 | @echo $(notdir $<) 151 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 152 | $(OBJDIR)/debug_print.o: guetzli/debug_print.cc 153 | @echo $(notdir $<) 154 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 155 | $(OBJDIR)/entropy_encode.o: guetzli/entropy_encode.cc 156 | @echo $(notdir $<) 157 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 158 | $(OBJDIR)/fdct.o: guetzli/fdct.cc 159 | @echo $(notdir $<) 160 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 161 | $(OBJDIR)/gamma_correct.o: guetzli/gamma_correct.cc 162 | @echo $(notdir $<) 163 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 164 | $(OBJDIR)/guetzli.o: guetzli/guetzli.cc 165 | @echo $(notdir $<) 166 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 167 | $(OBJDIR)/idct.o: guetzli/idct.cc 168 | @echo $(notdir $<) 169 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 170 | $(OBJDIR)/jpeg_data.o: guetzli/jpeg_data.cc 171 | @echo $(notdir $<) 172 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 173 | $(OBJDIR)/jpeg_data_decoder.o: guetzli/jpeg_data_decoder.cc 174 | @echo $(notdir $<) 175 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 176 | $(OBJDIR)/jpeg_data_encoder.o: guetzli/jpeg_data_encoder.cc 177 | @echo $(notdir $<) 178 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 179 | $(OBJDIR)/jpeg_data_reader.o: guetzli/jpeg_data_reader.cc 180 | @echo $(notdir $<) 181 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 182 | $(OBJDIR)/jpeg_data_writer.o: guetzli/jpeg_data_writer.cc 183 | @echo $(notdir $<) 184 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 185 | $(OBJDIR)/jpeg_huffman_decode.o: guetzli/jpeg_huffman_decode.cc 186 | @echo $(notdir $<) 187 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 188 | $(OBJDIR)/output_image.o: guetzli/output_image.cc 189 | @echo $(notdir $<) 190 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 191 | $(OBJDIR)/preprocess_downsample.o: guetzli/preprocess_downsample.cc 192 | @echo $(notdir $<) 193 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 194 | $(OBJDIR)/processor.o: guetzli/processor.cc 195 | @echo $(notdir $<) 196 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 197 | $(OBJDIR)/quality.o: guetzli/quality.cc 198 | @echo $(notdir $<) 199 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 200 | $(OBJDIR)/quantize.o: guetzli/quantize.cc 201 | @echo $(notdir $<) 202 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 203 | $(OBJDIR)/score.o: guetzli/score.cc 204 | @echo $(notdir $<) 205 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 206 | $(OBJDIR)/butteraugli.o: third_party/butteraugli/butteraugli/butteraugli.cc 207 | @echo $(notdir $<) 208 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 209 | 210 | -include $(OBJECTS:%.o=%.d) 211 | ifneq (,$(PCH)) 212 | -include $(OBJDIR)/$(notdir $(PCH)).d 213 | endif -------------------------------------------------------------------------------- /guetzli.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guetzli_static", "guetzli_static.vcxproj", "{30B3C385-1C81-B78B-0515-28B2F18193F0}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guetzli", "guetzli.vcxproj", "{C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Debug|Win32.Build.0 = Debug|Win32 18 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Debug|x64.ActiveCfg = Debug|x64 19 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Debug|x64.Build.0 = Debug|x64 20 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Release|Win32.ActiveCfg = Release|Win32 21 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Release|Win32.Build.0 = Release|Win32 22 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Release|x64.ActiveCfg = Release|x64 23 | {30B3C385-1C81-B78B-0515-28B2F18193F0}.Release|x64.Build.0 = Release|x64 24 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Debug|Win32.Build.0 = Debug|Win32 26 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Debug|x64.ActiveCfg = Debug|x64 27 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Debug|x64.Build.0 = Debug|x64 28 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Release|Win32.ActiveCfg = Release|Win32 29 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Release|Win32.Build.0 = Release|Win32 30 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Release|x64.ActiveCfg = Release|x64 31 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411}.Release|x64.Build.0 = Release|x64 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /guetzli.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /guetzli.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | x64 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Debug 18 | Win32 19 | 20 | 21 | 22 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411} 23 | true 24 | Win32Proj 25 | guetzli 26 | 27 | 28 | 29 | Application 30 | false 31 | Unicode 32 | v140 33 | 34 | 35 | Application 36 | false 37 | Unicode 38 | v140 39 | 40 | 41 | Application 42 | true 43 | Unicode 44 | v140 45 | 46 | 47 | Application 48 | true 49 | Unicode 50 | v140 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | false 70 | bin\x86_64\Release\ 71 | obj\x86_64\Release\guetzli\ 72 | guetzli 73 | .exe 74 | 75 | 76 | false 77 | bin\x86\Release\ 78 | obj\x86\Release\guetzli\ 79 | guetzli 80 | .exe 81 | 82 | 83 | true 84 | bin\x86_64\Debug\ 85 | obj\x86_64\Debug\guetzli\ 86 | guetzli 87 | .exe 88 | 89 | 90 | true 91 | bin\x86\Debug\ 92 | obj\x86\Debug\guetzli\ 93 | guetzli 94 | .exe 95 | 96 | 97 | 98 | NotUsing 99 | Level3 100 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 101 | Full 102 | true 103 | true 104 | false 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | shlwapi.lib;%(AdditionalDependencies) 112 | mainCRTStartup 113 | 114 | 115 | 116 | 117 | NotUsing 118 | Level3 119 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 120 | Full 121 | true 122 | true 123 | false 124 | true 125 | 126 | 127 | Console 128 | true 129 | true 130 | shlwapi.lib;%(AdditionalDependencies) 131 | mainCRTStartup 132 | 133 | 134 | 135 | 136 | NotUsing 137 | Level3 138 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 139 | EditAndContinue 140 | Disabled 141 | 142 | 143 | Console 144 | true 145 | shlwapi.lib;%(AdditionalDependencies) 146 | mainCRTStartup 147 | 148 | 149 | 150 | 151 | NotUsing 152 | Level3 153 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 154 | EditAndContinue 155 | Disabled 156 | 157 | 158 | Console 159 | true 160 | shlwapi.lib;%(AdditionalDependencies) 161 | mainCRTStartup 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /guetzli.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411} 6 | 7 | 8 | {0FB18DF1-7B66-06E7-045B-00BE700FFDEA} 9 | 10 | 11 | {468B2B32-B2C2-73C9-BBCC-D7EC27839AC2} 12 | 13 | 14 | {FD6FCB41-6929-36EC-F288-50C65E41EC5B} 15 | 16 | 17 | 18 | 19 | guetzli 20 | 21 | 22 | guetzli 23 | 24 | 25 | guetzli 26 | 27 | 28 | guetzli 29 | 30 | 31 | guetzli 32 | 33 | 34 | guetzli 35 | 36 | 37 | guetzli 38 | 39 | 40 | guetzli 41 | 42 | 43 | guetzli 44 | 45 | 46 | guetzli 47 | 48 | 49 | guetzli 50 | 51 | 52 | guetzli 53 | 54 | 55 | guetzli 56 | 57 | 58 | guetzli 59 | 60 | 61 | guetzli 62 | 63 | 64 | guetzli 65 | 66 | 67 | guetzli 68 | 69 | 70 | guetzli 71 | 72 | 73 | guetzli 74 | 75 | 76 | guetzli 77 | 78 | 79 | guetzli 80 | 81 | 82 | guetzli 83 | 84 | 85 | guetzli 86 | 87 | 88 | guetzli 89 | 90 | 91 | guetzli 92 | 93 | 94 | third_party\butteraugli\butteraugli 95 | 96 | 97 | 98 | 99 | guetzli 100 | 101 | 102 | guetzli 103 | 104 | 105 | guetzli 106 | 107 | 108 | guetzli 109 | 110 | 111 | guetzli 112 | 113 | 114 | guetzli 115 | 116 | 117 | guetzli 118 | 119 | 120 | guetzli 121 | 122 | 123 | guetzli 124 | 125 | 126 | guetzli 127 | 128 | 129 | guetzli 130 | 131 | 132 | guetzli 133 | 134 | 135 | guetzli 136 | 137 | 138 | guetzli 139 | 140 | 141 | guetzli 142 | 143 | 144 | guetzli 145 | 146 | 147 | guetzli 148 | 149 | 150 | guetzli 151 | 152 | 153 | guetzli 154 | 155 | 156 | guetzli 157 | 158 | 159 | third_party\butteraugli\butteraugli 160 | 161 | 162 | -------------------------------------------------------------------------------- /guetzli/butteraugli_comparator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_BUTTERAUGLI_COMPARATOR_H_ 18 | #define GUETZLI_BUTTERAUGLI_COMPARATOR_H_ 19 | 20 | #include 21 | 22 | #include "butteraugli/butteraugli.h" 23 | #include "guetzli/comparator.h" 24 | #include "guetzli/jpeg_data.h" 25 | #include "guetzli/output_image.h" 26 | #include "guetzli/stats.h" 27 | 28 | namespace guetzli { 29 | 30 | constexpr int kButteraugliStep = 3; 31 | 32 | class ButteraugliComparator : public Comparator { 33 | public: 34 | ButteraugliComparator(const int width, const int height, 35 | const std::vector* rgb, 36 | const float target_distance, ProcessStats* stats); 37 | 38 | void Compare(const OutputImage& img) override; 39 | 40 | void StartBlockComparisons() override; 41 | void FinishBlockComparisons() override; 42 | 43 | void SwitchBlock(int block_x, int block_y, 44 | int factor_x, int factor_y) override; 45 | 46 | double CompareBlock(const OutputImage& img, 47 | int off_x, int off_y) const override; 48 | 49 | double ScoreOutputSize(int size) const override; 50 | 51 | bool DistanceOK(double target_mul) const override { 52 | return distance_ <= target_mul * target_distance_; 53 | } 54 | 55 | const std::vector distmap() const override { return distmap_; } 56 | float distmap_aggregate() const override { return distance_; } 57 | 58 | float BlockErrorLimit() const override; 59 | 60 | void ComputeBlockErrorAdjustmentWeights( 61 | int direction, int max_block_dist, double target_mul, int factor_x, 62 | int factor_y, const std::vector& distmap, 63 | std::vector* block_weight) override; 64 | 65 | private: 66 | const int width_; 67 | const int height_; 68 | const float target_distance_; 69 | const std::vector& rgb_orig_; 70 | int block_x_; 71 | int block_y_; 72 | int factor_x_; 73 | int factor_y_; 74 | std::vector<::butteraugli::ImageF> mask_xyz_; 75 | std::vector>> per_block_pregamma_; 76 | ::butteraugli::ButteraugliComparator comparator_; 77 | float distance_; 78 | std::vector distmap_; 79 | ProcessStats* stats_; 80 | }; 81 | 82 | } // namespace guetzli 83 | 84 | #endif // GUETZLI_BUTTERAUGLI_COMPARATOR_H_ 85 | -------------------------------------------------------------------------------- /guetzli/comparator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_COMPARATOR_H_ 18 | #define GUETZLI_COMPARATOR_H_ 19 | 20 | #include 21 | 22 | #include "guetzli/output_image.h" 23 | #include "guetzli/stats.h" 24 | 25 | namespace guetzli { 26 | 27 | // Represents a baseline image, a comparison metric and an image acceptance 28 | // criteria based on this metric. 29 | class Comparator { 30 | public: 31 | Comparator() {} 32 | virtual ~Comparator() {} 33 | 34 | // Compares img with the baseline image and saves the resulting distance map 35 | // inside the object. The provided image must have the same dimensions as the 36 | // baseline image. 37 | virtual void Compare(const OutputImage& img) = 0; 38 | 39 | // Must be called before any CompareBlock() calls can be called. 40 | virtual void StartBlockComparisons() = 0; 41 | // No more CompareBlock() calls can be called after this. 42 | virtual void FinishBlockComparisons() = 0; 43 | 44 | // Sets the coordinates of the current macro-block for the purpose of 45 | // CompareBlock() calls. 46 | virtual void SwitchBlock(int block_x, int block_y, 47 | int factor_x, int factor_y) = 0; 48 | 49 | // Compares the 8x8 block with offsets (off_x, off_y) within the current 50 | // macro-block of the baseline image with the same block of img and returns 51 | // the resulting per-block distance. The interpretation of the returned 52 | // distance depends on the comparator used. 53 | virtual double CompareBlock(const OutputImage& img, 54 | int off_x, int off_y) const = 0; 55 | 56 | // Returns the combined score of the output image in the last Compare() call 57 | // (or the baseline image, if Compare() was not called yet), based on output 58 | // size and the similarity metric. 59 | virtual double ScoreOutputSize(int size) const = 0; 60 | 61 | // Returns true if the argument of the last Compare() call (or the baseline 62 | // image, if Compare() was not called yet) meets the image acceptance 63 | // criteria. The target_mul modifies the acceptance criteria used in this call 64 | // the following way: 65 | // = 1.0 : the original acceptance criteria is used, 66 | // < 1.0 : a more strict acceptance criteria is used, 67 | // > 1.0 : a less strict acceptance criteria is used. 68 | virtual bool DistanceOK(double target_mul) const = 0; 69 | 70 | // Returns the distance map between the baseline image and the image in the 71 | // last Compare() call (or the baseline image, if Compare() was not called 72 | // yet). 73 | // The dimensions of the distance map are the same as the baseline image. 74 | // The interpretation of the distance values depend on the comparator used. 75 | virtual const std::vector distmap() const = 0; 76 | 77 | // Returns an aggregate distance or similarity value between the baseline 78 | // image and the image in the last Compare() call (or the baseline image, if 79 | // Compare() was not called yet). 80 | // The interpretation of this aggregate value depends on the comparator used. 81 | virtual float distmap_aggregate() const = 0; 82 | 83 | // Returns a heuristic cutoff on block errors in the sense that we won't 84 | // consider distortions where a block error is greater than this. 85 | virtual float BlockErrorLimit() const = 0; 86 | // Given the search direction (+1 for upwards and -1 for downwards) and the 87 | // current distance map, fills in *block_weight image with the relative block 88 | // error adjustment weights. 89 | // The target_mul param has the same semantics as in DistanceOK(). 90 | // Note that this is essentially a static function in the sense that it does 91 | // not depend on the last Compare() call. 92 | virtual void ComputeBlockErrorAdjustmentWeights( 93 | int direction, int max_block_dist, double target_mul, int factor_x, 94 | int factor_y, const std::vector& distmap, 95 | std::vector* block_weight) = 0; 96 | }; 97 | 98 | 99 | } // namespace guetzli 100 | 101 | #endif // GUETZLI_COMPARATOR_H_ 102 | -------------------------------------------------------------------------------- /guetzli/dct_double.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/dct_double.h" 18 | 19 | #include 20 | #include 21 | 22 | namespace guetzli { 23 | 24 | namespace { 25 | 26 | // kDCTMatrix[8*u+x] = 0.5*alpha(u)*cos((2*x+1)*u*M_PI/16), 27 | // where alpha(0) = 1/sqrt(2) and alpha(u) = 1 for u > 0. 28 | static const double kDCTMatrix[64] = { 29 | 0.3535533906, 0.3535533906, 0.3535533906, 0.3535533906, 30 | 0.3535533906, 0.3535533906, 0.3535533906, 0.3535533906, 31 | 0.4903926402, 0.4157348062, 0.2777851165, 0.0975451610, 32 | -0.0975451610, -0.2777851165, -0.4157348062, -0.4903926402, 33 | 0.4619397663, 0.1913417162, -0.1913417162, -0.4619397663, 34 | -0.4619397663, -0.1913417162, 0.1913417162, 0.4619397663, 35 | 0.4157348062, -0.0975451610, -0.4903926402, -0.2777851165, 36 | 0.2777851165, 0.4903926402, 0.0975451610, -0.4157348062, 37 | 0.3535533906, -0.3535533906, -0.3535533906, 0.3535533906, 38 | 0.3535533906, -0.3535533906, -0.3535533906, 0.3535533906, 39 | 0.2777851165, -0.4903926402, 0.0975451610, 0.4157348062, 40 | -0.4157348062, -0.0975451610, 0.4903926402, -0.2777851165, 41 | 0.1913417162, -0.4619397663, 0.4619397663, -0.1913417162, 42 | -0.1913417162, 0.4619397663, -0.4619397663, 0.1913417162, 43 | 0.0975451610, -0.2777851165, 0.4157348062, -0.4903926402, 44 | 0.4903926402, -0.4157348062, 0.2777851165, -0.0975451610, 45 | }; 46 | 47 | void DCT1d(const double* in, int stride, double* out) { 48 | for (int x = 0; x < 8; ++x) { 49 | out[x * stride] = 0.0; 50 | for (int u = 0; u < 8; ++u) { 51 | out[x * stride] += kDCTMatrix[8 * x + u] * in[u * stride]; 52 | } 53 | } 54 | } 55 | 56 | void IDCT1d(const double* in, int stride, double* out) { 57 | for (int x = 0; x < 8; ++x) { 58 | out[x * stride] = 0.0; 59 | for (int u = 0; u < 8; ++u) { 60 | out[x * stride] += kDCTMatrix[8 * u + x] * in[u * stride]; 61 | } 62 | } 63 | } 64 | 65 | typedef void (*Transform1d)(const double* in, int stride, double* out); 66 | 67 | void TransformBlock(double block[64], Transform1d f) { 68 | double tmp[64]; 69 | for (int x = 0; x < 8; ++x) { 70 | f(&block[x], 8, &tmp[x]); 71 | } 72 | for (int y = 0; y < 8; ++y) { 73 | f(&tmp[8 * y], 1, &block[8 * y]); 74 | } 75 | } 76 | 77 | } // namespace 78 | 79 | void ComputeBlockDCTDouble(double block[64]) { 80 | TransformBlock(block, DCT1d); 81 | } 82 | 83 | void ComputeBlockIDCTDouble(double block[64]) { 84 | TransformBlock(block, IDCT1d); 85 | } 86 | 87 | } // namespace guetzli 88 | -------------------------------------------------------------------------------- /guetzli/dct_double.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_DCT_DOUBLE_H_ 18 | #define GUETZLI_DCT_DOUBLE_H_ 19 | 20 | namespace guetzli { 21 | 22 | // Performs in-place floating point 8x8 DCT on block[0..63]. 23 | // Note that the DCT used here is the DCT-2 with the first term multiplied by 24 | // 1/sqrt(2) and the result scaled by 1/2. 25 | void ComputeBlockDCTDouble(double block[64]); 26 | 27 | // Performs in-place floating point 8x8 inverse DCT on block[0..63]. 28 | void ComputeBlockIDCTDouble(double block[64]); 29 | 30 | } // namespace guetzli 31 | 32 | #endif // GUETZLI_DCT_DOUBLE_H_ 33 | -------------------------------------------------------------------------------- /guetzli/debug_print.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/debug_print.h" 18 | 19 | namespace guetzli { 20 | 21 | void PrintDebug(ProcessStats* stats, std::string s) { 22 | if (stats->debug_output) { 23 | stats->debug_output->append(s); 24 | } 25 | if (stats->debug_output_file) { 26 | fprintf(stats->debug_output_file, "%s", s.c_str()); 27 | } 28 | } 29 | 30 | } // namespace guetzli 31 | -------------------------------------------------------------------------------- /guetzli/debug_print.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_DEBUG_PRINT_H_ 18 | #define GUETZLI_DEBUG_PRINT_H_ 19 | 20 | #include "guetzli/stats.h" 21 | 22 | namespace guetzli { 23 | 24 | void PrintDebug(ProcessStats* stats, std::string s); 25 | 26 | } // namespace guetzli 27 | 28 | #define GUETZLI_LOG(stats, ...) \ 29 | do { \ 30 | char debug_string[1024]; \ 31 | int res = snprintf(debug_string, sizeof(debug_string), \ 32 | __VA_ARGS__); \ 33 | assert(res > 0 && "expected successful printing"); \ 34 | (void)res; \ 35 | debug_string[sizeof(debug_string) - 1] = '\0'; \ 36 | ::guetzli::PrintDebug( \ 37 | stats, std::string(debug_string)); \ 38 | } while (0) 39 | #define GUETZLI_LOG_QUANT(stats, q) \ 40 | for (int y = 0; y < 8; ++y) { \ 41 | for (int c = 0; c < 3; ++c) { \ 42 | for (int x = 0; x < 8; ++x) \ 43 | GUETZLI_LOG(stats, " %2d", (q)[c][8 * y + x]); \ 44 | GUETZLI_LOG(stats, " "); \ 45 | } \ 46 | GUETZLI_LOG(stats, "\n"); \ 47 | } 48 | 49 | #endif // GUETZLI_DEBUG_PRINT_H_ 50 | -------------------------------------------------------------------------------- /guetzli/entropy_encode.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Entropy encoding (Huffman) utilities. 18 | 19 | #include "guetzli/entropy_encode.h" 20 | 21 | #include 22 | #include 23 | 24 | namespace guetzli { 25 | 26 | bool SetDepth(int p0, HuffmanTree *pool, uint8_t *depth, int max_depth) { 27 | int stack[17]; 28 | int level = 0; 29 | int p = p0; 30 | assert(max_depth <= 16); 31 | stack[0] = -1; 32 | while (true) { 33 | if (pool[p].index_left_ >= 0) { 34 | level++; 35 | if (level > max_depth) return false; 36 | stack[level] = pool[p].index_right_or_value_; 37 | p = pool[p].index_left_; 38 | continue; 39 | } else { 40 | depth[pool[p].index_right_or_value_] = static_cast(level); 41 | } 42 | while (level >= 0 && stack[level] == -1) level--; 43 | if (level < 0) return true; 44 | p = stack[level]; 45 | stack[level] = -1; 46 | } 47 | } 48 | 49 | // Sort the root nodes, least popular first. 50 | static inline bool SortHuffmanTree(const HuffmanTree& v0, 51 | const HuffmanTree& v1) { 52 | if (v0.total_count_ != v1.total_count_) { 53 | return v0.total_count_ < v1.total_count_; 54 | } 55 | return v0.index_right_or_value_ > v1.index_right_or_value_; 56 | } 57 | 58 | // This function will create a Huffman tree. 59 | // 60 | // The catch here is that the tree cannot be arbitrarily deep. 61 | // Brotli specifies a maximum depth of 15 bits for "code trees" 62 | // and 7 bits for "code length code trees." 63 | // 64 | // count_limit is the value that is to be faked as the minimum value 65 | // and this minimum value is raised until the tree matches the 66 | // maximum length requirement. 67 | // 68 | // This algorithm is not of excellent performance for very long data blocks, 69 | // especially when population counts are longer than 2**tree_limit, but 70 | // we are not planning to use this with extremely long blocks. 71 | // 72 | // See http://en.wikipedia.org/wiki/Huffman_coding 73 | void CreateHuffmanTree(const uint32_t *data, 74 | const size_t length, 75 | const int tree_limit, 76 | HuffmanTree* tree, 77 | uint8_t *depth) { 78 | // For block sizes below 64 kB, we never need to do a second iteration 79 | // of this loop. Probably all of our block sizes will be smaller than 80 | // that, so this loop is mostly of academic interest. If we actually 81 | // would need this, we would be better off with the Katajainen algorithm. 82 | for (uint32_t count_limit = 1; ; count_limit *= 2) { 83 | size_t n = 0; 84 | for (size_t i = length; i != 0;) { 85 | --i; 86 | if (data[i]) { 87 | const uint32_t count = std::max(data[i], count_limit); 88 | tree[n++] = HuffmanTree(count, -1, static_cast(i)); 89 | } 90 | } 91 | 92 | if (n == 1) { 93 | depth[tree[0].index_right_or_value_] = 1; // Only one element. 94 | break; 95 | } 96 | 97 | std::sort(tree, tree + n, SortHuffmanTree); 98 | 99 | // The nodes are: 100 | // [0, n): the sorted leaf nodes that we start with. 101 | // [n]: we add a sentinel here. 102 | // [n + 1, 2n): new parent nodes are added here, starting from 103 | // (n+1). These are naturally in ascending order. 104 | // [2n]: we add a sentinel at the end as well. 105 | // There will be (2n+1) elements at the end. 106 | const HuffmanTree sentinel(~static_cast(0), -1, -1); 107 | tree[n] = sentinel; 108 | tree[n + 1] = sentinel; 109 | 110 | size_t i = 0; // Points to the next leaf node. 111 | size_t j = n + 1; // Points to the next non-leaf node. 112 | for (size_t k = n - 1; k != 0; --k) { 113 | size_t left, right; 114 | if (tree[i].total_count_ <= tree[j].total_count_) { 115 | left = i; 116 | ++i; 117 | } else { 118 | left = j; 119 | ++j; 120 | } 121 | if (tree[i].total_count_ <= tree[j].total_count_) { 122 | right = i; 123 | ++i; 124 | } else { 125 | right = j; 126 | ++j; 127 | } 128 | 129 | // The sentinel node becomes the parent node. 130 | size_t j_end = 2 * n - k; 131 | tree[j_end].total_count_ = 132 | tree[left].total_count_ + tree[right].total_count_; 133 | tree[j_end].index_left_ = static_cast(left); 134 | tree[j_end].index_right_or_value_ = static_cast(right); 135 | 136 | // Add back the last sentinel node. 137 | tree[j_end + 1] = sentinel; 138 | } 139 | if (SetDepth(static_cast(2 * n - 1), &tree[0], depth, tree_limit)) { 140 | /* We need to pack the Huffman tree in tree_limit bits. If this was not 141 | successful, add fake entities to the lowest values and retry. */ 142 | break; 143 | } 144 | } 145 | } 146 | 147 | } // namespace guetzli 148 | -------------------------------------------------------------------------------- /guetzli/entropy_encode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Entropy encoding (Huffman) utilities. 18 | 19 | #ifndef GUETZLI_ENTROPY_ENCODE_H_ 20 | #define GUETZLI_ENTROPY_ENCODE_H_ 21 | 22 | #include 23 | #include 24 | 25 | namespace guetzli { 26 | 27 | // A node of a Huffman tree. 28 | struct HuffmanTree { 29 | HuffmanTree() {} 30 | HuffmanTree(uint32_t count, int16_t left, int16_t right) 31 | : total_count_(count), 32 | index_left_(left), 33 | index_right_or_value_(right) { 34 | } 35 | uint32_t total_count_; 36 | int16_t index_left_; 37 | int16_t index_right_or_value_; 38 | }; 39 | 40 | bool SetDepth(int p, HuffmanTree *pool, uint8_t *depth, int max_depth); 41 | 42 | // This function will create a Huffman tree. 43 | // 44 | // The (data,length) contains the population counts. 45 | // The tree_limit is the maximum bit depth of the Huffman codes. 46 | // 47 | // The depth contains the tree, i.e., how many bits are used for 48 | // the symbol. 49 | // 50 | // The actual Huffman tree is constructed in the tree[] array, which has to 51 | // be at least 2 * length + 1 long. 52 | // 53 | // See http://en.wikipedia.org/wiki/Huffman_coding 54 | void CreateHuffmanTree(const uint32_t *data, 55 | const size_t length, 56 | const int tree_limit, 57 | HuffmanTree* tree, 58 | uint8_t *depth); 59 | 60 | } // namespace guetzli 61 | 62 | #endif // GUETZLI_ENTROPY_ENCODE_H_ 63 | -------------------------------------------------------------------------------- /guetzli/fast_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_FAST_LOG_H_ 18 | #define GUETZLI_FAST_LOG_H_ 19 | 20 | #include 21 | 22 | namespace guetzli { 23 | 24 | inline int Log2FloorNonZero(uint32_t n) { 25 | #ifdef __GNUC__ 26 | return 31 ^ __builtin_clz(n); 27 | #else 28 | unsigned int result = 0; 29 | while (n >>= 1) result++; 30 | return result; 31 | #endif 32 | } 33 | 34 | inline int Log2Floor(uint32_t n) { 35 | return n == 0 ? -1 : Log2FloorNonZero(n); 36 | } 37 | 38 | } // namespace guetzli 39 | 40 | #endif // GUETZLI_FAST_LOG_H_ 41 | -------------------------------------------------------------------------------- /guetzli/fdct.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Integer implementation of the Discrete Cosine Transform (DCT) 18 | // 19 | // Note! DCT output is kept scaled by 16, to retain maximum 16bit precision 20 | 21 | #include "guetzli/fdct.h" 22 | 23 | namespace guetzli { 24 | 25 | namespace { 26 | 27 | /////////////////////////////////////////////////////////////////////////////// 28 | // Cosine table: C(k) = cos(k.pi/16)/sqrt(2), k = 1..7 using 15 bits signed 29 | const coeff_t kTable04[7] = { 22725, 21407, 19266, 16384, 12873, 8867, 4520 }; 30 | // rows #1 and #7 are pre-multiplied by 2.C(1) before the 2nd pass. 31 | // This multiply is merged in the table of constants used during 1st pass: 32 | const coeff_t kTable17[7] = { 31521, 29692, 26722, 22725, 17855, 12299, 6270 }; 33 | // rows #2 and #6 are pre-multiplied by 2.C(2): 34 | const coeff_t kTable26[7] = { 29692, 27969, 25172, 21407, 16819, 11585, 5906 }; 35 | // rows #3 and #5 are pre-multiplied by 2.C(3): 36 | const coeff_t kTable35[7] = { 26722, 25172, 22654, 19266, 15137, 10426, 5315 }; 37 | 38 | /////////////////////////////////////////////////////////////////////////////// 39 | // Constants (15bit precision) and C macros for IDCT vertical pass 40 | 41 | #define kTan1 (13036) // = tan(pi/16) 42 | #define kTan2 (27146) // = tan(2.pi/16) = sqrt(2) - 1. 43 | #define kTan3m1 (-21746) // = tan(3.pi/16) - 1 44 | #define k2Sqrt2 (23170) // = 1 / 2.sqrt(2) 45 | 46 | // performs: {a,b} <- {a-b, a+b}, without saturation 47 | #define BUTTERFLY(a, b) do { \ 48 | SUB((a), (b)); \ 49 | ADD((b), (b)); \ 50 | ADD((b), (a)); \ 51 | } while (0) 52 | 53 | /////////////////////////////////////////////////////////////////////////////// 54 | // Constants for DCT horizontal pass 55 | 56 | // Note about the CORRECT_LSB macro: 57 | // using 16bit fixed-point constants, we often compute products like: 58 | // p = (A*x + B*y + 32768) >> 16 by adding two sub-terms q = (A*x) >> 16 59 | // and r = (B*y) >> 16 together. Statistically, we have p = q + r + 1 60 | // in 3/4 of the cases. This can be easily seen from the relation: 61 | // (a + b + 1) >> 1 = (a >> 1) + (b >> 1) + ((a|b)&1) 62 | // The approximation we are doing is replacing ((a|b)&1) by 1. 63 | // In practice, this is a slightly more involved because the constants A and B 64 | // have also been rounded compared to their exact floating point value. 65 | // However, all in all the correction is quite small, and CORRECT_LSB can 66 | // be defined empty if needed. 67 | 68 | #define COLUMN_DCT8(in) do { \ 69 | LOAD(m0, (in)[0 * 8]); \ 70 | LOAD(m2, (in)[2 * 8]); \ 71 | LOAD(m7, (in)[7 * 8]); \ 72 | LOAD(m5, (in)[5 * 8]); \ 73 | \ 74 | BUTTERFLY(m0, m7); \ 75 | BUTTERFLY(m2, m5); \ 76 | \ 77 | LOAD(m3, (in)[3 * 8]); \ 78 | LOAD(m4, (in)[4 * 8]); \ 79 | BUTTERFLY(m3, m4); \ 80 | \ 81 | LOAD(m6, (in)[6 * 8]); \ 82 | LOAD(m1, (in)[1 * 8]); \ 83 | BUTTERFLY(m1, m6); \ 84 | BUTTERFLY(m7, m4); \ 85 | BUTTERFLY(m6, m5); \ 86 | \ 87 | /* RowIdct() needs 15bits fixed-point input, when the output from */ \ 88 | /* ColumnIdct() would be 12bits. We are better doing the shift by 3 */ \ 89 | /* now instead of in RowIdct(), because we have some multiplies to */ \ 90 | /* perform, that can take advantage of the extra 3bits precision. */ \ 91 | LSHIFT(m4, 3); \ 92 | LSHIFT(m5, 3); \ 93 | BUTTERFLY(m4, m5); \ 94 | STORE16((in)[0 * 8], m5); \ 95 | STORE16((in)[4 * 8], m4); \ 96 | \ 97 | LSHIFT(m7, 3); \ 98 | LSHIFT(m6, 3); \ 99 | LSHIFT(m3, 3); \ 100 | LSHIFT(m0, 3); \ 101 | \ 102 | LOAD_CST(m4, kTan2); \ 103 | m5 = m4; \ 104 | MULT(m4, m7); \ 105 | MULT(m5, m6); \ 106 | SUB(m4, m6); \ 107 | ADD(m5, m7); \ 108 | STORE16((in)[2 * 8], m5); \ 109 | STORE16((in)[6 * 8], m4); \ 110 | \ 111 | /* We should be multiplying m6 by C4 = 1/sqrt(2) here, but we only have */ \ 112 | /* the k2Sqrt2 = 1/(2.sqrt(2)) constant that fits into 15bits. So we */ \ 113 | /* shift by 4 instead of 3 to compensate for the additional 1/2 factor. */ \ 114 | LOAD_CST(m6, k2Sqrt2); \ 115 | LSHIFT(m2, 3 + 1); \ 116 | LSHIFT(m1, 3 + 1); \ 117 | BUTTERFLY(m1, m2); \ 118 | MULT(m2, m6); \ 119 | MULT(m1, m6); \ 120 | BUTTERFLY(m3, m1); \ 121 | BUTTERFLY(m0, m2); \ 122 | \ 123 | LOAD_CST(m4, kTan3m1); \ 124 | LOAD_CST(m5, kTan1); \ 125 | m7 = m3; \ 126 | m6 = m1; \ 127 | MULT(m3, m4); \ 128 | MULT(m1, m5); \ 129 | \ 130 | ADD(m3, m7); \ 131 | ADD(m1, m2); \ 132 | CORRECT_LSB(m1); \ 133 | CORRECT_LSB(m3); \ 134 | MULT(m4, m0); \ 135 | MULT(m5, m2); \ 136 | ADD(m4, m0); \ 137 | SUB(m0, m3); \ 138 | ADD(m7, m4); \ 139 | SUB(m5, m6); \ 140 | \ 141 | STORE16((in)[1 * 8], m1); \ 142 | STORE16((in)[3 * 8], m0); \ 143 | STORE16((in)[5 * 8], m7); \ 144 | STORE16((in)[7 * 8], m5); \ 145 | } while (0) 146 | 147 | 148 | // these are the macro required by COLUMN_* 149 | #define LOAD_CST(dst, src) (dst) = (src) 150 | #define LOAD(dst, src) (dst) = (src) 151 | #define MULT(a, b) (a) = (((a) * (b)) >> 16) 152 | #define ADD(a, b) (a) = (a) + (b) 153 | #define SUB(a, b) (a) = (a) - (b) 154 | #define LSHIFT(a, n) (a) = ((a) << (n)) 155 | #define STORE16(a, b) (a) = (b) 156 | #define CORRECT_LSB(a) (a) += 1 157 | 158 | // DCT vertical pass 159 | 160 | inline void ColumnDct(coeff_t* in) { 161 | for (int i = 0; i < 8; ++i) { 162 | int m0, m1, m2, m3, m4, m5, m6, m7; 163 | COLUMN_DCT8(in + i); 164 | } 165 | } 166 | 167 | // DCT horizontal pass 168 | 169 | // We don't really need to round before descaling, since we 170 | // still have 4 bits of precision left as final scaled output. 171 | #define DESCALE(a) static_cast((a) >> 16) 172 | 173 | void RowDct(coeff_t* in, const coeff_t* table) { 174 | // The Fourier transform is an unitary operator, so we're basically 175 | // doing the transpose of RowIdct() 176 | const int a0 = in[0] + in[7]; 177 | const int b0 = in[0] - in[7]; 178 | const int a1 = in[1] + in[6]; 179 | const int b1 = in[1] - in[6]; 180 | const int a2 = in[2] + in[5]; 181 | const int b2 = in[2] - in[5]; 182 | const int a3 = in[3] + in[4]; 183 | const int b3 = in[3] - in[4]; 184 | 185 | // even part 186 | const int C2 = table[1]; 187 | const int C4 = table[3]; 188 | const int C6 = table[5]; 189 | const int c0 = a0 + a3; 190 | const int c1 = a0 - a3; 191 | const int c2 = a1 + a2; 192 | const int c3 = a1 - a2; 193 | 194 | in[0] = DESCALE(C4 * (c0 + c2)); 195 | in[4] = DESCALE(C4 * (c0 - c2)); 196 | in[2] = DESCALE(C2 * c1 + C6 * c3); 197 | in[6] = DESCALE(C6 * c1 - C2 * c3); 198 | 199 | // odd part 200 | const int C1 = table[0]; 201 | const int C3 = table[2]; 202 | const int C5 = table[4]; 203 | const int C7 = table[6]; 204 | in[1] = DESCALE(C1 * b0 + C3 * b1 + C5 * b2 + C7 * b3); 205 | in[3] = DESCALE(C3 * b0 - C7 * b1 - C1 * b2 - C5 * b3); 206 | in[5] = DESCALE(C5 * b0 - C1 * b1 + C7 * b2 + C3 * b3); 207 | in[7] = DESCALE(C7 * b0 - C5 * b1 + C3 * b2 - C1 * b3); 208 | } 209 | #undef DESCALE 210 | #undef LOAD_CST 211 | #undef LOAD 212 | #undef MULT 213 | #undef ADD 214 | #undef SUB 215 | #undef LSHIFT 216 | #undef STORE16 217 | #undef CORRECT_LSB 218 | #undef kTan1 219 | #undef kTan2 220 | #undef kTan3m1 221 | #undef k2Sqrt2 222 | #undef BUTTERFLY 223 | #undef COLUMN_DCT8 224 | 225 | } // namespace 226 | 227 | /////////////////////////////////////////////////////////////////////////////// 228 | // visible FDCT callable functions 229 | 230 | void ComputeBlockDCT(coeff_t* coeffs) { 231 | ColumnDct(coeffs); 232 | RowDct(coeffs + 0 * 8, kTable04); 233 | RowDct(coeffs + 1 * 8, kTable17); 234 | RowDct(coeffs + 2 * 8, kTable26); 235 | RowDct(coeffs + 3 * 8, kTable35); 236 | RowDct(coeffs + 4 * 8, kTable04); 237 | RowDct(coeffs + 5 * 8, kTable35); 238 | RowDct(coeffs + 6 * 8, kTable26); 239 | RowDct(coeffs + 7 * 8, kTable17); 240 | } 241 | 242 | } // namespace guetzli 243 | -------------------------------------------------------------------------------- /guetzli/fdct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_FDCT_H_ 18 | #define GUETZLI_FDCT_H_ 19 | 20 | #include "guetzli/jpeg_data.h" 21 | 22 | namespace guetzli { 23 | 24 | // Computes the DCT (Discrete Cosine Transform) of the 8x8 array in 'block', 25 | // scaled up by a factor of 16. The values in 'block' are laid out row-by-row 26 | // and the result is written to the same memory area. 27 | void ComputeBlockDCT(coeff_t* block); 28 | 29 | } // namespace guetzli 30 | 31 | #endif // GUETZLI_FDCT_H_ 32 | -------------------------------------------------------------------------------- /guetzli/gamma_correct.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/gamma_correct.h" 18 | 19 | #include 20 | 21 | namespace guetzli { 22 | 23 | const double* NewSrgb8ToLinearTable() { 24 | double* table = new double[256]; 25 | int i = 0; 26 | for (; i < 11; ++i) { 27 | table[i] = i / 12.92; 28 | } 29 | for (; i < 256; ++i) { 30 | table[i] = 255.0 * std::pow(((i / 255.0) + 0.055) / 1.055, 2.4); 31 | } 32 | return table; 33 | } 34 | 35 | const double* Srgb8ToLinearTable() { 36 | static const double* const kSrgb8ToLinearTable = NewSrgb8ToLinearTable(); 37 | return kSrgb8ToLinearTable; 38 | } 39 | 40 | } // namespace guetzli 41 | -------------------------------------------------------------------------------- /guetzli/gamma_correct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_GAMMA_CORRECT_H_ 18 | #define GUETZLI_GAMMA_CORRECT_H_ 19 | 20 | namespace guetzli { 21 | 22 | const double* Srgb8ToLinearTable(); 23 | 24 | } // namespace guetzli 25 | 26 | #endif // GUETZLI_GAMMA_CORRECT_H_ 27 | -------------------------------------------------------------------------------- /guetzli/guetzli.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "png.h" 26 | #include "guetzli/jpeg_data.h" 27 | #include "guetzli/jpeg_data_reader.h" 28 | #include "guetzli/processor.h" 29 | #include "guetzli/quality.h" 30 | #include "guetzli/stats.h" 31 | 32 | namespace { 33 | 34 | constexpr int kDefaultJPEGQuality = 95; 35 | 36 | // An upper estimate of memory usage of Guetzli. The bound is 37 | // max(kLowerMemusaeMB * 1<<20, pixel_count * kBytesPerPixel) 38 | constexpr int kBytesPerPixel = 350; 39 | constexpr int kLowestMemusageMB = 100; // in MB 40 | 41 | constexpr int kDefaultMemlimitMB = 6000; // in MB 42 | 43 | inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) { 44 | return (static_cast(val) * static_cast(alpha) + 128) / 255; 45 | } 46 | 47 | bool ReadPNG(const std::string& data, int* xsize, int* ysize, 48 | std::vector* rgb) { 49 | png_structp png_ptr = 50 | png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 51 | if (!png_ptr) { 52 | return false; 53 | } 54 | 55 | png_infop info_ptr = png_create_info_struct(png_ptr); 56 | if (!info_ptr) { 57 | png_destroy_read_struct(&png_ptr, nullptr, nullptr); 58 | return false; 59 | } 60 | 61 | if (setjmp(png_jmpbuf(png_ptr)) != 0) { 62 | // Ok we are here because of the setjmp. 63 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); 64 | return false; 65 | } 66 | 67 | std::istringstream memstream(data, std::ios::in | std::ios::binary); 68 | png_set_read_fn(png_ptr, static_cast(&memstream), [](png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) { 69 | std::istringstream& memstream = *static_cast(png_get_io_ptr(png_ptr)); 70 | 71 | memstream.read(reinterpret_cast(outBytes), byteCountToRead); 72 | 73 | if (memstream.eof()) png_error(png_ptr, "unexpected end of data"); 74 | if (memstream.fail()) png_error(png_ptr, "read from memory error"); 75 | }); 76 | 77 | // The png_transforms flags are as follows: 78 | // packing == convert 1,2,4 bit images, 79 | // strip == 16 -> 8 bits / channel, 80 | // shift == use sBIT dynamics, and 81 | // expand == palettes -> rgb, grayscale -> 8 bit images, tRNS -> alpha. 82 | const unsigned int png_transforms = 83 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16; 84 | 85 | png_read_png(png_ptr, info_ptr, png_transforms, nullptr); 86 | 87 | png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); 88 | 89 | *xsize = png_get_image_width(png_ptr, info_ptr); 90 | *ysize = png_get_image_height(png_ptr, info_ptr); 91 | rgb->resize(3 * (*xsize) * (*ysize)); 92 | 93 | const int components = png_get_channels(png_ptr, info_ptr); 94 | switch (components) { 95 | case 1: { 96 | // GRAYSCALE 97 | for (int y = 0; y < *ysize; ++y) { 98 | const uint8_t* row_in = row_pointers[y]; 99 | uint8_t* row_out = &(*rgb)[3 * y * (*xsize)]; 100 | for (int x = 0; x < *xsize; ++x) { 101 | const uint8_t gray = row_in[x]; 102 | row_out[3 * x + 0] = gray; 103 | row_out[3 * x + 1] = gray; 104 | row_out[3 * x + 2] = gray; 105 | } 106 | } 107 | break; 108 | } 109 | case 2: { 110 | // GRAYSCALE + ALPHA 111 | for (int y = 0; y < *ysize; ++y) { 112 | const uint8_t* row_in = row_pointers[y]; 113 | uint8_t* row_out = &(*rgb)[3 * y * (*xsize)]; 114 | for (int x = 0; x < *xsize; ++x) { 115 | const uint8_t gray = BlendOnBlack(row_in[2 * x], row_in[2 * x + 1]); 116 | row_out[3 * x + 0] = gray; 117 | row_out[3 * x + 1] = gray; 118 | row_out[3 * x + 2] = gray; 119 | } 120 | } 121 | break; 122 | } 123 | case 3: { 124 | // RGB 125 | for (int y = 0; y < *ysize; ++y) { 126 | const uint8_t* row_in = row_pointers[y]; 127 | uint8_t* row_out = &(*rgb)[3 * y * (*xsize)]; 128 | memcpy(row_out, row_in, 3 * (*xsize)); 129 | } 130 | break; 131 | } 132 | case 4: { 133 | // RGBA 134 | for (int y = 0; y < *ysize; ++y) { 135 | const uint8_t* row_in = row_pointers[y]; 136 | uint8_t* row_out = &(*rgb)[3 * y * (*xsize)]; 137 | for (int x = 0; x < *xsize; ++x) { 138 | const uint8_t alpha = row_in[4 * x + 3]; 139 | row_out[3 * x + 0] = BlendOnBlack(row_in[4 * x + 0], alpha); 140 | row_out[3 * x + 1] = BlendOnBlack(row_in[4 * x + 1], alpha); 141 | row_out[3 * x + 2] = BlendOnBlack(row_in[4 * x + 2], alpha); 142 | } 143 | } 144 | break; 145 | } 146 | default: 147 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); 148 | return false; 149 | } 150 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); 151 | return true; 152 | } 153 | 154 | std::string ReadFileOrDie(const char* filename) { 155 | bool read_from_stdin = strncmp(filename, "-", 2) == 0; 156 | 157 | FILE* f = read_from_stdin ? stdin : fopen(filename, "rb"); 158 | if (!f) { 159 | perror("Can't open input file"); 160 | exit(1); 161 | } 162 | 163 | std::string result; 164 | off_t buffer_size = 8192; 165 | 166 | if (fseek(f, 0, SEEK_END) == 0) { 167 | buffer_size = std::max(ftell(f), 1); 168 | if (fseek(f, 0, SEEK_SET) != 0) { 169 | perror("fseek"); 170 | exit(1); 171 | } 172 | } else if (ferror(f)) { 173 | perror("fseek"); 174 | exit(1); 175 | } 176 | 177 | std::unique_ptr buf(new char[buffer_size]); 178 | while (!feof(f)) { 179 | size_t read_bytes = fread(buf.get(), sizeof(char), buffer_size, f); 180 | if (ferror(f)) { 181 | perror("fread"); 182 | exit(1); 183 | } 184 | result.append(buf.get(), read_bytes); 185 | } 186 | 187 | fclose(f); 188 | return result; 189 | } 190 | 191 | void WriteFileOrDie(const char* filename, const std::string& contents) { 192 | bool write_to_stdout = strncmp(filename, "-", 2) == 0; 193 | 194 | FILE* f = write_to_stdout ? stdout : fopen(filename, "wb"); 195 | if (!f) { 196 | perror("Can't open output file for writing"); 197 | exit(1); 198 | } 199 | if (fwrite(contents.data(), 1, contents.size(), f) != contents.size()) { 200 | perror("fwrite"); 201 | exit(1); 202 | } 203 | if (fclose(f) < 0) { 204 | perror("fclose"); 205 | exit(1); 206 | } 207 | } 208 | 209 | void TerminateHandler() { 210 | fprintf(stderr, "Unhandled exception. Most likely insufficient memory available.\n" 211 | "Make sure that there is 300MB/MPix of memory available.\n"); 212 | exit(1); 213 | } 214 | 215 | void Usage() { 216 | fprintf(stderr, 217 | "Guetzli JPEG compressor. Usage: \n" 218 | "guetzli [flags] input_filename output_filename\n" 219 | "\n" 220 | "Flags:\n" 221 | " --verbose - Print a verbose trace of all attempts to standard output.\n" 222 | " --quality Q - Visual quality to aim for, expressed as a JPEG quality value.\n" 223 | " Default value is %d.\n" 224 | " --memlimit M - Memory limit in MB. Guetzli will fail if unable to stay under\n" 225 | " the limit. Default limit is %d MB.\n" 226 | " --nomemlimit - Do not limit memory usage.\n", kDefaultJPEGQuality, kDefaultMemlimitMB); 227 | exit(1); 228 | } 229 | 230 | } // namespace 231 | 232 | int main(int argc, char** argv) { 233 | std::set_terminate(TerminateHandler); 234 | 235 | int verbose = 0; 236 | int quality = kDefaultJPEGQuality; 237 | int memlimit_mb = kDefaultMemlimitMB; 238 | 239 | int opt_idx = 1; 240 | for(;opt_idx < argc;opt_idx++) { 241 | if (strnlen(argv[opt_idx], 2) < 2 || argv[opt_idx][0] != '-' || argv[opt_idx][1] != '-') 242 | break; 243 | if (!strcmp(argv[opt_idx], "--verbose")) { 244 | verbose = 1; 245 | } else if (!strcmp(argv[opt_idx], "--quality")) { 246 | opt_idx++; 247 | if (opt_idx >= argc) 248 | Usage(); 249 | quality = atoi(argv[opt_idx]); 250 | } else if (!strcmp(argv[opt_idx], "--memlimit")) { 251 | opt_idx++; 252 | if (opt_idx >= argc) 253 | Usage(); 254 | memlimit_mb = atoi(argv[opt_idx]); 255 | } else if (!strcmp(argv[opt_idx], "--nomemlimit")) { 256 | memlimit_mb = -1; 257 | } else if (!strcmp(argv[opt_idx], "--")) { 258 | opt_idx++; 259 | break; 260 | } else { 261 | fprintf(stderr, "Unknown commandline flag: %s\n", argv[opt_idx]); 262 | Usage(); 263 | } 264 | } 265 | 266 | if (argc - opt_idx != 2) { 267 | Usage(); 268 | } 269 | 270 | std::string in_data = ReadFileOrDie(argv[opt_idx]); 271 | std::string out_data; 272 | 273 | guetzli::Params params; 274 | params.butteraugli_target = static_cast( 275 | guetzli::ButteraugliScoreForQuality(quality)); 276 | 277 | guetzli::ProcessStats stats; 278 | 279 | if (verbose) { 280 | stats.debug_output_file = stderr; 281 | } 282 | 283 | static const unsigned char kPNGMagicBytes[] = { 284 | 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 285 | }; 286 | if (in_data.size() >= 8 && 287 | memcmp(in_data.data(), kPNGMagicBytes, sizeof(kPNGMagicBytes)) == 0) { 288 | int xsize, ysize; 289 | std::vector rgb; 290 | if (!ReadPNG(in_data, &xsize, &ysize, &rgb)) { 291 | fprintf(stderr, "Error reading PNG data from input file\n"); 292 | return 1; 293 | } 294 | double pixels = static_cast(xsize) * ysize; 295 | if (memlimit_mb != -1 296 | && (pixels * kBytesPerPixel / (1 << 20) > memlimit_mb 297 | || memlimit_mb < kLowestMemusageMB)) { 298 | fprintf(stderr, "Memory limit would be exceeded. Failing.\n"); 299 | return 1; 300 | } 301 | if (!guetzli::Process(params, &stats, rgb, xsize, ysize, &out_data)) { 302 | fprintf(stderr, "Guetzli processing failed\n"); 303 | return 1; 304 | } 305 | } else { 306 | guetzli::JPEGData jpg_header; 307 | if (!guetzli::ReadJpeg(in_data, guetzli::JPEG_READ_HEADER, &jpg_header)) { 308 | fprintf(stderr, "Error reading JPG data from input file\n"); 309 | return 1; 310 | } 311 | double pixels = static_cast(jpg_header.width) * jpg_header.height; 312 | if (memlimit_mb != -1 313 | && (pixels * kBytesPerPixel / (1 << 20) > memlimit_mb 314 | || memlimit_mb < kLowestMemusageMB)) { 315 | fprintf(stderr, "Memory limit would be exceeded. Failing.\n"); 316 | return 1; 317 | } 318 | if (!guetzli::Process(params, &stats, in_data, &out_data)) { 319 | fprintf(stderr, "Guetzli processing failed\n"); 320 | return 1; 321 | } 322 | } 323 | 324 | WriteFileOrDie(argv[opt_idx + 1], out_data); 325 | return 0; 326 | } 327 | -------------------------------------------------------------------------------- /guetzli/idct.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Integer implementation of the Inverse Discrete Cosine Transform (IDCT). 18 | 19 | #include "guetzli/idct.h" 20 | 21 | #include 22 | #include 23 | 24 | namespace guetzli { 25 | 26 | // kIDCTMatrix[8*x+u] = alpha(u)*cos((2*x+1)*u*M_PI/16)*sqrt(2), with fixed 13 27 | // bit precision, where alpha(0) = 1/sqrt(2) and alpha(u) = 1 for u > 0. 28 | // Some coefficients are off by +-1 to mimick libjpeg's behaviour. 29 | static const int kIDCTMatrix[kDCTBlockSize] = { 30 | 8192, 11363, 10703, 9633, 8192, 6437, 4433, 2260, 31 | 8192, 9633, 4433, -2259, -8192, -11362, -10704, -6436, 32 | 8192, 6437, -4433, -11362, -8192, 2261, 10704, 9633, 33 | 8192, 2260, -10703, -6436, 8192, 9633, -4433, -11363, 34 | 8192, -2260, -10703, 6436, 8192, -9633, -4433, 11363, 35 | 8192, -6437, -4433, 11362, -8192, -2261, 10704, -9633, 36 | 8192, -9633, 4433, 2259, -8192, 11362, -10704, 6436, 37 | 8192, -11363, 10703, -9633, 8192, -6437, 4433, -2260, 38 | }; 39 | 40 | // Computes out[x] = sum{kIDCTMatrix[8*x+u]*in[u*stride]; for u in [0..7]} 41 | inline void Compute1dIDCT(const coeff_t* in, const int stride, int out[8]) { 42 | int tmp0, tmp1, tmp2, tmp3, tmp4; 43 | 44 | tmp1 = kIDCTMatrix[0] * in[0]; 45 | out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = tmp1; 46 | 47 | tmp0 = in[stride]; 48 | tmp1 = kIDCTMatrix[ 1] * tmp0; 49 | tmp2 = kIDCTMatrix[ 9] * tmp0; 50 | tmp3 = kIDCTMatrix[17] * tmp0; 51 | tmp4 = kIDCTMatrix[25] * tmp0; 52 | out[0] += tmp1; 53 | out[1] += tmp2; 54 | out[2] += tmp3; 55 | out[3] += tmp4; 56 | out[4] -= tmp4; 57 | out[5] -= tmp3; 58 | out[6] -= tmp2; 59 | out[7] -= tmp1; 60 | 61 | tmp0 = in[2 * stride]; 62 | tmp1 = kIDCTMatrix[ 2] * tmp0; 63 | tmp2 = kIDCTMatrix[10] * tmp0; 64 | out[0] += tmp1; 65 | out[1] += tmp2; 66 | out[2] -= tmp2; 67 | out[3] -= tmp1; 68 | out[4] -= tmp1; 69 | out[5] -= tmp2; 70 | out[6] += tmp2; 71 | out[7] += tmp1; 72 | 73 | tmp0 = in[3 * stride]; 74 | tmp1 = kIDCTMatrix[ 3] * tmp0; 75 | tmp2 = kIDCTMatrix[11] * tmp0; 76 | tmp3 = kIDCTMatrix[19] * tmp0; 77 | tmp4 = kIDCTMatrix[27] * tmp0; 78 | out[0] += tmp1; 79 | out[1] += tmp2; 80 | out[2] += tmp3; 81 | out[3] += tmp4; 82 | out[4] -= tmp4; 83 | out[5] -= tmp3; 84 | out[6] -= tmp2; 85 | out[7] -= tmp1; 86 | 87 | tmp0 = in[4 * stride]; 88 | tmp1 = kIDCTMatrix[ 4] * tmp0; 89 | out[0] += tmp1; 90 | out[1] -= tmp1; 91 | out[2] -= tmp1; 92 | out[3] += tmp1; 93 | out[4] += tmp1; 94 | out[5] -= tmp1; 95 | out[6] -= tmp1; 96 | out[7] += tmp1; 97 | 98 | tmp0 = in[5 * stride]; 99 | tmp1 = kIDCTMatrix[ 5] * tmp0; 100 | tmp2 = kIDCTMatrix[13] * tmp0; 101 | tmp3 = kIDCTMatrix[21] * tmp0; 102 | tmp4 = kIDCTMatrix[29] * tmp0; 103 | out[0] += tmp1; 104 | out[1] += tmp2; 105 | out[2] += tmp3; 106 | out[3] += tmp4; 107 | out[4] -= tmp4; 108 | out[5] -= tmp3; 109 | out[6] -= tmp2; 110 | out[7] -= tmp1; 111 | 112 | tmp0 = in[6 * stride]; 113 | tmp1 = kIDCTMatrix[ 6] * tmp0; 114 | tmp2 = kIDCTMatrix[14] * tmp0; 115 | out[0] += tmp1; 116 | out[1] += tmp2; 117 | out[2] -= tmp2; 118 | out[3] -= tmp1; 119 | out[4] -= tmp1; 120 | out[5] -= tmp2; 121 | out[6] += tmp2; 122 | out[7] += tmp1; 123 | 124 | tmp0 = in[7 * stride]; 125 | tmp1 = kIDCTMatrix[ 7] * tmp0; 126 | tmp2 = kIDCTMatrix[15] * tmp0; 127 | tmp3 = kIDCTMatrix[23] * tmp0; 128 | tmp4 = kIDCTMatrix[31] * tmp0; 129 | out[0] += tmp1; 130 | out[1] += tmp2; 131 | out[2] += tmp3; 132 | out[3] += tmp4; 133 | out[4] -= tmp4; 134 | out[5] -= tmp3; 135 | out[6] -= tmp2; 136 | out[7] -= tmp1; 137 | } 138 | 139 | void ComputeBlockIDCT(const coeff_t* block, uint8_t* out) { 140 | coeff_t colidcts[kDCTBlockSize]; 141 | const int kColScale = 11; 142 | const int kColRound = 1 << (kColScale - 1); 143 | for (int x = 0; x < 8; ++x) { 144 | int colbuf[8] = { 0 }; 145 | Compute1dIDCT(&block[x], 8, colbuf); 146 | for (int y = 0; y < 8; ++y) { 147 | colidcts[8 * y + x] = (colbuf[y] + kColRound) >> kColScale; 148 | } 149 | } 150 | const int kRowScale = 18; 151 | const int kRowRound = 257 << (kRowScale - 1); // includes offset by 128 152 | for (int y = 0; y < 8; ++y) { 153 | const int rowidx = 8 * y; 154 | int rowbuf[8] = { 0 }; 155 | Compute1dIDCT(&colidcts[rowidx], 1, rowbuf); 156 | for (int x = 0; x < 8; ++x) { 157 | out[rowidx + x] = 158 | std::max(0, std::min(255, (rowbuf[x] + kRowRound) >> kRowScale)); 159 | } 160 | } 161 | } 162 | 163 | } // namespace guetzli 164 | -------------------------------------------------------------------------------- /guetzli/idct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_IDCT_H_ 18 | #define GUETZLI_IDCT_H_ 19 | 20 | #include "guetzli/jpeg_data.h" 21 | 22 | namespace guetzli { 23 | 24 | // Fills in 'result' with the inverse DCT of 'block'. 25 | // The arguments 'block' and 'result' point to 8x8 arrays that are arranged in 26 | // a row-by-row memory layout. 27 | void ComputeBlockIDCT(const coeff_t* block, uint8_t* result); 28 | 29 | } // namespace guetzli 30 | 31 | #endif // GUETZLI_IDCT_H_ 32 | -------------------------------------------------------------------------------- /guetzli/jpeg_bit_writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_JPEG_BIT_WRITER_H_ 18 | #define GUETZLI_JPEG_BIT_WRITER_H_ 19 | 20 | #include 21 | #include 22 | 23 | namespace guetzli { 24 | 25 | // Returns non-zero if and only if x has a zero byte, i.e. one of 26 | // x & 0xff, x & 0xff00, ..., x & 0xff00000000000000 is zero. 27 | inline uint64_t HasZeroByte(uint64_t x) { 28 | return (x - 0x0101010101010101ULL) & ~x & 0x8080808080808080ULL; 29 | } 30 | 31 | // Handles the packing of bits into output bytes. 32 | struct BitWriter { 33 | explicit BitWriter(size_t length) : len(length), 34 | data(new uint8_t[len]), 35 | pos(0), 36 | put_buffer(0), 37 | put_bits(64), 38 | overflow(false) {} 39 | 40 | void WriteBits(int nbits, uint64_t bits) { 41 | put_bits -= nbits; 42 | put_buffer |= (bits << put_bits); 43 | if (put_bits <= 16) { 44 | // At this point we are ready to emit the most significant 6 bytes of 45 | // put_buffer_ to the output. 46 | // The JPEG format requires that after every 0xff byte in the entropy 47 | // coded section, there is a zero byte, therefore we first check if any of 48 | // the 6 most significant bytes of put_buffer_ is 0xff. 49 | if (HasZeroByte(~put_buffer | 0xffff)) { 50 | // We have a 0xff byte somewhere, examine each byte and append a zero 51 | // byte if necessary. 52 | EmitByte((put_buffer >> 56) & 0xff); 53 | EmitByte((put_buffer >> 48) & 0xff); 54 | EmitByte((put_buffer >> 40) & 0xff); 55 | EmitByte((put_buffer >> 32) & 0xff); 56 | EmitByte((put_buffer >> 24) & 0xff); 57 | EmitByte((put_buffer >> 16) & 0xff); 58 | } else if (pos + 6 < len) { 59 | // We don't have any 0xff bytes, output all 6 bytes without checking. 60 | data[pos] = (put_buffer >> 56) & 0xff; 61 | data[pos + 1] = (put_buffer >> 48) & 0xff; 62 | data[pos + 2] = (put_buffer >> 40) & 0xff; 63 | data[pos + 3] = (put_buffer >> 32) & 0xff; 64 | data[pos + 4] = (put_buffer >> 24) & 0xff; 65 | data[pos + 5] = (put_buffer >> 16) & 0xff; 66 | pos += 6; 67 | } else { 68 | overflow = true; 69 | } 70 | put_buffer <<= 48; 71 | put_bits += 48; 72 | } 73 | } 74 | 75 | // Writes the given byte to the output, writes an extra zero if byte is 0xff. 76 | void EmitByte(int byte) { 77 | if (pos < len) { 78 | data[pos++] = byte; 79 | } else { 80 | overflow = true; 81 | } 82 | if (byte == 0xff) { 83 | EmitByte(0); 84 | } 85 | } 86 | 87 | void JumpToByteBoundary() { 88 | while (put_bits <= 56) { 89 | int c = (put_buffer >> 56) & 0xff; 90 | EmitByte(c); 91 | put_buffer <<= 8; 92 | put_bits += 8; 93 | } 94 | if (put_bits < 64) { 95 | int padmask = 0xff >> (64 - put_bits); 96 | int c = ((put_buffer >> 56) & ~padmask) | padmask; 97 | EmitByte(c); 98 | } 99 | put_buffer = 0; 100 | put_bits = 64; 101 | } 102 | 103 | size_t len; 104 | std::unique_ptr data; 105 | size_t pos; 106 | uint64_t put_buffer; 107 | int put_bits; 108 | bool overflow; 109 | }; 110 | 111 | } // namespace guetzli 112 | 113 | #endif // GUETZLI_JPEG_BIT_WRITER_H_ 114 | -------------------------------------------------------------------------------- /guetzli/jpeg_data.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/jpeg_data.h" 18 | 19 | #include 20 | #include 21 | 22 | namespace guetzli { 23 | 24 | bool JPEGData::Is420() const { 25 | return (components.size() == 3 && 26 | max_h_samp_factor == 2 && 27 | max_v_samp_factor == 2 && 28 | components[0].h_samp_factor == 2 && 29 | components[0].v_samp_factor == 2 && 30 | components[1].h_samp_factor == 1 && 31 | components[1].v_samp_factor == 1 && 32 | components[2].h_samp_factor == 1 && 33 | components[2].v_samp_factor == 1); 34 | } 35 | 36 | bool JPEGData::Is444() const { 37 | return (components.size() == 3 && 38 | max_h_samp_factor == 1 && 39 | max_v_samp_factor == 1 && 40 | components[0].h_samp_factor == 1 && 41 | components[0].v_samp_factor == 1 && 42 | components[1].h_samp_factor == 1 && 43 | components[1].v_samp_factor == 1 && 44 | components[2].h_samp_factor == 1 && 45 | components[2].v_samp_factor == 1); 46 | } 47 | 48 | void InitJPEGDataForYUV444(int w, int h, JPEGData* jpg) { 49 | jpg->width = w; 50 | jpg->height = h; 51 | jpg->max_h_samp_factor = 1; 52 | jpg->max_v_samp_factor = 1; 53 | jpg->MCU_rows = (h + 7) >> 3; 54 | jpg->MCU_cols = (w + 7) >> 3; 55 | jpg->quant.resize(3); 56 | jpg->components.resize(3); 57 | for (int i = 0; i < 3; ++i) { 58 | JPEGComponent* c = &jpg->components[i]; 59 | c->id = i; 60 | c->h_samp_factor = 1; 61 | c->v_samp_factor = 1; 62 | c->quant_idx = i; 63 | c->width_in_blocks = jpg->MCU_cols; 64 | c->height_in_blocks = jpg->MCU_rows; 65 | c->num_blocks = c->width_in_blocks * c->height_in_blocks; 66 | c->coeffs.resize(c->num_blocks * kDCTBlockSize); 67 | } 68 | } 69 | 70 | void SaveQuantTables(const int q[3][kDCTBlockSize], JPEGData* jpg) { 71 | const size_t kTableSize = kDCTBlockSize * sizeof(q[0][0]); 72 | jpg->quant.clear(); 73 | int num_tables = 0; 74 | for (size_t i = 0; i < jpg->components.size(); ++i) { 75 | JPEGComponent* comp = &jpg->components[i]; 76 | // Check if we have this quant table already. 77 | bool found = false; 78 | for (int j = 0; j < num_tables; ++j) { 79 | if (memcmp(&q[i][0], &jpg->quant[j].values[0], kTableSize) == 0) { 80 | comp->quant_idx = j; 81 | found = true; 82 | break; 83 | } 84 | } 85 | if (!found) { 86 | JPEGQuantTable table; 87 | memcpy(&table.values[0], &q[i][0], kTableSize); 88 | table.precision = 0; 89 | for (int k = 0; k < kDCTBlockSize; ++k) { 90 | assert(table.values[k] >= 0); 91 | assert(table.values[k] < (1 << 16)); 92 | if (table.values[k] > 0xff) { 93 | table.precision = 1; 94 | } 95 | } 96 | table.index = num_tables; 97 | comp->quant_idx = num_tables; 98 | jpg->quant.push_back(table); 99 | ++num_tables; 100 | } 101 | } 102 | } 103 | 104 | } // namespace guetzli 105 | -------------------------------------------------------------------------------- /guetzli/jpeg_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Data structures that represent the contents of a jpeg file. 18 | 19 | #ifndef GUETZLI_JPEG_DATA_H_ 20 | #define GUETZLI_JPEG_DATA_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "guetzli/jpeg_error.h" 28 | 29 | namespace guetzli { 30 | 31 | static const int kDCTBlockSize = 64; 32 | static const int kMaxComponents = 4; 33 | static const int kMaxQuantTables = 4; 34 | static const int kMaxHuffmanTables = 4; 35 | static const int kJpegHuffmanMaxBitLength = 16; 36 | static const int kJpegHuffmanAlphabetSize = 256; 37 | static const int kJpegDCAlphabetSize = 12; 38 | static const int kMaxDHTMarkers = 512; 39 | 40 | static const uint8_t kDefaultQuantMatrix[2][64] = { 41 | { 16, 11, 10, 16, 24, 40, 51, 61, 42 | 12, 12, 14, 19, 26, 58, 60, 55, 43 | 14, 13, 16, 24, 40, 57, 69, 56, 44 | 14, 17, 22, 29, 51, 87, 80, 62, 45 | 18, 22, 37, 56, 68, 109, 103, 77, 46 | 24, 35, 55, 64, 81, 104, 113, 92, 47 | 49, 64, 78, 87, 103, 121, 120, 101, 48 | 72, 92, 95, 98, 112, 100, 103, 99 }, 49 | { 17, 18, 24, 47, 99, 99, 99, 99, 50 | 18, 21, 26, 66, 99, 99, 99, 99, 51 | 24, 26, 56, 99, 99, 99, 99, 99, 52 | 47, 66, 99, 99, 99, 99, 99, 99, 53 | 99, 99, 99, 99, 99, 99, 99, 99, 54 | 99, 99, 99, 99, 99, 99, 99, 99, 55 | 99, 99, 99, 99, 99, 99, 99, 99, 56 | 99, 99, 99, 99, 99, 99, 99, 99 } 57 | }; 58 | 59 | const int kJPEGNaturalOrder[80] = { 60 | 0, 1, 8, 16, 9, 2, 3, 10, 61 | 17, 24, 32, 25, 18, 11, 4, 5, 62 | 12, 19, 26, 33, 40, 48, 41, 34, 63 | 27, 20, 13, 6, 7, 14, 21, 28, 64 | 35, 42, 49, 56, 57, 50, 43, 36, 65 | 29, 22, 15, 23, 30, 37, 44, 51, 66 | 58, 59, 52, 45, 38, 31, 39, 46, 67 | 53, 60, 61, 54, 47, 55, 62, 63, 68 | // extra entries for safety in decoder 69 | 63, 63, 63, 63, 63, 63, 63, 63, 70 | 63, 63, 63, 63, 63, 63, 63, 63 71 | }; 72 | 73 | const int kJPEGZigZagOrder[64] = { 74 | 0, 1, 5, 6, 14, 15, 27, 28, 75 | 2, 4, 7, 13, 16, 26, 29, 42, 76 | 3, 8, 12, 17, 25, 30, 41, 43, 77 | 9, 11, 18, 24, 31, 40, 44, 53, 78 | 10, 19, 23, 32, 39, 45, 52, 54, 79 | 20, 22, 33, 38, 46, 51, 55, 60, 80 | 21, 34, 37, 47, 50, 56, 59, 61, 81 | 35, 36, 48, 49, 57, 58, 62, 63 82 | }; 83 | 84 | // Quantization values for an 8x8 pixel block. 85 | struct JPEGQuantTable { 86 | JPEGQuantTable() : values(kDCTBlockSize), precision(0), 87 | index(0), is_last(true) {} 88 | 89 | std::vector values; 90 | int precision; 91 | // The index of this quantization table as it was parsed from the input JPEG. 92 | // Each DQT marker segment contains an 'index' field, and we save this index 93 | // here. Valid values are 0 to 3. 94 | int index; 95 | // Set to true if this table is the last one within its marker segment. 96 | bool is_last; 97 | }; 98 | 99 | // Huffman code and decoding lookup table used for DC and AC coefficients. 100 | struct JPEGHuffmanCode { 101 | JPEGHuffmanCode() : counts(kJpegHuffmanMaxBitLength + 1), 102 | values(kJpegHuffmanAlphabetSize + 1), 103 | slot_id(0), 104 | is_last(true) {} 105 | 106 | // Bit length histogram. 107 | std::vector counts; 108 | // Symbol values sorted by increasing bit lengths. 109 | std::vector values; 110 | // The index of the Huffman code in the current set of Huffman codes. For AC 111 | // component Huffman codes, 0x10 is added to the index. 112 | int slot_id; 113 | // Set to true if this Huffman code is the last one within its marker segment. 114 | bool is_last; 115 | }; 116 | 117 | // Huffman table indexes used for one component of one scan. 118 | struct JPEGComponentScanInfo { 119 | int comp_idx; 120 | int dc_tbl_idx; 121 | int ac_tbl_idx; 122 | }; 123 | 124 | // Contains information that is used in one scan. 125 | struct JPEGScanInfo { 126 | // Parameters used for progressive scans (named the same way as in the spec): 127 | // Ss : Start of spectral band in zig-zag sequence. 128 | // Se : End of spectral band in zig-zag sequence. 129 | // Ah : Successive approximation bit position, high. 130 | // Al : Successive approximation bit position, low. 131 | int Ss; 132 | int Se; 133 | int Ah; 134 | int Al; 135 | std::vector components; 136 | }; 137 | 138 | typedef int16_t coeff_t; 139 | 140 | // Represents one component of a jpeg file. 141 | struct JPEGComponent { 142 | JPEGComponent() : id(0), 143 | h_samp_factor(1), 144 | v_samp_factor(1), 145 | quant_idx(0), 146 | width_in_blocks(0), 147 | height_in_blocks(0) {} 148 | 149 | // One-byte id of the component. 150 | int id; 151 | // Horizontal and vertical sampling factors. 152 | // In interleaved mode, each minimal coded unit (MCU) has 153 | // h_samp_factor x v_samp_factor DCT blocks from this component. 154 | int h_samp_factor; 155 | int v_samp_factor; 156 | // The index of the quantization table used for this component. 157 | size_t quant_idx; 158 | // The dimensions of the component measured in 8x8 blocks. 159 | int width_in_blocks; 160 | int height_in_blocks; 161 | int num_blocks; 162 | // The DCT coefficients of this component, laid out block-by-block, divided 163 | // through the quantization matrix values. 164 | std::vector coeffs; 165 | }; 166 | 167 | // Represents a parsed jpeg file. 168 | struct JPEGData { 169 | JPEGData() : width(0), 170 | height(0), 171 | version(0), 172 | max_h_samp_factor(1), 173 | max_v_samp_factor(1), 174 | MCU_rows(0), 175 | MCU_cols(0), 176 | restart_interval(0), 177 | original_jpg(NULL), 178 | original_jpg_size(0), 179 | error(JPEG_OK) {} 180 | 181 | bool Is420() const; 182 | bool Is444() const; 183 | 184 | int width; 185 | int height; 186 | int version; 187 | int max_h_samp_factor; 188 | int max_v_samp_factor; 189 | int MCU_rows; 190 | int MCU_cols; 191 | int restart_interval; 192 | std::vector app_data; 193 | std::vector com_data; 194 | std::vector quant; 195 | std::vector huffman_code; 196 | std::vector components; 197 | std::vector scan_info; 198 | std::vector marker_order; 199 | std::vector inter_marker_data; 200 | std::string tail_data; 201 | const uint8_t* original_jpg; 202 | size_t original_jpg_size; 203 | JPEGReadError error; 204 | }; 205 | 206 | void InitJPEGDataForYUV444(int w, int h, JPEGData* jpg); 207 | void SaveQuantTables(const int q[3][kDCTBlockSize], JPEGData* jpg); 208 | 209 | } // namespace guetzli 210 | 211 | #endif // GUETZLI_JPEG_DATA_H_ 212 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_decoder.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/jpeg_data_decoder.h" 18 | 19 | #include "guetzli/output_image.h" 20 | 21 | namespace guetzli { 22 | 23 | // Mimic libjpeg's heuristics to guess jpeg color space. 24 | // Requires that the jpg has 3 components. 25 | bool HasYCbCrColorSpace(const JPEGData& jpg) { 26 | bool has_Adobe_marker = false; 27 | uint8_t Adobe_transform = 0; 28 | for (const std::string& app : jpg.app_data) { 29 | if (static_cast(app[0]) == 0xe0) { 30 | return true; 31 | } else if (static_cast(app[0]) == 0xee && app.size() >= 15) { 32 | has_Adobe_marker = true; 33 | Adobe_transform = app[14]; 34 | } 35 | } 36 | if (has_Adobe_marker) { 37 | return (Adobe_transform != 0); 38 | } 39 | const int cid0 = jpg.components[0].id; 40 | const int cid1 = jpg.components[1].id; 41 | const int cid2 = jpg.components[2].id; 42 | return (cid0 != 'R' || cid1 != 'G' || cid2 != 'B'); 43 | } 44 | 45 | std::vector DecodeJpegToRGB(const JPEGData& jpg) { 46 | if (jpg.components.size() == 1 || 47 | (jpg.components.size() == 3 && 48 | HasYCbCrColorSpace(jpg) && (jpg.Is420() || jpg.Is444()))) { 49 | OutputImage img(jpg.width, jpg.height); 50 | img.CopyFromJpegData(jpg); 51 | return img.ToSRGB(); 52 | } 53 | return std::vector(); 54 | } 55 | 56 | } // namespace guetzli 57 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Library to decode jpeg coefficients into an RGB image. 18 | 19 | #ifndef GUETZLI_JPEG_DATA_DECODER_H_ 20 | #define GUETZLI_JPEG_DATA_DECODER_H_ 21 | 22 | #include 23 | 24 | #include "guetzli/jpeg_data.h" 25 | 26 | namespace guetzli { 27 | 28 | // Decodes the parsed jpeg coefficients into an RGB image. 29 | // There can be only either 1 or 3 image components, in either case, an RGB 30 | // output image will be generated. 31 | // Only YUV420 and YUV444 sampling factors are supported. 32 | // Vector will be empty if a decoding error occurred. 33 | std::vector DecodeJpegToRGB(const JPEGData& jpg); 34 | 35 | // Mimic libjpeg's heuristics to guess jpeg color space. 36 | // Requires that the jpg has 3 components. 37 | bool HasYCbCrColorSpace(const JPEGData& jpg); 38 | 39 | } // namespace guetzli 40 | 41 | #endif // GUETZLI_JPEG_DATA_DECODER_H_ 42 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_encoder.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/jpeg_data_encoder.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "guetzli/fdct.h" 23 | 24 | namespace guetzli { 25 | 26 | namespace { 27 | 28 | static const int kIQuantBits = 16; 29 | // Output of the DCT is upscaled by 16. 30 | static const int kDCTBits = kIQuantBits + 4; 31 | static const int kBias = 0x80 << (kDCTBits - 8); 32 | 33 | void Quantize(coeff_t* v, int iquant) { 34 | *v = (*v * iquant + kBias) >> kDCTBits; 35 | } 36 | 37 | // Single pixel rgb to 16-bit yuv conversion. 38 | // The returned yuv values are signed integers in the 39 | // range [-128, 127] inclusive. 40 | inline static void RGBToYUV16(const uint8_t* const rgb, 41 | coeff_t *out) { 42 | enum { FRAC = 16, HALF = 1 << (FRAC - 1) }; 43 | const int r = rgb[0]; 44 | const int g = rgb[1]; 45 | const int b = rgb[2]; 46 | out[0] = (19595 * r + 38469 * g + 7471 * b - (128 << 16) + HALF) >> FRAC; 47 | out[64] = (-11059 * r - 21709 * g + 32768 * b + HALF - 1) >> FRAC; 48 | out[128] = (32768 * r - 27439 * g - 5329 * b + HALF - 1) >> FRAC; 49 | } 50 | 51 | } // namespace 52 | 53 | void AddApp0Data(JPEGData* jpg) { 54 | const unsigned char kApp0Data[] = { 55 | 0xe0, 0x00, 0x10, // APP0 56 | 0x4a, 0x46, 0x49, 0x46, 0x00, // 'JFIF' 57 | 0x01, 0x01, // v1.01 58 | 0x00, 0x00, 0x01, 0x00, 0x01, // aspect ratio = 1:1 59 | 0x00, 0x00 // thumbnail width/height 60 | }; 61 | jpg->app_data.push_back( 62 | std::string(reinterpret_cast(kApp0Data), 63 | sizeof(kApp0Data))); 64 | } 65 | 66 | bool EncodeRGBToJpeg(const std::vector& rgb, int w, int h, 67 | const int* quant, JPEGData* jpg) { 68 | if (w < 0 || w >= 1 << 16 || h < 0 || h >= 1 << 16 || 69 | rgb.size() != 3 * w * h) { 70 | return false; 71 | } 72 | InitJPEGDataForYUV444(w, h, jpg); 73 | AddApp0Data(jpg); 74 | 75 | int iquant[3 * kDCTBlockSize]; 76 | int idx = 0; 77 | for (int i = 0; i < 3; ++i) { 78 | for (int j = 0; j < kDCTBlockSize; ++j) { 79 | int v = quant[idx]; 80 | jpg->quant[i].values[j] = v; 81 | iquant[idx++] = ((1 << kIQuantBits) + 1) / v; 82 | } 83 | } 84 | 85 | // Compute YUV444 DCT coefficients. 86 | int block_ix = 0; 87 | for (int block_y = 0; block_y < jpg->MCU_rows; ++block_y) { 88 | for (int block_x = 0; block_x < jpg->MCU_cols; ++block_x) { 89 | coeff_t block[3 * kDCTBlockSize]; 90 | // RGB->YUV transform. 91 | for (int iy = 0; iy < 8; ++iy) { 92 | for (int ix = 0; ix < 8; ++ix) { 93 | int y = std::min(h - 1, 8 * block_y + iy); 94 | int x = std::min(w - 1, 8 * block_x + ix); 95 | int p = y * w + x; 96 | RGBToYUV16(&rgb[3 * p], &block[8 * iy + ix]); 97 | } 98 | } 99 | // DCT 100 | for (int i = 0; i < 3; ++i) { 101 | ComputeBlockDCT(&block[i * kDCTBlockSize]); 102 | } 103 | // Quantization 104 | for (int i = 0; i < 3 * 64; ++i) { 105 | Quantize(&block[i], iquant[i]); 106 | } 107 | // Copy the resulting coefficients to *jpg. 108 | for (int i = 0; i < 3; ++i) { 109 | memcpy(&jpg->components[i].coeffs[block_ix * kDCTBlockSize], 110 | &block[i * kDCTBlockSize], kDCTBlockSize * sizeof(block[0])); 111 | } 112 | ++block_ix; 113 | } 114 | } 115 | 116 | return true; 117 | } 118 | 119 | bool EncodeRGBToJpeg(const std::vector& rgb, int w, int h, 120 | JPEGData* jpg) { 121 | static const int quant[3 * kDCTBlockSize] = { 122 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 123 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 124 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 125 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 126 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 127 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 128 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 129 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 130 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 131 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 132 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 133 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 134 | }; 135 | return EncodeRGBToJpeg(rgb, w, h, quant, jpg); 136 | } 137 | 138 | } // namespace guetzli 139 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_encoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_JPEG_DATA_ENCODER_H_ 18 | #define GUETZLI_JPEG_DATA_ENCODER_H_ 19 | 20 | #include 21 | 22 | #include "guetzli/jpeg_data.h" 23 | 24 | namespace guetzli { 25 | 26 | 27 | // Adds APP0 header data. 28 | void AddApp0Data(JPEGData* jpg); 29 | 30 | // Creates a JPEG from the rgb pixel data. Returns true on success. 31 | bool EncodeRGBToJpeg(const std::vector& rgb, int w, int h, 32 | JPEGData* jpg); 33 | 34 | // Creates a JPEG from the rgb pixel data. Returns true on success. The given 35 | // quantization table must have 3 * kDCTBlockSize values. 36 | bool EncodeRGBToJpeg(const std::vector& rgb, int w, int h, 37 | const int* quant, JPEGData* jpg); 38 | 39 | } // namespace guetzli 40 | 41 | #endif // GUETZLI_JPEG_DATA_ENCODER_H_ 42 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_reader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Functions for reading a jpeg byte stream into a JPEGData object. 18 | 19 | #ifndef GUETZLI_JPEG_DATA_READER_H_ 20 | #define GUETZLI_JPEG_DATA_READER_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "guetzli/jpeg_data.h" 28 | 29 | namespace guetzli { 30 | 31 | enum JpegReadMode { 32 | JPEG_READ_HEADER, // only basic headers 33 | JPEG_READ_TABLES, // headers and tables (quant, Huffman, ...) 34 | JPEG_READ_ALL, // everything 35 | }; 36 | 37 | // Parses the jpeg stream contained in data[*pos ... len) and fills in *jpg with 38 | // the parsed information. 39 | // If mode is JPEG_READ_HEADER, it fills in only the image dimensions in *jpg. 40 | // Returns false if the data is not valid jpeg, or if it contains an unsupported 41 | // jpeg feature. 42 | bool ReadJpeg(const uint8_t* data, const size_t len, JpegReadMode mode, 43 | JPEGData* jpg); 44 | // string variant 45 | bool ReadJpeg(const std::string& data, JpegReadMode mode, 46 | JPEGData* jpg); 47 | 48 | } // namespace guetzli 49 | 50 | #endif // GUETZLI_JPEG_DATA_READER_H_ 51 | -------------------------------------------------------------------------------- /guetzli/jpeg_data_writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Functions for writing a JPEGData object into a jpeg byte stream. 18 | 19 | #ifndef GUETZLI_JPEG_DATA_WRITER_H_ 20 | #define GUETZLI_JPEG_DATA_WRITER_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "guetzli/jpeg_data.h" 27 | 28 | namespace guetzli { 29 | 30 | // Function pointer type used to write len bytes into buf. Returns the 31 | // number of bytes written or -1 on error. 32 | typedef int (*JPEGOutputHook)(void* data, const uint8_t* buf, size_t len); 33 | 34 | // Output callback function with associated data. 35 | struct JPEGOutput { 36 | JPEGOutput(JPEGOutputHook cb, void* data) : cb(cb), data(data) {} 37 | bool Write(const uint8_t* buf, size_t len) const { 38 | return (len == 0) || (cb(data, buf, len) == len); 39 | } 40 | private: 41 | JPEGOutputHook cb; 42 | void* data; 43 | }; 44 | 45 | bool WriteJpeg(const JPEGData& jpg, bool strip_metadata, JPEGOutput out); 46 | 47 | struct HuffmanCodeTable { 48 | uint8_t depth[256]; 49 | int code[256]; 50 | }; 51 | 52 | void BuildSequentialHuffmanCodes( 53 | const JPEGData& jpg, std::vector* dc_huffman_code_tables, 54 | std::vector* ac_huffman_code_tables); 55 | 56 | struct JpegHistogram { 57 | static const int kSize = kJpegHuffmanAlphabetSize + 1; 58 | 59 | JpegHistogram() { Clear(); } 60 | void Clear() { 61 | memset(counts, 0, sizeof(counts)); 62 | counts[kSize - 1] = 1; 63 | } 64 | void Add(int symbol) { 65 | counts[symbol] += 2; 66 | } 67 | void Add(int symbol, int weight) { 68 | counts[symbol] += 2 * weight; 69 | } 70 | void AddHistogram(const JpegHistogram& other) { 71 | for (int i = 0; i + 1 < kSize; ++i) { 72 | counts[i] += other.counts[i]; 73 | } 74 | counts[kSize - 1] = 1; 75 | } 76 | int NumSymbols() const { 77 | int n = 0; 78 | for (int i = 0; i + 1 < kSize; ++i) { 79 | n += (counts[i] > 0 ? 1 : 0); 80 | } 81 | return n; 82 | } 83 | 84 | uint32_t counts[kSize]; 85 | }; 86 | 87 | void BuildDCHistograms(const JPEGData& jpg, JpegHistogram* histo); 88 | void BuildACHistograms(const JPEGData& jpg, JpegHistogram* histo); 89 | size_t JpegHeaderSize(const JPEGData& jpg, bool strip_metadata); 90 | size_t EstimateJpegDataSize(const int num_components, 91 | const std::vector& histograms); 92 | 93 | size_t HistogramEntropyCost(const JpegHistogram& histo, 94 | const uint8_t depths[256]); 95 | size_t HistogramHeaderCost(const JpegHistogram& histo); 96 | 97 | void UpdateACHistogramForDCTBlock(const coeff_t* coeffs, 98 | JpegHistogram* ac_histogram); 99 | 100 | size_t ClusterHistograms(JpegHistogram* histo, size_t* num, int* histo_indexes, 101 | uint8_t* depths); 102 | 103 | } // namespace guetzli 104 | 105 | #endif // GUETZLI_JPEG_DATA_WRITER_H_ 106 | -------------------------------------------------------------------------------- /guetzli/jpeg_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Definition of error codes for parsing jpeg files. 18 | 19 | #ifndef GUETZLI_JPEG_ERROR_H_ 20 | #define GUETZLI_JPEG_ERROR_H_ 21 | 22 | namespace guetzli { 23 | 24 | enum JPEGReadError { 25 | JPEG_OK = 0, 26 | JPEG_SOI_NOT_FOUND, 27 | JPEG_SOF_NOT_FOUND, 28 | JPEG_UNEXPECTED_EOF, 29 | JPEG_MARKER_BYTE_NOT_FOUND, 30 | JPEG_UNSUPPORTED_MARKER, 31 | JPEG_WRONG_MARKER_SIZE, 32 | JPEG_INVALID_PRECISION, 33 | JPEG_INVALID_WIDTH, 34 | JPEG_INVALID_HEIGHT, 35 | JPEG_INVALID_NUMCOMP, 36 | JPEG_INVALID_SAMP_FACTOR, 37 | JPEG_INVALID_START_OF_SCAN, 38 | JPEG_INVALID_END_OF_SCAN, 39 | JPEG_INVALID_SCAN_BIT_POSITION, 40 | JPEG_INVALID_COMPS_IN_SCAN, 41 | JPEG_INVALID_HUFFMAN_INDEX, 42 | JPEG_INVALID_QUANT_TBL_INDEX, 43 | JPEG_INVALID_QUANT_VAL, 44 | JPEG_INVALID_MARKER_LEN, 45 | JPEG_INVALID_SAMPLING_FACTORS, 46 | JPEG_INVALID_HUFFMAN_CODE, 47 | JPEG_INVALID_SYMBOL, 48 | JPEG_NON_REPRESENTABLE_DC_COEFF, 49 | JPEG_NON_REPRESENTABLE_AC_COEFF, 50 | JPEG_INVALID_SCAN, 51 | JPEG_OVERLAPPING_SCANS, 52 | JPEG_INVALID_SCAN_ORDER, 53 | JPEG_EXTRA_ZERO_RUN, 54 | JPEG_DUPLICATE_DRI, 55 | JPEG_DUPLICATE_SOF, 56 | JPEG_WRONG_RESTART_MARKER, 57 | JPEG_DUPLICATE_COMPONENT_ID, 58 | JPEG_COMPONENT_NOT_FOUND, 59 | JPEG_HUFFMAN_TABLE_NOT_FOUND, 60 | JPEG_HUFFMAN_TABLE_ERROR, 61 | JPEG_QUANT_TABLE_NOT_FOUND, 62 | JPEG_EMPTY_DHT, 63 | JPEG_EMPTY_DQT, 64 | JPEG_OUT_OF_BAND_COEFF, 65 | JPEG_EOB_RUN_TOO_LONG, 66 | JPEG_IMAGE_TOO_LARGE, 67 | }; 68 | 69 | } // namespace guetzli 70 | 71 | #endif // GUETZLI_JPEG_ERROR_H_ 72 | -------------------------------------------------------------------------------- /guetzli/jpeg_huffman_decode.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/jpeg_huffman_decode.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "guetzli/jpeg_data.h" 25 | 26 | namespace guetzli { 27 | 28 | // Returns the table width of the next 2nd level table, count is the histogram 29 | // of bit lengths for the remaining symbols, len is the code length of the next 30 | // processed symbol. 31 | static inline int NextTableBitSize(const int* count, int len) { 32 | int left = 1 << (len - kJpegHuffmanRootTableBits); 33 | while (len < kJpegHuffmanMaxBitLength) { 34 | left -= count[len]; 35 | if (left <= 0) break; 36 | ++len; 37 | left <<= 1; 38 | } 39 | return len - kJpegHuffmanRootTableBits; 40 | } 41 | 42 | int BuildJpegHuffmanTable(const int* count_in, const int* symbols, 43 | HuffmanTableEntry* lut) { 44 | HuffmanTableEntry code; // current table entry 45 | HuffmanTableEntry* table; // next available space in table 46 | int len; // current code length 47 | int idx; // symbol index 48 | int key; // prefix code 49 | int reps; // number of replicate key values in current table 50 | int low; // low bits for current root entry 51 | int table_bits; // key length of current table 52 | int table_size; // size of current table 53 | int total_size; // sum of root table size and 2nd level table sizes 54 | 55 | // Make a local copy of the input bit length histogram. 56 | int count[kJpegHuffmanMaxBitLength + 1] = { 0 }; 57 | int total_count = 0; 58 | for (len = 1; len <= kJpegHuffmanMaxBitLength; ++len) { 59 | count[len] = count_in[len]; 60 | total_count += count[len]; 61 | } 62 | 63 | table = lut; 64 | table_bits = kJpegHuffmanRootTableBits; 65 | table_size = 1 << table_bits; 66 | total_size = table_size; 67 | 68 | // Special case code with only one value. 69 | if (total_count == 1) { 70 | code.bits = 0; 71 | code.value = symbols[0]; 72 | for (key = 0; key < total_size; ++key) { 73 | table[key] = code; 74 | } 75 | return total_size; 76 | } 77 | 78 | // Fill in root table. 79 | key = 0; 80 | idx = 0; 81 | for (len = 1; len <= kJpegHuffmanRootTableBits; ++len) { 82 | for (; count[len] > 0; --count[len]) { 83 | code.bits = len; 84 | code.value = symbols[idx++]; 85 | reps = 1 << (kJpegHuffmanRootTableBits - len); 86 | while (reps--) { 87 | table[key++] = code; 88 | } 89 | } 90 | } 91 | 92 | // Fill in 2nd level tables and add pointers to root table. 93 | table += table_size; 94 | table_size = 0; 95 | low = 0; 96 | for (len = kJpegHuffmanRootTableBits + 1; 97 | len <= kJpegHuffmanMaxBitLength; ++len) { 98 | for (; count[len] > 0; --count[len]) { 99 | // Start a new sub-table if the previous one is full. 100 | if (low >= table_size) { 101 | table += table_size; 102 | table_bits = NextTableBitSize(count, len); 103 | table_size = 1 << table_bits; 104 | total_size += table_size; 105 | low = 0; 106 | lut[key].bits = table_bits + kJpegHuffmanRootTableBits; 107 | lut[key].value = (table - lut) - key; 108 | ++key; 109 | } 110 | code.bits = len - kJpegHuffmanRootTableBits; 111 | code.value = symbols[idx++]; 112 | reps = 1 << (table_bits - code.bits); 113 | while (reps--) { 114 | table[low++] = code; 115 | } 116 | } 117 | } 118 | 119 | return total_size; 120 | } 121 | 122 | } // namespace guetzli 123 | -------------------------------------------------------------------------------- /guetzli/jpeg_huffman_decode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Utility function for building a Huffman lookup table for the jpeg decoder. 18 | 19 | #ifndef GUETZLI_JPEG_HUFFMAN_DECODE_H_ 20 | #define GUETZLI_JPEG_HUFFMAN_DECODE_H_ 21 | 22 | #include 23 | 24 | namespace guetzli { 25 | 26 | static const int kJpegHuffmanRootTableBits = 8; 27 | // Maximum huffman lookup table size. 28 | // According to zlib/examples/enough.c, 758 entries are always enough for 29 | // an alphabet of 257 symbols (256 + 1 special symbol for the all 1s code) and 30 | // max bit length 16 if the root table has 8 bits. 31 | static const int kJpegHuffmanLutSize = 758; 32 | 33 | struct HuffmanTableEntry { 34 | // Initialize the value to an invalid symbol so that we can recognize it 35 | // when reading the bit stream using a Huffman code with space > 0. 36 | HuffmanTableEntry() : bits(0), value(0xffff) {} 37 | 38 | uint8_t bits; // number of bits used for this symbol 39 | uint16_t value; // symbol value or table offset 40 | }; 41 | 42 | // Builds jpeg-style Huffman lookup table from the given symbols. 43 | // The symbols are in order of increasing bit lengths. The number of symbols 44 | // with bit length n is given in counts[n] for each n >= 1. 45 | // Returns the size of the lookup table. 46 | int BuildJpegHuffmanTable(const int* counts, const int* symbols, 47 | HuffmanTableEntry* lut); 48 | 49 | } // namespace guetzli 50 | 51 | #endif // GUETZLI_JPEG_HUFFMAN_DECODE_H_ 52 | -------------------------------------------------------------------------------- /guetzli/order.inc: -------------------------------------------------------------------------------- 1 | // Automatically generated by guetzli/order:update_c_code 2 | 3 | static const float csf[192] = { 4 | 0.0f, 5 | 1.71014f, 6 | 0.298711f, 7 | 0.233709f, 8 | 0.223126f, 9 | 0.207072f, 10 | 0.192775f, 11 | 0.161201f, 12 | 2.05807f, 13 | 0.222927f, 14 | 0.203406f, 15 | 0.188465f, 16 | 0.184668f, 17 | 0.169993f, 18 | 0.159142f, 19 | 0.130155f, 20 | 0.430518f, 21 | 0.204939f, 22 | 0.206655f, 23 | 0.192231f, 24 | 0.182941f, 25 | 0.169455f, 26 | 0.157599f, 27 | 0.127153f, 28 | 0.234757f, 29 | 0.191098f, 30 | 0.192698f, 31 | 0.17425f, 32 | 0.166503f, 33 | 0.142154f, 34 | 0.126182f, 35 | 0.104196f, 36 | 0.226117f, 37 | 0.185373f, 38 | 0.183825f, 39 | 0.166643f, 40 | 0.159414f, 41 | 0.12636f, 42 | 0.108696f, 43 | 0.0911974f, 44 | 0.207463f, 45 | 0.171517f, 46 | 0.170124f, 47 | 0.141582f, 48 | 0.126213f, 49 | 0.103627f, 50 | 0.0882436f, 51 | 0.0751848f, 52 | 0.196436f, 53 | 0.161947f, 54 | 0.159271f, 55 | 0.126938f, 56 | 0.109125f, 57 | 0.0878027f, 58 | 0.0749842f, 59 | 0.0633859f, 60 | 0.165232f, 61 | 0.132905f, 62 | 0.128679f, 63 | 0.105766f, 64 | 0.0906087f, 65 | 0.0751544f, 66 | 0.0641187f, 67 | 0.0529921f, 68 | 0.0f, 69 | 0.147235f, 70 | 0.11264f, 71 | 0.0757892f, 72 | 0.0493929f, 73 | 0.0280663f, 74 | 0.0075012f, 75 | -0.000945567f, 76 | 0.149251f, 77 | 0.0964806f, 78 | 0.0786224f, 79 | 0.05206f, 80 | 0.0292758f, 81 | 0.00353094f, 82 | -0.00277912f, 83 | -0.00404481f, 84 | 0.115551f, 85 | 0.0793142f, 86 | 0.0623735f, 87 | 0.0405019f, 88 | 0.0152656f, 89 | -0.00145742f, 90 | -0.00370369f, 91 | -0.00375106f, 92 | 0.0791547f, 93 | 0.0537506f, 94 | 0.0413634f, 95 | 0.0193486f, 96 | 0.000609066f, 97 | -0.00510923f, 98 | -0.0046452f, 99 | -0.00385187f, 100 | 0.0544534f, 101 | 0.0334066f, 102 | 0.0153899f, 103 | 0.000539088f, 104 | -0.00356085f, 105 | -0.00535661f, 106 | -0.00429145f, 107 | -0.00343131f, 108 | 0.0356439f, 109 | 0.00865645f, 110 | 0.00165229f, 111 | -0.00425931f, 112 | -0.00507324f, 113 | -0.00459083f, 114 | -0.003703f, 115 | -0.00310327f, 116 | 0.0121926f, 117 | -0.0009259f, 118 | -0.00330991f, 119 | -0.00499378f, 120 | -0.00437381f, 121 | -0.00377427f, 122 | -0.00311731f, 123 | -0.00255125f, 124 | -0.000320593f, 125 | -0.00426043f, 126 | -0.00416549f, 127 | -0.00419364f, 128 | -0.00365418f, 129 | -0.00317499f, 130 | -0.00255932f, 131 | -0.00217917f, 132 | 0.0f, 133 | 0.143471f, 134 | 0.124336f, 135 | 0.0947465f, 136 | 0.0814066f, 137 | 0.0686776f, 138 | 0.0588122f, 139 | 0.0374415f, 140 | 0.146315f, 141 | 0.105334f, 142 | 0.0949415f, 143 | 0.0784241f, 144 | 0.0689064f, 145 | 0.0588304f, 146 | 0.0495961f, 147 | 0.0202342f, 148 | 0.123818f, 149 | 0.0952654f, 150 | 0.0860556f, 151 | 0.0724158f, 152 | 0.0628307f, 153 | 0.0529965f, 154 | 0.0353941f, 155 | 0.00815821f, 156 | 0.097054f, 157 | 0.080422f, 158 | 0.0731085f, 159 | 0.0636154f, 160 | 0.055606f, 161 | 0.0384127f, 162 | 0.0142879f, 163 | 0.00105195f, 164 | 0.0849312f, 165 | 0.071115f, 166 | 0.0631183f, 167 | 0.0552972f, 168 | 0.0369221f, 169 | 0.00798314f, 170 | 0.000716374f, 171 | -0.00200948f, 172 | 0.0722298f, 173 | 0.0599559f, 174 | 0.054841f, 175 | 0.0387529f, 176 | 0.0107262f, 177 | 0.000355315f, 178 | -0.00244803f, 179 | -0.00335222f, 180 | 0.0635335f, 181 | 0.0514196f, 182 | 0.0406309f, 183 | 0.0125833f, 184 | 0.00151305f, 185 | -0.00140269f, 186 | -0.00362547f, 187 | -0.00337649f, 188 | 0.0472024f, 189 | 0.0198725f, 190 | 0.0113437f, 191 | 0.00266305f, 192 | -0.00137183f, 193 | -0.00354158f, 194 | -0.00341292f, 195 | -0.00290074f 196 | }; 197 | 198 | static const float bias[192] = { 199 | 0.0f, 200 | 0.0f, 201 | 0.0f, 202 | 0.0f, 203 | 0.0f, 204 | 0.0f, 205 | 0.0f, 206 | 0.0f, 207 | 0.0f, 208 | 0.0f, 209 | 0.0f, 210 | 0.0f, 211 | 0.0f, 212 | 0.0f, 213 | 0.0f, 214 | 0.0f, 215 | 0.0f, 216 | 0.0f, 217 | 0.0f, 218 | 0.0f, 219 | 0.0f, 220 | 0.0f, 221 | 0.0f, 222 | 0.0f, 223 | 0.0f, 224 | 0.0f, 225 | 0.0f, 226 | 0.0f, 227 | 0.0f, 228 | 0.0f, 229 | 0.0f, 230 | 0.0f, 231 | 0.0f, 232 | 0.0f, 233 | 0.0f, 234 | 0.0f, 235 | 0.0f, 236 | 0.0f, 237 | 0.0f, 238 | 0.0f, 239 | 0.0f, 240 | 0.0f, 241 | 0.0f, 242 | 0.0f, 243 | 0.0f, 244 | 0.0f, 245 | 0.0f, 246 | 0.0f, 247 | 0.0f, 248 | 0.0f, 249 | 0.0f, 250 | 0.0f, 251 | 0.0f, 252 | 0.0f, 253 | 0.0f, 254 | 0.0f, 255 | 0.0f, 256 | 0.0f, 257 | 0.0f, 258 | 0.0f, 259 | 0.0f, 260 | 0.0f, 261 | 0.0f, 262 | 0.0f, 263 | 0.0f, 264 | 0.0f, 265 | 0.0f, 266 | 0.0f, 267 | 0.0f, 268 | 0.0f, 269 | 0.0f, 270 | 0.0f, 271 | 0.0f, 272 | 0.0f, 273 | 0.0f, 274 | 0.0f, 275 | 0.0f, 276 | 0.0f, 277 | 0.0f, 278 | 0.0f, 279 | 0.0f, 280 | 0.0f, 281 | 0.0f, 282 | 0.0f, 283 | 0.0f, 284 | 0.0f, 285 | 0.0f, 286 | 0.0f, 287 | 0.0f, 288 | 0.0f, 289 | 0.0f, 290 | 0.0f, 291 | 0.0f, 292 | 0.0f, 293 | 0.0f, 294 | 0.0f, 295 | 0.0f, 296 | 0.0f, 297 | 0.0f, 298 | 0.0f, 299 | 0.0f, 300 | 0.0f, 301 | 0.0f, 302 | 0.0f, 303 | 0.0f, 304 | 0.0f, 305 | 0.0f, 306 | 0.0f, 307 | 0.0f, 308 | 0.0f, 309 | 0.0f, 310 | 0.0f, 311 | 0.0f, 312 | 0.0f, 313 | 0.0f, 314 | 0.0f, 315 | 0.0f, 316 | 0.0f, 317 | 0.0f, 318 | 0.0f, 319 | 0.0f, 320 | 0.0f, 321 | 0.0f, 322 | 0.0f, 323 | 0.0f, 324 | 0.0f, 325 | 0.0f, 326 | 0.0f, 327 | 0.0f, 328 | 0.0f, 329 | 0.0f, 330 | 0.0f, 331 | 0.0f, 332 | 0.0f, 333 | 0.0f, 334 | 0.0f, 335 | 0.0f, 336 | 0.0f, 337 | 0.0f, 338 | 0.0f, 339 | 0.0f, 340 | 0.0f, 341 | 0.0f, 342 | 0.0f, 343 | 0.0f, 344 | 0.0f, 345 | 0.0f, 346 | 0.0f, 347 | 0.0f, 348 | 0.0f, 349 | 0.0f, 350 | 0.0f, 351 | 0.0f, 352 | 0.0f, 353 | 0.0f, 354 | 0.0f, 355 | 0.0f, 356 | 0.0f, 357 | 0.0f, 358 | 0.0f, 359 | 0.0f, 360 | 0.0f, 361 | 0.0f, 362 | 0.0f, 363 | 0.0f, 364 | 0.0f, 365 | 0.0f, 366 | 0.0f, 367 | 0.0f, 368 | 0.0f, 369 | 0.0f, 370 | 0.0f, 371 | 0.0f, 372 | 0.0f, 373 | 0.0f, 374 | 0.0f, 375 | 0.0f, 376 | 0.0f, 377 | 0.0f, 378 | 0.0f, 379 | 0.0f, 380 | 0.0f, 381 | 0.0f, 382 | 0.0f, 383 | 0.0f, 384 | 0.0f, 385 | 0.0f, 386 | 0.0f, 387 | 0.0f, 388 | 0.0f, 389 | 0.0f, 390 | 0.0 391 | }; 392 | -------------------------------------------------------------------------------- /guetzli/output_image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_OUTPUT_IMAGE_H_ 18 | #define GUETZLI_OUTPUT_IMAGE_H_ 19 | 20 | #include 21 | #include 22 | 23 | #include "guetzli/jpeg_data.h" 24 | 25 | namespace guetzli { 26 | 27 | class OutputImageComponent { 28 | public: 29 | OutputImageComponent(int w, int h); 30 | 31 | void Reset(int factor_x, int factor_y); 32 | 33 | int width() const { return width_; } 34 | int height() const { return height_; } 35 | int factor_x() const { return factor_x_; } 36 | int factor_y() const { return factor_y_; } 37 | int width_in_blocks() const { return width_in_blocks_; } 38 | int height_in_blocks() const { return height_in_blocks_; } 39 | const coeff_t* coeffs() const { return &coeffs_[0]; } 40 | const int* quant() const { return &quant_[0]; } 41 | bool IsAllZero() const; 42 | 43 | // Fills in block[] with the 8x8 coefficient block with block coordinates 44 | // (block_x, block_y). 45 | // NOTE: If the component is 2x2 subsampled, this corresponds to the 16x16 46 | // pixel area with upper-left corner (16 * block_x, 16 * block_y). 47 | void GetCoeffBlock(int block_x, int block_y, 48 | coeff_t block[kDCTBlockSize]) const; 49 | 50 | // Fills in out[] array with the 8-bit pixel view of this component cropped 51 | // to the specified window. The window's upper-left corner, (xmin, ymin) must 52 | // be within the image, but the window may extend past the image. In that 53 | // case the edge pixels are duplicated. 54 | void ToPixels(int xmin, int ymin, int xsize, int ysize, 55 | uint8_t* out, int stride) const; 56 | 57 | // Fills in out[] array with the floating-point precision pixel view of the 58 | // component. 59 | // REQUIRES: factor_x() == 1 and factor_y() == 1. 60 | void ToFloatPixels(float* out, int stride) const; 61 | 62 | // Sets the 8x8 coefficient block with block coordinates (block_x, block_y) 63 | // to block[]. 64 | // NOTE: If the component is 2x2 subsampled, this corresponds to the 16x16 65 | // pixel area with upper-left corner (16 * block_x, 16 * block_y). 66 | // REQUIRES: block[k] % quant()[k] == 0 for each coefficient index k. 67 | void SetCoeffBlock(int block_x, int block_y, 68 | const coeff_t block[kDCTBlockSize]); 69 | 70 | // Requires that comp is not downsampled. 71 | void CopyFromJpegComponent(const JPEGComponent& comp, 72 | int factor_x, int factor_y, 73 | const int* quant); 74 | 75 | void ApplyGlobalQuantization(const int q[kDCTBlockSize]); 76 | 77 | private: 78 | void UpdatePixelsForBlock(int block_x, int block_y, 79 | const uint8_t idct[kDCTBlockSize]); 80 | 81 | const int width_; 82 | const int height_; 83 | int factor_x_; 84 | int factor_y_; 85 | int width_in_blocks_; 86 | int height_in_blocks_; 87 | int num_blocks_; 88 | std::vector coeffs_; 89 | std::vector pixels_; 90 | // Same as last argument of ApplyGlobalQuantization() (default is all 1s). 91 | int quant_[kDCTBlockSize]; 92 | }; 93 | 94 | class OutputImage { 95 | public: 96 | OutputImage(int w, int h); 97 | 98 | int width() const { return width_; } 99 | int height() const { return height_; } 100 | 101 | OutputImageComponent& component(int c) { return components_[c]; } 102 | const OutputImageComponent& component(int c) const { return components_[c]; } 103 | 104 | // Requires that jpg is in YUV444 format. 105 | void CopyFromJpegData(const JPEGData& jpg); 106 | 107 | void ApplyGlobalQuantization(const int q[3][kDCTBlockSize]); 108 | 109 | // If sharpen or blur are enabled, preprocesses image before downsampling U or 110 | // V to improve butteraugli score and/or reduce file size. 111 | // u_sharpen: sharpen the u channel in red areas to improve score (not as 112 | // effective as v_sharpen, blue is not so important) 113 | // u_blur: blur the u channel in some areas to reduce file size 114 | // v_sharpen: sharpen the v channel in red areas to improve score 115 | // v_blur: blur the v channel in some areas to reduce file size 116 | struct DownsampleConfig { 117 | // Default is YUV420. 118 | DownsampleConfig() : u_factor_x(2), u_factor_y(2), 119 | v_factor_x(2), v_factor_y(2), 120 | u_sharpen(true), u_blur(true), 121 | v_sharpen(true), v_blur(true), 122 | use_silver_screen(false) {} 123 | int u_factor_x; 124 | int u_factor_y; 125 | int v_factor_x; 126 | int v_factor_y; 127 | bool u_sharpen; 128 | bool u_blur; 129 | bool v_sharpen; 130 | bool v_blur; 131 | bool use_silver_screen; 132 | }; 133 | 134 | void Downsample(const DownsampleConfig& cfg); 135 | 136 | void SaveToJpegData(JPEGData* jpg) const; 137 | 138 | std::vector ToSRGB() const; 139 | 140 | std::vector ToSRGB(int xmin, int ymin, int xsize, int ysize) const; 141 | 142 | void ToLinearRGB(std::vector >* rgb) const; 143 | 144 | void ToLinearRGB(int xmin, int ymin, int xsize, int ysize, 145 | std::vector >* rgb) const; 146 | 147 | std::string FrameTypeStr() const; 148 | 149 | private: 150 | const int width_; 151 | const int height_; 152 | std::vector components_; 153 | }; 154 | 155 | } // namespace guetzli 156 | 157 | #endif // GUETZLI_OUTPUT_IMAGE_H_ 158 | -------------------------------------------------------------------------------- /guetzli/preprocess_downsample.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Preprocesses U and V channel for better results after downsampling. 18 | 19 | #ifndef GUETZLI_PREPROCESS_DOWNSAMPLE_H_ 20 | #define GUETZLI_PREPROCESS_DOWNSAMPLE_H_ 21 | 22 | #include 23 | #include 24 | 25 | namespace guetzli { 26 | 27 | // Preprocesses the u (1) or v (2) channel of the given YUV image (range 0-255). 28 | std::vector> PreProcessChannel( 29 | int w, int h, int channel, float sigma, float amount, bool blur, 30 | bool sharpen, const std::vector>& image); 31 | 32 | // Gamma-compensated chroma subsampling. 33 | // Returns Y, U, V image planes, each with width x height dimensions, but the 34 | // U and V planes are composed of 2x2 blocks with the same values. 35 | std::vector > RGBToYUV420( 36 | const std::vector& rgb_in, const int width, const int height); 37 | 38 | } // namespace guetzli 39 | 40 | #endif // GUETZLI_PREPROCESS_DOWNSAMPLE_H_ 41 | -------------------------------------------------------------------------------- /guetzli/processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_PROCESSOR_H_ 18 | #define GUETZLI_PROCESSOR_H_ 19 | 20 | #include 21 | #include 22 | 23 | #include "guetzli/comparator.h" 24 | #include "guetzli/jpeg_data.h" 25 | #include "guetzli/stats.h" 26 | 27 | namespace guetzli { 28 | 29 | struct Params { 30 | float butteraugli_target = 1.0; 31 | bool clear_metadata = true; 32 | bool try_420 = false; 33 | bool force_420 = false; 34 | bool use_silver_screen = false; 35 | int zeroing_greedy_lookahead = 3; 36 | bool new_zeroing_model = true; 37 | }; 38 | 39 | bool Process(const Params& params, ProcessStats* stats, 40 | const std::string& in_data, 41 | std::string* out_data); 42 | 43 | struct GuetzliOutput { 44 | std::string jpeg_data; 45 | double score; 46 | }; 47 | 48 | bool ProcessJpegData(const Params& params, const JPEGData& jpg_in, 49 | Comparator* comparator, GuetzliOutput* out, 50 | ProcessStats* stats); 51 | 52 | // Sets *out to a jpeg encoded string that will decode to an image that is 53 | // visually indistinguishable from the input rgb image. 54 | bool Process(const Params& params, ProcessStats* stats, 55 | const std::vector& rgb, int w, int h, 56 | std::string* out); 57 | 58 | } // namespace guetzli 59 | 60 | #endif // GUETZLI_PROCESSOR_H_ 61 | -------------------------------------------------------------------------------- /guetzli/quality.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/quality.h" 18 | 19 | namespace guetzli { 20 | 21 | namespace { 22 | 23 | constexpr int kLowestQuality = 70; 24 | constexpr int kHighestQuality = 110; 25 | 26 | // Butteraugli scores that correspond to JPEG quality levels, starting at 27 | // kLowestQuality. They were computed by taking median BA scores of JPEGs 28 | // generated using libjpeg-turbo at given quality from a set of PNGs. 29 | // The scores above quality level 100 are just linearly decreased so that score 30 | // for 110 is 90% of the score for 100. 31 | const double kScoreForQuality[] = { 32 | 2.810761, // 70 33 | 2.729300, 34 | 2.689687, 35 | 2.636811, 36 | 2.547863, 37 | 2.525400, 38 | 2.473416, 39 | 2.366133, 40 | 2.338078, 41 | 2.318654, 42 | 2.201674, // 80 43 | 2.145517, 44 | 2.087322, 45 | 2.009328, 46 | 1.945456, 47 | 1.900112, 48 | 1.805701, 49 | 1.750194, 50 | 1.644175, 51 | 1.562165, 52 | 1.473608, // 90 53 | 1.382021, 54 | 1.294298, 55 | 1.185402, 56 | 1.066781, 57 | 0.971769, // 95 58 | 0.852901, 59 | 0.724544, 60 | 0.611302, 61 | 0.443185, 62 | 0.211578, // 100 63 | 0.209462, 64 | 0.207346, 65 | 0.205230, 66 | 0.203114, 67 | 0.200999, // 105 68 | 0.198883, 69 | 0.196767, 70 | 0.194651, 71 | 0.192535, 72 | 0.190420, // 110 73 | 0.190420, 74 | }; 75 | 76 | } // namespace 77 | 78 | double ButteraugliScoreForQuality(double quality) { 79 | if (quality < kLowestQuality) quality = kLowestQuality; 80 | if (quality > kHighestQuality) quality = kHighestQuality; 81 | int index = static_cast(quality); 82 | double mix = quality - index; 83 | return kScoreForQuality[index - kLowestQuality] * (1 - mix) + 84 | kScoreForQuality[index - kLowestQuality + 1] * mix; 85 | } 86 | 87 | } // namespace guetzli 88 | -------------------------------------------------------------------------------- /guetzli/quality.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_QUALITY_H_ 18 | #define GUETZLI_QUALITY_H_ 19 | 20 | namespace guetzli { 21 | 22 | double ButteraugliScoreForQuality(double quality); 23 | 24 | } // namespace guetzli 25 | 26 | #endif // GUETZLI_QUALITY_H_ 27 | -------------------------------------------------------------------------------- /guetzli/quantize.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/quantize.h" 18 | 19 | namespace guetzli { 20 | 21 | bool QuantizeBlock(coeff_t block[kDCTBlockSize], 22 | const int q[kDCTBlockSize]) { 23 | bool changed = false; 24 | for (int k = 0; k < kDCTBlockSize; ++k) { 25 | coeff_t coeff = Quantize(block[k], q[k]); 26 | changed = changed || (coeff != block[k]); 27 | block[k] = coeff; 28 | } 29 | return changed; 30 | } 31 | 32 | } // namespace guetzli 33 | -------------------------------------------------------------------------------- /guetzli/quantize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_QUANTIZE_H_ 18 | #define GUETZLI_QUANTIZE_H_ 19 | 20 | #include "guetzli/jpeg_data.h" 21 | 22 | namespace guetzli { 23 | 24 | inline coeff_t Quantize(coeff_t raw_coeff, int quant) { 25 | const int r = raw_coeff % quant; 26 | const coeff_t delta = 27 | 2 * r > quant ? quant - r : (-2) * r > quant ? -quant - r : -r; 28 | return raw_coeff + delta; 29 | } 30 | 31 | bool QuantizeBlock(coeff_t block[kDCTBlockSize], const int q[kDCTBlockSize]); 32 | 33 | } // namespace guetzli 34 | 35 | #endif // GUETZLI_QUANTIZE_H_ 36 | -------------------------------------------------------------------------------- /guetzli/score.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "guetzli/score.h" 18 | 19 | #include 20 | 21 | namespace guetzli { 22 | 23 | double ScoreJPEG(double butteraugli_distance, int size, 24 | double butteraugli_target) { 25 | constexpr double kScale = 50; 26 | constexpr double kMaxExponent = 10; 27 | constexpr double kLargeSize = 1e30; 28 | // TODO(user): The score should also depend on distance below target (and be 29 | // smooth). 30 | double diff = butteraugli_distance - butteraugli_target; 31 | if (diff <= 0.0) { 32 | return size; 33 | } else { 34 | double exponent = kScale * diff; 35 | if (exponent > kMaxExponent) { 36 | return kLargeSize * std::exp(kMaxExponent) * diff + size; 37 | } else { 38 | return std::exp(exponent) * size; 39 | } 40 | } 41 | } 42 | 43 | } // namespace guetzli 44 | -------------------------------------------------------------------------------- /guetzli/score.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_SCORE_H_ 18 | #define GUETZLI_SCORE_H_ 19 | 20 | #include 21 | 22 | namespace guetzli { 23 | 24 | double ScoreJPEG(double butteraugli_distance, int size, 25 | double butteraugli_target); 26 | 27 | } // namespace guetzli 28 | #endif // GUETZLI_SCORE_H_ 29 | -------------------------------------------------------------------------------- /guetzli/stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GUETZLI_STATS_H_ 18 | #define GUETZLI_STATS_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | namespace guetzli { 28 | 29 | static const char* const kNumItersCnt = "number of iterations"; 30 | static const char* const kNumItersUpCnt = "number of iterations up"; 31 | static const char* const kNumItersDownCnt = "number of iterations down"; 32 | 33 | struct ProcessStats { 34 | ProcessStats() {} 35 | std::map counters; 36 | std::string* debug_output = nullptr; 37 | FILE* debug_output_file = nullptr; 38 | 39 | std::string filename; 40 | }; 41 | 42 | } // namespace guetzli 43 | 44 | #endif // GUETZLI_STATS_H_ 45 | -------------------------------------------------------------------------------- /guetzli_static.make: -------------------------------------------------------------------------------- 1 | # GNU Make project makefile autogenerated by Premake 2 | 3 | ifndef config 4 | config=release 5 | endif 6 | 7 | ifndef verbose 8 | SILENT = @ 9 | endif 10 | 11 | .PHONY: clean prebuild prelink 12 | 13 | ifeq ($(config),release) 14 | RESCOMP = windres 15 | TARGETDIR = bin/Release 16 | TARGET = $(TARGETDIR)/libguetzli_static.a 17 | OBJDIR = obj/Release/guetzli_static 18 | DEFINES += 19 | INCLUDES += -I. -Ithird_party/butteraugli 20 | FORCE_INCLUDE += 21 | ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) 22 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O3 -g `pkg-config --static --cflags libpng || libpng-config --static --cflags` 23 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O3 -g -std=c++11 `pkg-config --static --cflags libpng || libpng-config --static --cflags` 24 | ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) 25 | LIBS += 26 | LDDEPS += 27 | ALL_LDFLAGS += $(LDFLAGS) `pkg-config --static --libs libpng || libpng-config --static --ldflags` 28 | LINKCMD = $(AR) -rcs "$@" $(OBJECTS) 29 | define PREBUILDCMDS 30 | endef 31 | define PRELINKCMDS 32 | endef 33 | define POSTBUILDCMDS 34 | endef 35 | all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) 36 | @: 37 | 38 | endif 39 | 40 | ifeq ($(config),debug) 41 | RESCOMP = windres 42 | TARGETDIR = bin/Debug 43 | TARGET = $(TARGETDIR)/libguetzli_static.a 44 | OBJDIR = obj/Debug/guetzli_static 45 | DEFINES += 46 | INCLUDES += -I. -Ithird_party/butteraugli 47 | FORCE_INCLUDE += 48 | ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) 49 | ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g `pkg-config --static --cflags libpng || libpng-config --static --cflags` 50 | ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11 `pkg-config --static --cflags libpng || libpng-config --static --cflags` 51 | ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) 52 | LIBS += 53 | LDDEPS += 54 | ALL_LDFLAGS += $(LDFLAGS) `pkg-config --static --libs libpng || libpng-config --static --ldflags` 55 | LINKCMD = $(AR) -rcs "$@" $(OBJECTS) 56 | define PREBUILDCMDS 57 | endef 58 | define PRELINKCMDS 59 | endef 60 | define POSTBUILDCMDS 61 | endef 62 | all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) 63 | @: 64 | 65 | endif 66 | 67 | OBJECTS := \ 68 | $(OBJDIR)/butteraugli_comparator.o \ 69 | $(OBJDIR)/dct_double.o \ 70 | $(OBJDIR)/debug_print.o \ 71 | $(OBJDIR)/entropy_encode.o \ 72 | $(OBJDIR)/fdct.o \ 73 | $(OBJDIR)/gamma_correct.o \ 74 | $(OBJDIR)/idct.o \ 75 | $(OBJDIR)/jpeg_data.o \ 76 | $(OBJDIR)/jpeg_data_decoder.o \ 77 | $(OBJDIR)/jpeg_data_encoder.o \ 78 | $(OBJDIR)/jpeg_data_reader.o \ 79 | $(OBJDIR)/jpeg_data_writer.o \ 80 | $(OBJDIR)/jpeg_huffman_decode.o \ 81 | $(OBJDIR)/output_image.o \ 82 | $(OBJDIR)/preprocess_downsample.o \ 83 | $(OBJDIR)/processor.o \ 84 | $(OBJDIR)/quality.o \ 85 | $(OBJDIR)/quantize.o \ 86 | $(OBJDIR)/score.o \ 87 | $(OBJDIR)/butteraugli.o \ 88 | 89 | RESOURCES := \ 90 | 91 | CUSTOMFILES := \ 92 | 93 | SHELLTYPE := msdos 94 | ifeq (,$(ComSpec)$(COMSPEC)) 95 | SHELLTYPE := posix 96 | endif 97 | ifeq (/bin,$(findstring /bin,$(SHELL))) 98 | SHELLTYPE := posix 99 | endif 100 | 101 | $(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES) 102 | @echo Linking guetzli_static 103 | $(SILENT) $(LINKCMD) 104 | $(POSTBUILDCMDS) 105 | 106 | $(TARGETDIR): 107 | @echo Creating $(TARGETDIR) 108 | ifeq (posix,$(SHELLTYPE)) 109 | $(SILENT) mkdir -p $(TARGETDIR) 110 | else 111 | $(SILENT) mkdir $(subst /,\\,$(TARGETDIR)) 112 | endif 113 | 114 | $(OBJDIR): 115 | @echo Creating $(OBJDIR) 116 | ifeq (posix,$(SHELLTYPE)) 117 | $(SILENT) mkdir -p $(OBJDIR) 118 | else 119 | $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) 120 | endif 121 | 122 | clean: 123 | @echo Cleaning guetzli_static 124 | ifeq (posix,$(SHELLTYPE)) 125 | $(SILENT) rm -f $(TARGET) 126 | $(SILENT) rm -rf $(OBJDIR) 127 | else 128 | $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) 129 | $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) 130 | endif 131 | 132 | prebuild: 133 | $(PREBUILDCMDS) 134 | 135 | prelink: 136 | $(PRELINKCMDS) 137 | 138 | ifneq (,$(PCH)) 139 | $(OBJECTS): $(GCH) $(PCH) 140 | $(GCH): $(PCH) 141 | @echo $(notdir $<) 142 | $(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<" 143 | endif 144 | 145 | $(OBJDIR)/butteraugli_comparator.o: guetzli/butteraugli_comparator.cc 146 | @echo $(notdir $<) 147 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 148 | $(OBJDIR)/dct_double.o: guetzli/dct_double.cc 149 | @echo $(notdir $<) 150 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 151 | $(OBJDIR)/debug_print.o: guetzli/debug_print.cc 152 | @echo $(notdir $<) 153 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 154 | $(OBJDIR)/entropy_encode.o: guetzli/entropy_encode.cc 155 | @echo $(notdir $<) 156 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 157 | $(OBJDIR)/fdct.o: guetzli/fdct.cc 158 | @echo $(notdir $<) 159 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 160 | $(OBJDIR)/gamma_correct.o: guetzli/gamma_correct.cc 161 | @echo $(notdir $<) 162 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 163 | $(OBJDIR)/idct.o: guetzli/idct.cc 164 | @echo $(notdir $<) 165 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 166 | $(OBJDIR)/jpeg_data.o: guetzli/jpeg_data.cc 167 | @echo $(notdir $<) 168 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 169 | $(OBJDIR)/jpeg_data_decoder.o: guetzli/jpeg_data_decoder.cc 170 | @echo $(notdir $<) 171 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 172 | $(OBJDIR)/jpeg_data_encoder.o: guetzli/jpeg_data_encoder.cc 173 | @echo $(notdir $<) 174 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 175 | $(OBJDIR)/jpeg_data_reader.o: guetzli/jpeg_data_reader.cc 176 | @echo $(notdir $<) 177 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 178 | $(OBJDIR)/jpeg_data_writer.o: guetzli/jpeg_data_writer.cc 179 | @echo $(notdir $<) 180 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 181 | $(OBJDIR)/jpeg_huffman_decode.o: guetzli/jpeg_huffman_decode.cc 182 | @echo $(notdir $<) 183 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 184 | $(OBJDIR)/output_image.o: guetzli/output_image.cc 185 | @echo $(notdir $<) 186 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 187 | $(OBJDIR)/preprocess_downsample.o: guetzli/preprocess_downsample.cc 188 | @echo $(notdir $<) 189 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 190 | $(OBJDIR)/processor.o: guetzli/processor.cc 191 | @echo $(notdir $<) 192 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 193 | $(OBJDIR)/quality.o: guetzli/quality.cc 194 | @echo $(notdir $<) 195 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 196 | $(OBJDIR)/quantize.o: guetzli/quantize.cc 197 | @echo $(notdir $<) 198 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 199 | $(OBJDIR)/score.o: guetzli/score.cc 200 | @echo $(notdir $<) 201 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 202 | $(OBJDIR)/butteraugli.o: third_party/butteraugli/butteraugli/butteraugli.cc 203 | @echo $(notdir $<) 204 | $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" 205 | 206 | -include $(OBJECTS:%.o=%.d) 207 | ifneq (,$(PCH)) 208 | -include $(OBJDIR)/$(notdir $(PCH)).d 209 | endif -------------------------------------------------------------------------------- /guetzli_static.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | x64 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Debug 18 | Win32 19 | 20 | 21 | 22 | {30B3C385-1C81-B78B-0515-28B2F18193F0} 23 | true 24 | Win32Proj 25 | guetzli_static 26 | 27 | 28 | 29 | StaticLibrary 30 | false 31 | Unicode 32 | v140 33 | 34 | 35 | StaticLibrary 36 | false 37 | Unicode 38 | v140 39 | 40 | 41 | StaticLibrary 42 | true 43 | Unicode 44 | v140 45 | 46 | 47 | StaticLibrary 48 | true 49 | Unicode 50 | v140 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | bin\x86_64\Release\ 70 | obj\x86_64\Release\guetzli_static\ 71 | guetzli_static 72 | .lib 73 | 74 | 75 | bin\x86\Release\ 76 | obj\x86\Release\guetzli_static\ 77 | guetzli_static 78 | .lib 79 | 80 | 81 | bin\x86_64\Debug\ 82 | obj\x86_64\Debug\guetzli_static\ 83 | guetzli_static 84 | .lib 85 | 86 | 87 | bin\x86\Debug\ 88 | obj\x86\Debug\guetzli_static\ 89 | guetzli_static 90 | .lib 91 | 92 | 93 | 94 | NotUsing 95 | Level3 96 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 97 | Full 98 | true 99 | true 100 | false 101 | true 102 | 103 | 104 | Windows 105 | true 106 | true 107 | 108 | 109 | 110 | 111 | NotUsing 112 | Level3 113 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 114 | Full 115 | true 116 | true 117 | false 118 | true 119 | 120 | 121 | Windows 122 | true 123 | true 124 | 125 | 126 | 127 | 128 | NotUsing 129 | Level3 130 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 131 | EditAndContinue 132 | Disabled 133 | 134 | 135 | Windows 136 | true 137 | 138 | 139 | 140 | 141 | NotUsing 142 | Level3 143 | .;third_party\butteraugli;%(AdditionalIncludeDirectories) 144 | EditAndContinue 145 | Disabled 146 | 147 | 148 | Windows 149 | true 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /guetzli_static.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {C9FCBE14-35DC-3DB0-3EF4-C886AA52A411} 6 | 7 | 8 | {0FB18DF1-7B66-06E7-045B-00BE700FFDEA} 9 | 10 | 11 | {468B2B32-B2C2-73C9-BBCC-D7EC27839AC2} 12 | 13 | 14 | {FD6FCB41-6929-36EC-F288-50C65E41EC5B} 15 | 16 | 17 | 18 | 19 | guetzli 20 | 21 | 22 | guetzli 23 | 24 | 25 | guetzli 26 | 27 | 28 | guetzli 29 | 30 | 31 | guetzli 32 | 33 | 34 | guetzli 35 | 36 | 37 | guetzli 38 | 39 | 40 | guetzli 41 | 42 | 43 | guetzli 44 | 45 | 46 | guetzli 47 | 48 | 49 | guetzli 50 | 51 | 52 | guetzli 53 | 54 | 55 | guetzli 56 | 57 | 58 | guetzli 59 | 60 | 61 | guetzli 62 | 63 | 64 | guetzli 65 | 66 | 67 | guetzli 68 | 69 | 70 | guetzli 71 | 72 | 73 | guetzli 74 | 75 | 76 | guetzli 77 | 78 | 79 | guetzli 80 | 81 | 82 | guetzli 83 | 84 | 85 | guetzli 86 | 87 | 88 | guetzli 89 | 90 | 91 | guetzli 92 | 93 | 94 | third_party\butteraugli\butteraugli 95 | 96 | 97 | 98 | 99 | guetzli 100 | 101 | 102 | guetzli 103 | 104 | 105 | guetzli 106 | 107 | 108 | guetzli 109 | 110 | 111 | guetzli 112 | 113 | 114 | guetzli 115 | 116 | 117 | guetzli 118 | 119 | 120 | guetzli 121 | 122 | 123 | guetzli 124 | 125 | 126 | guetzli 127 | 128 | 129 | guetzli 130 | 131 | 132 | guetzli 133 | 134 | 135 | guetzli 136 | 137 | 138 | guetzli 139 | 140 | 141 | guetzli 142 | 143 | 144 | guetzli 145 | 146 | 147 | guetzli 148 | 149 | 150 | guetzli 151 | 152 | 153 | guetzli 154 | 155 | 156 | third_party\butteraugli\butteraugli 157 | 158 | 159 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "guetzli" 2 | configurations { "Release", "Debug" } 3 | language "C++" 4 | flags { "C++11" } 5 | includedirs { ".", "third_party/butteraugli" } 6 | 7 | filter "action:vs*" 8 | platforms { "x86_64", "x86" } 9 | 10 | filter "platforms:x86" 11 | architecture "x86" 12 | filter "platforms:x86_64" 13 | architecture "x86_64" 14 | 15 | -- workaround for #41 16 | filter "action:gmake" 17 | symbols "On" 18 | 19 | filter "configurations:Debug" 20 | symbols "On" 21 | filter "configurations:Release" 22 | optimize "Full" 23 | filter {} 24 | 25 | project "guetzli_static" 26 | kind "StaticLib" 27 | files 28 | { 29 | "guetzli/*.cc", 30 | "guetzli/*.h", 31 | "third_party/butteraugli/butteraugli/butteraugli.cc", 32 | "third_party/butteraugli/butteraugli/butteraugli.h" 33 | } 34 | removefiles "guetzli/guetzli.cc" 35 | filter "action:gmake" 36 | linkoptions { "`pkg-config --static --libs libpng || libpng-config --static --ldflags`" } 37 | buildoptions { "`pkg-config --static --cflags libpng || libpng-config --static --cflags`" } 38 | 39 | project "guetzli" 40 | kind "ConsoleApp" 41 | filter "action:gmake" 42 | linkoptions { "`pkg-config --libs libpng || libpng-config --ldflags`" } 43 | buildoptions { "`pkg-config --cflags libpng || libpng-config --cflags`" } 44 | filter "action:vs*" 45 | links { "shlwapi" } 46 | filter {} 47 | files 48 | { 49 | "guetzli/*.cc", 50 | "guetzli/*.h", 51 | "third_party/butteraugli/butteraugli/butteraugli.cc", 52 | "third_party/butteraugli/butteraugli/butteraugli.h" 53 | } 54 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: guetzli 2 | version: master 3 | summary: JPEG encoder for excellent compression density at high visual quality 4 | description: | 5 | Guetzli-generated images are typically 20-30% smaller than images of 6 | equivalent quality generated by libjpeg. Guetzli generates only sequential 7 | (nonprogressive) JPEGs due to faster decompression speeds they offer. 8 | 9 | grade: devel 10 | confinement: strict 11 | 12 | apps: 13 | guetzli: 14 | command: bin/Release/guetzli 15 | plugs: [home] 16 | 17 | parts: 18 | guetzli: 19 | source: . 20 | plugin: make 21 | build-packages: [libpng12-dev, libgflags-dev] 22 | artifacts: [bin/Release/guetzli] 23 | -------------------------------------------------------------------------------- /tests/bees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/guetzli/214f2bb42abf5a577c079d00add5d6cc470620d3/tests/bees.png -------------------------------------------------------------------------------- /tests/golden_checksums.txt: -------------------------------------------------------------------------------- 1 | 40a8e87fc2feecfe5db466f44c248bb970591132f357140fd3cc93705cd233fb bees-420.jpg.guetzli.jpg 2 | 2da4c37bfc1ed94c1285bf43e07b61c647d160179b8c685707bdf6dcc7d28b33 bees.jpg.guetzli.jpg 3 | 39cfc110d3d389ddf3b9c47adece290ef077b78467f1ed39679b691c6fb7c96d bees.png.guetzli.jpg 4 | 2da4c37bfc1ed94c1285bf43e07b61c647d160179b8c685707bdf6dcc7d28b33 bees-progressive.jpg.guetzli.jpg 5 | 80fb7d673090ed5269b680a90d958e876190516b76f12caca7d4bf227ef9da3d bench2-420.jpg.guetzli.jpg 6 | 8f76f86500851858c047d03c2fc49841d60a84163656bf45662d653ee58e66b8 bench2.jpg.guetzli.jpg 7 | 9d7734214baaf01bcd44ee080ea3b7fef8829f2fa51b53b79a8b6474c0c5ae80 bench2.png.guetzli.jpg 8 | 8f76f86500851858c047d03c2fc49841d60a84163656bf45662d653ee58e66b8 bench2-progressive.jpg.guetzli.jpg 9 | e2ca9887fbe6c98fc84a2688c3278387ba17a19b4cc481c267044ddc8d16ed55 bench-420.jpg.guetzli.jpg 10 | 7cec578c81ab24525dd4fffd793886114d87d80b48a8666795b3b6c400a18bd0 bench.jpg.guetzli.jpg 11 | 4aa0a50b196dba81534e31f451517d952cfbdd40b32c9a9c3c26dd1f954216ce bench.png.guetzli.jpg 12 | 7cec578c81ab24525dd4fffd793886114d87d80b48a8666795b3b6c400a18bd0 bench-progressive.jpg.guetzli.jpg 13 | e2dfa6c9642ef73947f64671d3d288c82595293cfeb6aabe490bda6e63d6e824 bicycles-420.jpg.guetzli.jpg 14 | 0dfd25366c2cfe0b93b0ad8da38be623dd067f590968f6dbde66e8fe6b04ceff bicycles.jpg.guetzli.jpg 15 | a9439e530c365a62c965e2d858c8de8fbd3f44e6e9c6ade1c2248ad373fb8755 bicycles.png.guetzli.jpg 16 | 0dfd25366c2cfe0b93b0ad8da38be623dd067f590968f6dbde66e8fe6b04ceff bicycles-progressive.jpg.guetzli.jpg 17 | 8ebf427aa736b66d315cead233b6eb6bc0dc49e83529b0c53315b272d35148fa blue-rose-420.jpg.guetzli.jpg 18 | 9ccdf1be8f0d121d4b6888e47d187e8b6378b63d5592a2b9f001a4d017506bde blue-rose.jpg.guetzli.jpg 19 | 6c75b537c2d603aa51c9fbc8f7f6b1bff413de269b13eec5982d24cfcf1e0d08 blue-rose.png.guetzli.jpg 20 | 9ccdf1be8f0d121d4b6888e47d187e8b6378b63d5592a2b9f001a4d017506bde blue-rose-progressive.jpg.guetzli.jpg 21 | 2763977af200403d57c7b9d9d33cfb76947076413c9531b16171c0a5fbc83339 brake-light-420.jpg.guetzli.jpg 22 | a84703948373a12cc1db1edd32616c983db08ff07f550a3be7b111bf9e4ba06f brake-light.jpg.guetzli.jpg 23 | eda4f537c54ca55eddc03097b6aa57db61c57f80e276306ff4c73b72123e5402 brake-light.png.guetzli.jpg 24 | a84703948373a12cc1db1edd32616c983db08ff07f550a3be7b111bf9e4ba06f brake-light-progressive.jpg.guetzli.jpg 25 | c25be9699cad0796f1c663d8a7d92c2e99dfb95bed4efd0d58c15d52bb4fe049 cloth-420.jpg.guetzli.jpg 26 | 6bf2ef7d27a5a8614db0f698b1f977cd0f486fdc2d4260b90f0d64d653383c35 cloth.jpg.guetzli.jpg 27 | 446850f4decd68d77c8a5b09d925fdc9075f44fdfe6dfb2e60a1064677678a3f cloth.png.guetzli.jpg 28 | 6bf2ef7d27a5a8614db0f698b1f977cd0f486fdc2d4260b90f0d64d653383c35 cloth-progressive.jpg.guetzli.jpg 29 | e6407f3d38f70dde51584ee174ae29f53cc2d2d7e63812a3405d20079d67a45c geranium2-420.jpg.guetzli.jpg 30 | 14fb9aab1ebd6d7b8779566665fe2f94b07158b277f29296ef2f9fee71c3c4a4 geranium2.jpg.guetzli.jpg 31 | b7ded98029eca0ecf75bb01d5ea54a833fa13377136b4e7e404ae35503f82eb8 geranium2.png.guetzli.jpg 32 | 14fb9aab1ebd6d7b8779566665fe2f94b07158b277f29296ef2f9fee71c3c4a4 geranium2-progressive.jpg.guetzli.jpg 33 | 9eea5d54068ccaacfb1839c67c401685646c73edfdc38bac8e1e3a084e268f0d geranium-420.jpg.guetzli.jpg 34 | 4f249d42280d6f982fa093343236b318be887dc0f2241e125fcf6d4c913305e3 geranium.jpg.guetzli.jpg 35 | 31040ac1623c371187c94946ae91c548c553403f60cc43899d9e13bcf39b6a7c geranium.png.guetzli.jpg 36 | 4f249d42280d6f982fa093343236b318be887dc0f2241e125fcf6d4c913305e3 geranium-progressive.jpg.guetzli.jpg 37 | 86fb6f73a32bac4c7f3dfd009d5f745dd3694bc773bd853278e14624a91f7434 green-420.jpg.guetzli.jpg 38 | e1fbdb05fe74f2d78cf6547621d99afea6e72069d8de68da274d66530b5dcdd7 green.jpg.guetzli.jpg 39 | 3df6e963406121db078b99653d7c4e49ce2affe99b31212b026239d082748291 green.png.guetzli.jpg 40 | e1fbdb05fe74f2d78cf6547621d99afea6e72069d8de68da274d66530b5dcdd7 green-progressive.jpg.guetzli.jpg 41 | c2fcd25260b5c52871def4a7ef0136be7e7e7f63f836a974c51a4681a651d7c7 green-rose-420.jpg.guetzli.jpg 42 | 90998e98318bb62538fe64f3b60d3100230474bf57dda72cd737eeee8ea482ae green-rose.jpg.guetzli.jpg 43 | 513e03accb79e60e9c8a2e9832bdbf9f1af8b23c6905cdb476e0626e1a7009d2 green-rose.png.guetzli.jpg 44 | 90998e98318bb62538fe64f3b60d3100230474bf57dda72cd737eeee8ea482ae green-rose-progressive.jpg.guetzli.jpg 45 | f1279ca9177e0aea7451bafa4abcd8ecfdf8a939ae97c974fbc802b668d8a56b hand-420.jpg.guetzli.jpg 46 | 8d2d8f4a95deea2dca8539a0c12ba8186ea93e7d9bcff9cb2c0bb9eab5504d1f hand.jpg.guetzli.jpg 47 | 4d156e4dbec82cb2f8fa324ea9f9142327d63853379cf3332775fdd40bbafc2f hand.png.guetzli.jpg 48 | 8d2d8f4a95deea2dca8539a0c12ba8186ea93e7d9bcff9cb2c0bb9eab5504d1f hand-progressive.jpg.guetzli.jpg 49 | c3a3f86da0eeacc015504139181c19f874e9631336bb5f90fbf8a367058ec95f lichen-420.jpg.guetzli.jpg 50 | 44db143ce962b2eb45fcc1a79468d96ca7c677cba864efd9a984e3f86de5a0a5 lichen.jpg.guetzli.jpg 51 | 9df98b8aa95a160a5937b602de715a9c54dde5ea9cd25d188643642656bb22b7 lichen.png.guetzli.jpg 52 | 44db143ce962b2eb45fcc1a79468d96ca7c677cba864efd9a984e3f86de5a0a5 lichen-progressive.jpg.guetzli.jpg 53 | c8b301b6ecfba6c9e9119b5a59e6174b6e7e9341b96943efd32f5d53c8d5e858 minerology-420.jpg.guetzli.jpg 54 | cff08d7d8896f5a4a95f04e34a1af6b6e165672532d828e95ade620beca9026f minerology.jpg.guetzli.jpg 55 | 4d789c23515fabc586d7e16c41e56df3013d6512f4bde17a6e8872b37911fcff minerology.png.guetzli.jpg 56 | cff08d7d8896f5a4a95f04e34a1af6b6e165672532d828e95ade620beca9026f minerology-progressive.jpg.guetzli.jpg 57 | e4ff3c1299f42d6ee537c1122954a5131f48a0d4fe0ef03c220c4c93543964da out-of-focus-420.jpg.guetzli.jpg 58 | 57590d333c2970e920fd5239bef84542823a465049aab17a111092863f2126ca out-of-focus.jpg.guetzli.jpg 59 | 087e342be60df5851977c9a178bf52460108d169eaab8272c2c83789da44d818 out-of-focus.png.guetzli.jpg 60 | 57590d333c2970e920fd5239bef84542823a465049aab17a111092863f2126ca out-of-focus-progressive.jpg.guetzli.jpg 61 | dcff545a0bf03441a679134a4fa3922325bd0196447cdf2de63eea48eac7fab3 pimpinelli-420.jpg.guetzli.jpg 62 | fccbde44ee9cc867bda3f2d93ae8b47a893ba683a0f0e2aff7c9213c126b4830 pimpinelli.jpg.guetzli.jpg 63 | a51ffedd0a9c814a5d763418e523b18c25abf167088f245018196a19c7830583 pimpinelli.png.guetzli.jpg 64 | fccbde44ee9cc867bda3f2d93ae8b47a893ba683a0f0e2aff7c9213c126b4830 pimpinelli-progressive.jpg.guetzli.jpg 65 | a23ecdeb4a556d25a596fe5d49dde55eb7d4531d999629a610e68953811c678f pink-flower-420.jpg.guetzli.jpg 66 | 87ac31333c5a61e00947a2f7f94078d9b753b6a0291d218ca5547861a7c28b57 pink-flower.jpg.guetzli.jpg 67 | 773fb2075a222ca7e07bec1c87f7453fc4d4b578e44ee816bc2f90d971706a70 pink-flower.png.guetzli.jpg 68 | 87ac31333c5a61e00947a2f7f94078d9b753b6a0291d218ca5547861a7c28b57 pink-flower-progressive.jpg.guetzli.jpg 69 | aceb338115241d9984510fd2e8a2bf46b3c5fc431e827a2d1efe496dff038675 port-420.jpg.guetzli.jpg 70 | 02aac145b6df57db2913952d3d46c8d456e2f000cff1ff4bfc574b27175335e0 port.jpg.guetzli.jpg 71 | 157a25812bcf7bce343fe6c6a88932ee49117b46b5d3ba0aa3421edc8f2f1a09 port.png.guetzli.jpg 72 | 02aac145b6df57db2913952d3d46c8d456e2f000cff1ff4bfc574b27175335e0 port-progressive.jpg.guetzli.jpg 73 | f41f613ecfae42d050115b785c1591724fcb7937c361b9c5d2a3248b7580953f rainbow-420.jpg.guetzli.jpg 74 | 74d94a13c52b0d582c50d6bc70cecb6762c08740db6c234dff9b0e1c04fccbb5 rainbow.jpg.guetzli.jpg 75 | 657efb5cfa742fbdfd6304703b131a63c2ddf8b686600840a800e7d94b4da0eb rainbow.png.guetzli.jpg 76 | 74d94a13c52b0d582c50d6bc70cecb6762c08740db6c234dff9b0e1c04fccbb5 rainbow-progressive.jpg.guetzli.jpg 77 | 4667bf8db85507bf260bdbad439b87250e0613092131e0a662f22164d7abb91e red-flowers-420.jpg.guetzli.jpg 78 | d48d6208e857fc92e9fb584d19e5738d767b520d3fd57937f16657a4cfe57743 red-flowers.jpg.guetzli.jpg 79 | 6a2fb22da73b20e80d31fd2920d16c847cc0f68eb44af3f924766339f8869a99 red-flowers.png.guetzli.jpg 80 | d48d6208e857fc92e9fb584d19e5738d767b520d3fd57937f16657a4cfe57743 red-flowers-progressive.jpg.guetzli.jpg 81 | 37827b7701fcb66ee2d808f5c7a5be5f6fbe732241f178f152b12103e3581d35 red-room-420.jpg.guetzli.jpg 82 | ed14d00d18dc1b810ad595db079ce8897d00afc39e9cd09dcc122eb8c9ab59f6 red-room.jpg.guetzli.jpg 83 | b1ca1634719fda14c88dea08f99fab9cd5450cc41dd32385387fd774e33896ce red-room.png.guetzli.jpg 84 | ed14d00d18dc1b810ad595db079ce8897d00afc39e9cd09dcc122eb8c9ab59f6 red-room-progressive.jpg.guetzli.jpg 85 | c5499fdc97b3ae02d77ea12140d6da8ad645406e66adc88250a3c980bb70fe7d red-rose-420.jpg.guetzli.jpg 86 | f9a97e475af9127ea6d6d4d41fec52330ca075aae707185d90910fe198695e8d red-rose.jpg.guetzli.jpg 87 | 22f21955e7078745d03c1eb1985b8c5ffbd0b615870071a821102c44bd94af97 red-rose.png.guetzli.jpg 88 | f9a97e475af9127ea6d6d4d41fec52330ca075aae707185d90910fe198695e8d red-rose-progressive.jpg.guetzli.jpg 89 | 4df6d9b244c2d02cacff35ada998da3be13d1c9f5e42d4a2ab9b4725fc78dfa5 rgb-420.jpg.guetzli.jpg 90 | 19256b30557be9dc6a7effe6418f2c1ba6e624940ef1f41c0ca71e356963014c rgb.jpg.guetzli.jpg 91 | c1f8e4161a8b6baddea1d279f4d490670560d9c5d1161b66ee101c4250d8dd48 rgb.png.guetzli.jpg 92 | 19256b30557be9dc6a7effe6418f2c1ba6e624940ef1f41c0ca71e356963014c rgb-progressive.jpg.guetzli.jpg 93 | a2eccf2d9e63c830f6666b7082589e5e58f551af460277110b0a21f07bc8e6d6 station-420.jpg.guetzli.jpg 94 | 0d5a61eaeda6616f026bea9789620b91c47d4c4b099099d28c76708c9e9caf8f station.jpg.guetzli.jpg 95 | 3cf674f2687bee61e43ef0e57bcec15d93a945c14e4413d22c1a0ee13d64f4f2 station.png.guetzli.jpg 96 | 0d5a61eaeda6616f026bea9789620b91c47d4c4b099099d28c76708c9e9caf8f station-progressive.jpg.guetzli.jpg 97 | 632c1b8aa116847dbb3471fce2e7201eb2bd028f22ebc920ae97344bfaf8c263 stp2-420.jpg.guetzli.jpg 98 | 6e741f8d6f27c4aec93d3bd01216b28aac31f7f8f501e0cbb49249ba02e3b82a stp2.jpg.guetzli.jpg 99 | 976fd6eca7e49b097817a1424a41ba71c8d3edbdb3fe9b55db4a4a36404c0b34 stp2.png.guetzli.jpg 100 | 6e741f8d6f27c4aec93d3bd01216b28aac31f7f8f501e0cbb49249ba02e3b82a stp2-progressive.jpg.guetzli.jpg 101 | a817caaf39ca100eb14ab96295298e9ce744e9262d6e678d31e86d2990ac5c2d stp-420.jpg.guetzli.jpg 102 | b7d1652051ed7ee6e07cb4b8918ab92042573746cd5a8fd1342aeaefc3e11c26 stp.jpg.guetzli.jpg 103 | 126d2d08e936828e38d70543c576fc81021aba7010a8368842abfcd777672e9a stp.png.guetzli.jpg 104 | b7d1652051ed7ee6e07cb4b8918ab92042573746cd5a8fd1342aeaefc3e11c26 stp-progressive.jpg.guetzli.jpg 105 | cf30b2be770b1cf597cae579d7d9e027586e0b53eb022d9f875bc56152c44cd4 vflower-420.jpg.guetzli.jpg 106 | c65d52efb093cb3764dce7efdf6320728faf5fbb48545ec7de107b505abd00cb vflower.jpg.guetzli.jpg 107 | 29f303b8354443478b6f209b6e250ab40740b58cbcee34bc5669b0eb8da4ee2b vflower.png.guetzli.jpg 108 | c65d52efb093cb3764dce7efdf6320728faf5fbb48545ec7de107b505abd00cb vflower-progressive.jpg.guetzli.jpg 109 | 6c53f97edc667a5d871045fa97bd372c2a84a94a126f5d5d25d6ffadc97574c7 white-yellow-420.jpg.guetzli.jpg 110 | 7b83bd4ab679f721bc067ce86e2375c355265bb1f01668efc47423f0c707cd0b white-yellow.jpg.guetzli.jpg 111 | 62759933c7b505e531fda54bf863ad494b09a9c91262c43a715777658d29fee7 white-yellow.png.guetzli.jpg 112 | 7b83bd4ab679f721bc067ce86e2375c355265bb1f01668efc47423f0c707cd0b white-yellow-progressive.jpg.guetzli.jpg 113 | f0cea391185003b58594a9d4e43226be4e6e68ed882ebee8e0787fc129613d74 wollerau-420.jpg.guetzli.jpg 114 | afe66a4d5b26180cc2471aac20253f7f7a0064fb458bdbc8a4376819779d126f wollerau.jpg.guetzli.jpg 115 | ed223e0974fa0030ad83c20b4616105355efd5d3360fbb496956ad3d4f9e59e8 wollerau.png.guetzli.jpg 116 | afe66a4d5b26180cc2471aac20253f7f7a0064fb458bdbc8a4376819779d126f wollerau-progressive.jpg.guetzli.jpg 117 | a9f72e6805afa346e8dff15d9f113d5cf637a4a11c670b4454c9a1dedd1824f8 yellow2-420.jpg.guetzli.jpg 118 | 62295c47a2abbebd89d56ad9cbdb85fa4f3e80781bee69977058b7869de46b5c yellow2.jpg.guetzli.jpg 119 | 5be448a421e9fef23e054a683bef8e3fe19cd968a72d250944050b176600e540 yellow2.png.guetzli.jpg 120 | 62295c47a2abbebd89d56ad9cbdb85fa4f3e80781bee69977058b7869de46b5c yellow2-progressive.jpg.guetzli.jpg 121 | d268fb8e60412f56689f473da391330c594d661b80af9bd46dbfbfed7a40d5f3 yellow-420.jpg.guetzli.jpg 122 | 31a33c73f06c4b5b3abdfafff7a50e1b107b013802858a3dc405a59d333b6b8b yellow.jpg.guetzli.jpg 123 | ee5b2844b2b23ad50434539ae31ec4b3ea027595fd959d192c03553bf167ae24 yellow.png.guetzli.jpg 124 | 31a33c73f06c4b5b3abdfafff7a50e1b107b013802858a3dc405a59d333b6b8b yellow-progressive.jpg.guetzli.jpg 125 | -------------------------------------------------------------------------------- /tests/golden_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GUETZLI=${1:-bin/Release/guetzli} 4 | INPUT_DIR_PNG=$HOME/.cache/guetzli-test-corpus 5 | INPUT_DIR_JPG=$(mktemp -d) 6 | OUTPUT_DIR=$(mktemp -d) 7 | 8 | if [[ -d $INPUT_DIR_PNG ]]; then 9 | (cd $INPUT_DIR_PNG ; sha256sum -c ; exit $? ) < $(dirname $0)/png_checksums.txt || rm -r ${INPUT_DIR_PNG} 10 | fi 11 | 12 | if [[ ! -d $INPUT_DIR_PNG ]]; then 13 | mkdir -p $INPUT_DIR_PNG || exit 2 14 | curl https://storage.googleapis.com/test-image-corpus/test-corpus.tgz | tar -C $INPUT_DIR_PNG -zxf - || exit 2 15 | fi 16 | 17 | for i in $INPUT_DIR_PNG/*.png; do 18 | pngtopnm < $i | cjpeg -sample 1x1 -quality 100 > $INPUT_DIR_JPG/$(basename $i .png).jpg || exit 2 19 | pngtopnm < $i | cjpeg -sample 1x1 -progressive -quality 100 > $INPUT_DIR_JPG/$(basename $i .png)-progressive.jpg || exit 2 20 | pngtopnm < $i | cjpeg -sample 2x2,1x1,1x1 -quality 100 > $INPUT_DIR_JPG/$(basename $i .png)-420.jpg || exit 2 21 | done 22 | 23 | for i in $INPUT_DIR_PNG/*.png $INPUT_DIR_JPG/*.jpg; do 24 | echo $i $OUTPUT_DIR/$(basename $i).guetzli.jpg 25 | done | xargs -L 1 -P $(getconf _NPROCESSORS_ONLN) -t $GUETZLI 26 | 27 | if [[ -n "$UPDATE_GOLDEN" ]]; then 28 | (cd $OUTPUT_DIR ; sha256sum *) > $(dirname $0)/golden_checksums.txt 29 | else 30 | (cd $OUTPUT_DIR ; sha256sum -c) < $(dirname $0)/golden_checksums.txt 31 | fi 32 | 33 | -------------------------------------------------------------------------------- /tests/png_checksums.txt: -------------------------------------------------------------------------------- 1 | 3531f6d5d30faf9d781f444398f32495a94ad276f2654c579a489bb2014f156b bees.png 2 | 0210aa8ed8d044e10b6e816ef0f6603de1d5834a1d0d2027898fafdc7bcac396 bench2.png 3 | e1fe02c671620555d25ee4e3ed8d16a216a40d52edf1b73c0d5088cee1b19da5 bench.png 4 | 616a52b544630ed7a6b8db33ca12c1bd6aad4ca07faf8f658cf4d1981af5b0bd bicycles.png 5 | 43252838b12e987502dfc98446e474a9b1008a6a49987ea6f6692eee68d3f541 blue-rose.png 6 | 8f6a52fb6c3ffb1b2c32e47075c7e2c22975570f0da0694c4272e1cec4c05438 brake-light.png 7 | 7572fc7bb317838b3ad0a7e39154e92c04f56c172ea347e85752146da2978578 cloth.png 8 | eb7797c8929576ccd8acc27907a3f354ae19246a58d6f02279918be541359692 geranium2.png 9 | d0f99e29280546f75b2065590ef3d9bed7ba86c3f1e2fb403971c83ebc996594 geranium.png 10 | c1f96c117f607205773ce5339ee2a1076b8f99de4bf674ee0aae25984f39c243 green.png 11 | 7564f4e4693ac423581e1d496fe339dd13cbfc6b1393c0d9e8c5bd4a1f53a8e8 green-rose.png 12 | b5236607cdce8f88e42132f6760c1b61a8dc83d975cd44a0be40684eaf035294 hand.png 13 | a784868d51b5a1d170fa1ae733cced48e1fc30f0bf42c81e6a9fd664e462bb83 lichen.png 14 | ab0eff8e6b57694455bffa91e74c91a0507e61294032521caacc28128ad3cf90 minerology.png 15 | d30b95585fe03802b9d9a70d62f8ce3b7b84f1072de67efabf59b8a83b4d9eae out-of-focus.png 16 | a6e05977e62e39d5faa7154fe00d2aaa3d18f28b9f933ccd8906c2f8a1f11633 pimpinelli.png 17 | 334d783039d60b805f46a2e9e4667749bc64ccdd97bb356e5faa045311861efb pink-flower.png 18 | 390ecd976e1e73f46addd6f245efe9fd886fed7437cbf5049db02e2f6f2d6afd port.png 19 | 858018895b71dd3cc612c3939832193c2d656b2ae1a8aec7a38c2f41f61d7005 rainbow.png 20 | d81b49b0a4db09aab24f573c141899955391440ccfdfa57c060eafa76c3416a4 red-flowers.png 21 | 0ebf4139eece6a5fdaf5397ed64c7fb8b9115a607ae7f82b2e4bf56ae0405f99 red-room.png 22 | 82a845a65b2c7217f7baea1d6b63f466d70dec5783ebb4b6b41f060348d5bfb3 red-rose.png 23 | 37b9c33b7ee63788ad5f09eb8f53127ebb2fc9d9113b856e38c440fe8a78df05 rgb.png 24 | 7dae648bb5f9bf22bb3c1f51f94ef1a04ec20b981c9d5b01f42f364d5ab63c11 station.png 25 | 8241aa8f95a8b051936cd519e0205a67a9d1f48e229c6c5745575adf68f4a3ab stp2.png 26 | 03c0139181f9212e188348e2315caf73a54e213f03e872f04759ef2936f851dc stp.png 27 | 4938aa4a4527df8deecd10c4007d4a63ff8d4f81f63b9fd87c471a0b5437a50c vflower.png 28 | ada6424a72548e7b80ac58590b58d1b7a7e185ef87ebdf76841b2a573b9cf23a white-yellow.png 29 | 77a5d289b2fa19b0f72de03cad2ce311c8b3cb088a32928811b2287fbeb18ce9 wollerau.png 30 | f1dbf76f4bb7b7e79c98fd1e8572f5b9a01d1a6c0ea8a1e6361dc2b8188f094e yellow2.png 31 | 37ccbd18a347ba4d326fb8d9ae56fbadaaefca9bb5a2298b9d09f30c18616ae6 yellow.png 32 | -------------------------------------------------------------------------------- /tests/smoke_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GUETZLI=${1:-bin/Release/guetzli} 4 | BEES_PNG=$(dirname $0)/bees.png 5 | BEES_JPG=$(mktemp ${TMPDIR:-/tmp}/beesXXXX.jpg) 6 | BUTTERAUGLI=$2 7 | 8 | pngtopnm < $BEES_PNG | cjpeg -sample 1x1 -quality 100 > $BEES_JPG || exit 2 9 | 10 | function run_test() { 11 | # png/jpeg stdin/file stdout/file flags... 12 | local in= 13 | local out=$(mktemp ${TMPDIR:-/tmp}/beesXXX.guetzli.jpg) 14 | echo "Testing $@, output in $out" 15 | case "$1" in 16 | png) in=$BEES_PNG ;; 17 | jpeg) in=$BEES_JPG ;; 18 | *) exit 2 ;; 19 | esac 20 | shift 21 | local inouthandling="$1:$2" 22 | shift; shift 23 | case "$inouthandling" in 24 | file:file) $GUETZLI $@ $in $out ;; 25 | stdin:file) $GUETZLI $@ - $out < $in ;; 26 | file:stdout) $GUETZLI $@ $in - > $out ;; 27 | stdin:stdout) $GUETZLI $@ - - < $in > $out ;; 28 | *) exit 2 ;; 29 | esac 30 | test -f "$out" || { echo "$out doesn't exist"; exit 1; } 31 | djpeg < $out > /dev/null || { echo "$out is not a valid JPEG"; exit 1; } 32 | if [ -n "$BUTTERAUGLI" ]; then 33 | $BUTTERAUGLI $in $out 34 | fi 35 | rm $out 36 | echo "OK" 37 | } 38 | 39 | run_test png file file 40 | run_test png stdin file 41 | run_test jpeg file file 42 | run_test jpeg stdin file 43 | 44 | run_test png stdin stdout 45 | run_test png file stdout 46 | 47 | run_test png file stdout --verbose 48 | run_test png file stdout --nomemlimit 49 | run_test png file stdout --memlimit 100 50 | run_test png file stdout --quality 85 51 | 52 | echo $GUETZLI /dev/null /dev/null 53 | $GUETZLI /dev/null /dev/null 54 | if [[ $? -ne 1 ]]; then 55 | echo "Expected a clean failure" 56 | exit 1 57 | fi 58 | 59 | -------------------------------------------------------------------------------- /third_party/butteraugli/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "butteraugli_lib", 3 | srcs = [ 4 | "butteraugli/butteraugli.cc", 5 | "butteraugli/butteraugli.h", 6 | ], 7 | hdrs = [ 8 | "butteraugli/butteraugli.h", 9 | ], 10 | copts = ["-Wno-sign-compare"], 11 | visibility = ["//visibility:public"], 12 | ) 13 | 14 | cc_binary( 15 | name = "butteraugli", 16 | srcs = ["butteraugli/butteraugli_main.cc"], 17 | copts = ["-Wno-sign-compare"], 18 | visibility = ["//visibility:public"], 19 | deps = [ 20 | ":butteraugli_lib", 21 | "@jpeg_archive//:jpeg", 22 | "@png_archive//:png", 23 | ], 24 | ) 25 | -------------------------------------------------------------------------------- /third_party/butteraugli/README.md: -------------------------------------------------------------------------------- 1 | # butteraugli 2 | 3 | > A tool for measuring perceived differences between images 4 | 5 | ## Introduction 6 | 7 | Butteraugli is a project that estimates the psychovisual similarity of two 8 | images. It gives a score for the images that is reliable in the domain of barely 9 | noticeable differences. Butteraugli not only gives a scalar score, but also 10 | computes a spatial map of the level of differences. 11 | 12 | One of the main motivations for this project is the statistical differences in 13 | location and density of different color receptors, particularly the low density 14 | of blue cones in the fovea. Another motivation comes from more accurate modeling 15 | of ganglion cells, particularly the frequency space inhibition. 16 | 17 | ## Use 18 | 19 | Butteraugli can work as a quality metric for lossy image and video compression. 20 | On our small test corpus butteraugli performs better than our implementations of 21 | the reference methods, psnrhsv-m, ssim, and our yuv-color-space variant of ssim. 22 | One possible use is to define the quality level setting used in a jpeg 23 | compressor, or to compare two or more compression methods at the same level of 24 | psychovisual differences. 25 | 26 | Butteraugli is intended to be a research tool more than a practical tool for 27 | choosing compression formats. We don't know how well butteraugli performs with 28 | major deformations -- we have mostly tuned it within a small range of quality, 29 | roughly corresponding to jpeg qualities 90 to 95. 30 | 31 | ## Interface 32 | 33 | Only a C++ interface is provided. The interface takes two images and outputs a 34 | map together with a scalar value defining the difference. The scalar value can 35 | be compared to two reference values that divide the value space into three 36 | experience classes: 'great', 'acceptable' and 'not acceptable'. 37 | 38 | ## Build instructions 39 | 40 | Install [Bazel](http://bazel.build) by following the 41 | [instructions](https://www.bazel.build/docs/install.html). Run `bazel build -c opt 42 | //:butteraugli` in the directory that contains this README file to build the 43 | [command-line utility](#cmdline-tool). If you want to use Butteraugli as a 44 | library, depend on the `//:butteraugli_lib` target. 45 | 46 | Alternatively, you can use the Makefile provided in the `butteraugli` directory, 47 | after ensuring that [libpng](http://www.libpng.org/) and 48 | [libjpeg](http://ijg.org/) are installed. On some systems you might need to also 49 | install corresponding `-dev` packages. 50 | 51 | The code is portable and also compiles on Windows after defining 52 | `_CRT_SECURE_NO_WARNINGS` in the project settings. 53 | 54 | ## Command-line utility {#cmdline-tool} 55 | 56 | Butteraugli, apart from the library, comes bundled with a comparison tool. The 57 | comparison tool supports PNG and JPG images as inputs. To compare images, run: 58 | 59 | ``` 60 | butteraugli image1.{png|jpg} image2.{png|jpg} 61 | ``` 62 | 63 | The tool can also produce a heatmap of differences between images. The heatmap 64 | will be output as a PNM image. To produce one, run: 65 | 66 | ``` 67 | butteraugli image1.{png|jpg} image2.{png|jpg} heatmap.pnm 68 | ``` 69 | -------------------------------------------------------------------------------- /third_party/butteraugli/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "butteraugli") 2 | 3 | new_http_archive( 4 | name = "png_archive", 5 | url = "http://github.com/glennrp/libpng/archive/v1.2.57.zip", 6 | sha256 = "a941dc09ca00148fe7aaf4ecdd6a67579c293678ed1e1cf633b5ffc02f4f8cf7", 7 | strip_prefix = "libpng-1.2.57", 8 | build_file = "png.BUILD", 9 | ) 10 | 11 | new_http_archive( 12 | name = "zlib_archive", 13 | url = "http://zlib.net/fossils/zlib-1.2.10.tar.gz", 14 | sha256 = "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017", 15 | strip_prefix = "zlib-1.2.10", 16 | build_file = "zlib.BUILD", 17 | ) 18 | 19 | new_http_archive( 20 | name = "jpeg_archive", 21 | url = "http://www.ijg.org/files/jpegsrc.v9b.tar.gz", 22 | sha256 = "240fd398da741669bf3c90366f58452ea59041cacc741a489b99f2f6a0bad052", 23 | strip_prefix = "jpeg-9b", 24 | build_file = "jpeg.BUILD", 25 | ) 26 | -------------------------------------------------------------------------------- /third_party/butteraugli/butteraugli/Makefile: -------------------------------------------------------------------------------- 1 | LDLIBS += -lpng -ljpeg 2 | CXXFLAGS += -std=c++11 -I.. 3 | LINK.o = $(LINK.cc) 4 | 5 | all: butteraugli.o butteraugli_main.o butteraugli 6 | 7 | butteraugli: butteraugli.o butteraugli_main.o 8 | -------------------------------------------------------------------------------- /third_party/butteraugli/jpeg.BUILD: -------------------------------------------------------------------------------- 1 | # Description: 2 | # The Independent JPEG Group's JPEG runtime library. 3 | 4 | licenses(["notice"]) # custom notice-style license, see LICENSE 5 | 6 | cc_library( 7 | name = "jpeg", 8 | srcs = [ 9 | "cderror.h", 10 | "cdjpeg.h", 11 | "jaricom.c", 12 | "jcapimin.c", 13 | "jcapistd.c", 14 | "jcarith.c", 15 | "jccoefct.c", 16 | "jccolor.c", 17 | "jcdctmgr.c", 18 | "jchuff.c", 19 | "jcinit.c", 20 | "jcmainct.c", 21 | "jcmarker.c", 22 | "jcmaster.c", 23 | "jcomapi.c", 24 | "jconfig.h", 25 | "jcparam.c", 26 | "jcprepct.c", 27 | "jcsample.c", 28 | "jctrans.c", 29 | "jdapimin.c", 30 | "jdapistd.c", 31 | "jdarith.c", 32 | "jdatadst.c", 33 | "jdatasrc.c", 34 | "jdcoefct.c", 35 | "jdcolor.c", 36 | "jdct.h", 37 | "jddctmgr.c", 38 | "jdhuff.c", 39 | "jdinput.c", 40 | "jdmainct.c", 41 | "jdmarker.c", 42 | "jdmaster.c", 43 | "jdmerge.c", 44 | "jdpostct.c", 45 | "jdsample.c", 46 | "jdtrans.c", 47 | "jerror.c", 48 | "jfdctflt.c", 49 | "jfdctfst.c", 50 | "jfdctint.c", 51 | "jidctflt.c", 52 | "jidctfst.c", 53 | "jidctint.c", 54 | "jinclude.h", 55 | "jmemmgr.c", 56 | "jmemnobs.c", 57 | "jmemsys.h", 58 | "jmorecfg.h", 59 | "jquant1.c", 60 | "jquant2.c", 61 | "jutils.c", 62 | "jversion.h", 63 | "transupp.h", 64 | ], 65 | hdrs = [ 66 | "jerror.h", 67 | "jpegint.h", 68 | "jpeglib.h", 69 | ], 70 | includes = ["."], 71 | visibility = ["//visibility:public"], 72 | ) 73 | 74 | genrule( 75 | name = "configure", 76 | outs = ["jconfig.h"], 77 | cmd = "cat <$@\n" + 78 | "#define HAVE_PROTOTYPES 1\n" + 79 | "#define HAVE_UNSIGNED_CHAR 1\n" + 80 | "#define HAVE_UNSIGNED_SHORT 1\n" + 81 | "#define HAVE_STDDEF_H 1\n" + 82 | "#define HAVE_STDLIB_H 1\n" + 83 | "#ifdef WIN32\n" + 84 | "#define INLINE __inline\n" + 85 | "#else\n" + 86 | "#define INLINE __inline__\n" + 87 | "#endif\n" + 88 | "EOF\n", 89 | ) 90 | -------------------------------------------------------------------------------- /third_party/butteraugli/png.BUILD: -------------------------------------------------------------------------------- 1 | # Description: 2 | # libpng is the official PNG reference library. 3 | 4 | licenses(["notice"]) # BSD/MIT-like license 5 | 6 | cc_library( 7 | name = "png", 8 | srcs = [ 9 | "png.c", 10 | "pngerror.c", 11 | "pngget.c", 12 | "pngmem.c", 13 | "pngpread.c", 14 | "pngread.c", 15 | "pngrio.c", 16 | "pngrtran.c", 17 | "pngrutil.c", 18 | "pngset.c", 19 | "pngtrans.c", 20 | "pngwio.c", 21 | "pngwrite.c", 22 | "pngwtran.c", 23 | "pngwutil.c", 24 | ], 25 | hdrs = [ 26 | "png.h", 27 | "pngconf.h", 28 | ], 29 | includes = ["."], 30 | linkopts = ["-lm"], 31 | visibility = ["//visibility:public"], 32 | deps = ["@zlib_archive//:zlib"], 33 | ) 34 | -------------------------------------------------------------------------------- /third_party/butteraugli/zlib.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | licenses(["notice"]) # BSD/MIT-like license (for zlib) 4 | 5 | cc_library( 6 | name = "zlib", 7 | srcs = [ 8 | "adler32.c", 9 | "compress.c", 10 | "crc32.c", 11 | "crc32.h", 12 | "deflate.c", 13 | "deflate.h", 14 | "gzclose.c", 15 | "gzguts.h", 16 | "gzlib.c", 17 | "gzread.c", 18 | "gzwrite.c", 19 | "infback.c", 20 | "inffast.c", 21 | "inffast.h", 22 | "inffixed.h", 23 | "inflate.c", 24 | "inflate.h", 25 | "inftrees.c", 26 | "inftrees.h", 27 | "trees.c", 28 | "trees.h", 29 | "uncompr.c", 30 | "zconf.h", 31 | "zutil.c", 32 | "zutil.h", 33 | ], 34 | hdrs = ["zlib.h"], 35 | includes = ["."], 36 | ) 37 | -------------------------------------------------------------------------------- /tools/guetzli-compare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import glob 6 | import sys 7 | import subprocess 8 | 9 | BA_CMDLINE = './butteraugli {0} {1} {2}' 10 | GUETZLI_CMDLINE = './guetzli -quality {2} {0} {1}' 11 | OTHER_CMDLINE = sys.argv[3] 12 | 13 | def run(cmdline): 14 | print('running {}'.format(cmdline), file=sys.stderr) 15 | return subprocess.check_output(cmdline, shell=True) 16 | 17 | def size(filename): 18 | return os.stat(filename).st_size 19 | 20 | def ba_distance(orig, compressed): 21 | return float(run(BA_CMDLINE.format(orig, compressed, compressed + ".diffmap.pnm"))) 22 | 23 | def handle_png(png): 24 | other_jpeg = png + "." + sys.argv[1] + ".other.jpg" 25 | guetzli_jpeg = png + "." + sys.argv[1] + ".guetzli.jpg" 26 | run(OTHER_CMDLINE.format(png, other_jpeg)) 27 | other_distance = ba_distance(png, other_jpeg) 28 | left = 84.0 29 | right = 110.0 30 | while right - left > 0.05: 31 | q = (left + right) / 2 32 | run(GUETZLI_CMDLINE.format(png, guetzli_jpeg, q)) 33 | guetzli_distance = ba_distance(png, guetzli_jpeg) 34 | if guetzli_distance < other_distance: 35 | right = q 36 | else: 37 | left = q 38 | run(GUETZLI_CMDLINE.format(png, guetzli_jpeg, right)) 39 | guetzli_distance = ba_distance(png, guetzli_jpeg) 40 | assert guetzli_distance < other_distance 41 | return (size(guetzli_jpeg), size(other_jpeg)) 42 | 43 | pngs = glob.glob(sys.argv[2]) 44 | sizes = (0, 0) 45 | for png in pngs: 46 | this_size = handle_png(png) 47 | print(png, this_size) 48 | sizes = (sizes[0] + this_size[0], sizes[1] + this_size[1]) 49 | print(sizes) 50 | --------------------------------------------------------------------------------