├── .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 |

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 | [](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