├── CMakeLists.txt ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── COPYING ├── Makefile ├── README ├── README.zopflipng ├── go ├── zopfli │ ├── zopfli.go │ └── zopfli_test.go └── zopflipng │ ├── testdata │ └── zoidberg.png │ ├── zopflipng.go │ └── zopflipng_test.go └── src ├── zopfli ├── blocksplitter.c ├── blocksplitter.h ├── cache.c ├── cache.h ├── deflate.c ├── deflate.h ├── gzip_container.c ├── gzip_container.h ├── hash.c ├── hash.h ├── katajainen.c ├── katajainen.h ├── lz77.c ├── lz77.h ├── squeeze.c ├── squeeze.h ├── symbols.h ├── tree.c ├── tree.h ├── util.c ├── util.h ├── zlib_container.c ├── zlib_container.h ├── zopfli.h ├── zopfli_bin.c └── zopfli_lib.c └── zopflipng ├── lodepng ├── lodepng.cpp ├── lodepng.h ├── lodepng_util.cpp └── lodepng_util.h ├── zopflipng_bin.cc ├── zopflipng_lib.cc └── zopflipng_lib.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.11) 2 | 3 | project(Zopfli) 4 | 5 | # Check if Zopfli is the top-level project (standalone), or a subproject 6 | set(zopfli_standalone FALSE) 7 | get_directory_property(zopfli_parent_directory PARENT_DIRECTORY) 8 | if(zopfli_parent_directory STREQUAL "") 9 | set(zopfli_standalone TRUE) 10 | endif() 11 | unset(zopfli_parent_directory) 12 | 13 | # 14 | # Options 15 | # 16 | 17 | # ZOPFLI_BUILD_SHARED controls if Zopfli libraries are built as shared or 18 | # static 19 | # 20 | # It defaults to the value of BUILD_SHARED_LIBS if set, and in most cases 21 | # that should be used instead. The purpose of ZOPFLI_BUILD_SHARED is to allow 22 | # overriding it when built as a subproject. 23 | set(zopfli_shared_default OFF) 24 | if(DEFINED BUILD_SHARED_LIBS) 25 | set(zopfli_shared_default ${BUILD_SHARED_LIBS}) 26 | endif() 27 | option(ZOPFLI_BUILD_SHARED "Build Zopfli with shared libraries" ${zopfli_shared_default}) 28 | unset(zopfli_shared_default) 29 | 30 | # ZOPFLI_BUILD_INSTALL controls if Zopfli adds an install target to the build 31 | # 32 | # When built standalone or as a shared library subproject, the default is ON, 33 | # and for static library subproject the default is OFF. 34 | if(zopfli_standalone OR ZOPFLI_BUILD_SHARED) 35 | option(ZOPFLI_BUILD_INSTALL "Add Zopfli install target" ON) 36 | else() 37 | option(ZOPFLI_BUILD_INSTALL "Add Zopfli install target" OFF) 38 | endif() 39 | 40 | # ZOPFLI_DEFAULT_RELEASE enables changing empty build type to Release 41 | # 42 | # Make based single-configuration generators default to an empty build type, 43 | # which might be surprising, but could be useful if you want full control over 44 | # compiler and linker flags. When ZOPFLI_DEFAULT_RELEASE is ON, change an 45 | # empty default build type to Release. 46 | option(ZOPFLI_DEFAULT_RELEASE "If CMAKE_BUILD_TYPE is empty, default to Release" ON) 47 | 48 | if(zopfli_standalone AND ZOPFLI_DEFAULT_RELEASE) 49 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 50 | message(STATUS "CMAKE_BUILD_TYPE empty, defaulting to Release") 51 | set(CMAKE_BUILD_TYPE Release) 52 | endif() 53 | endif() 54 | 55 | # 56 | # Library version 57 | # 58 | set(ZOPFLI_VERSION_MAJOR 1) 59 | set(ZOPFLI_VERSION_MINOR 0) 60 | set(ZOPFLI_VERSION_PATCH 3) 61 | set(ZOPFLI_VERSION ${ZOPFLI_VERSION_MAJOR}.${ZOPFLI_VERSION_MINOR}.${ZOPFLI_VERSION_PATCH}) 62 | 63 | if(ZOPFLI_BUILD_SHARED) 64 | set(zopfli_library_type SHARED) 65 | else() 66 | set(zopfli_library_type STATIC) 67 | endif() 68 | 69 | include(GNUInstallDirs) 70 | 71 | # 72 | # libzopfli 73 | # 74 | add_library(libzopfli ${zopfli_library_type} 75 | src/zopfli/blocksplitter.c 76 | src/zopfli/cache.c 77 | src/zopfli/deflate.c 78 | src/zopfli/gzip_container.c 79 | src/zopfli/hash.c 80 | src/zopfli/katajainen.c 81 | src/zopfli/lz77.c 82 | src/zopfli/squeeze.c 83 | src/zopfli/tree.c 84 | src/zopfli/util.c 85 | src/zopfli/zlib_container.c 86 | src/zopfli/zopfli_lib.c 87 | ) 88 | target_include_directories(libzopfli 89 | INTERFACE 90 | $ 91 | $ 92 | ) 93 | set_target_properties(libzopfli PROPERTIES 94 | OUTPUT_NAME zopfli 95 | VERSION ${ZOPFLI_VERSION} 96 | SOVERSION ${ZOPFLI_VERSION_MAJOR} 97 | ) 98 | if(UNIX AND NOT (BEOS OR HAIKU)) 99 | target_link_libraries(libzopfli m) 100 | endif() 101 | 102 | # 103 | # libzopflipng 104 | # 105 | add_library(libzopflipng ${zopfli_library_type} 106 | src/zopflipng/zopflipng_lib.cc 107 | src/zopflipng/lodepng/lodepng.cpp 108 | src/zopflipng/lodepng/lodepng_util.cpp 109 | ) 110 | target_link_libraries(libzopflipng libzopfli) 111 | target_include_directories(libzopflipng 112 | INTERFACE 113 | $ 114 | $ 115 | ) 116 | set_target_properties(libzopflipng PROPERTIES 117 | OUTPUT_NAME zopflipng 118 | VERSION ${ZOPFLI_VERSION} 119 | SOVERSION ${ZOPFLI_VERSION_MAJOR} 120 | ) 121 | 122 | # MSVC does not export symbols by default when building a DLL, this is a 123 | # workaround for recent versions of CMake 124 | if(MSVC AND ZOPFLI_BUILD_SHARED) 125 | if(CMAKE_VERSION VERSION_LESS 3.4) 126 | message(WARNING "Automatic export of all symbols to DLL not supported until CMake 3.4") 127 | else() 128 | set_target_properties(libzopfli PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) 129 | set_target_properties(libzopflipng PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) 130 | endif() 131 | endif() 132 | 133 | # 134 | # zopfli 135 | # 136 | add_executable(zopfli src/zopfli/zopfli_bin.c) 137 | target_link_libraries(zopfli libzopfli) 138 | if(MSVC) 139 | target_compile_definitions(zopfli PRIVATE _CRT_SECURE_NO_WARNINGS) 140 | endif() 141 | 142 | # 143 | # zopflipng 144 | # 145 | add_executable(zopflipng src/zopflipng/zopflipng_bin.cc) 146 | target_link_libraries(zopflipng libzopflipng) 147 | if(MSVC) 148 | target_compile_definitions(zopflipng PRIVATE _CRT_SECURE_NO_WARNINGS) 149 | endif() 150 | 151 | # Create aliases 152 | # 153 | # Makes targets available to projects using Zopfli as a subproject using the 154 | # same names as in the config file package. 155 | if(NOT CMAKE_VERSION VERSION_LESS 3.0) 156 | add_library(Zopfli::libzopfli ALIAS libzopfli) 157 | add_library(Zopfli::libzopflipng ALIAS libzopflipng) 158 | add_executable(Zopfli::zopfli ALIAS zopfli) 159 | add_executable(Zopfli::zopflipng ALIAS zopflipng) 160 | endif() 161 | 162 | # 163 | # Install 164 | # 165 | if(ZOPFLI_BUILD_INSTALL) 166 | # Install binaries, libraries, and headers 167 | install(TARGETS libzopfli libzopflipng zopfli zopflipng 168 | EXPORT ZopfliTargets 169 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 170 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 171 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 172 | ) 173 | install(FILES src/zopfli/zopfli.h src/zopflipng/zopflipng_lib.h 174 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 175 | ) 176 | 177 | # Install config file package 178 | # 179 | # This allows CMake based projects to use the installed libraries with 180 | # find_package(Zopfli). 181 | if(NOT CMAKE_VERSION VERSION_LESS 3.0) 182 | include(CMakePackageConfigHelpers) 183 | write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/ZopfliConfigVersion.cmake 184 | VERSION ${ZOPFLI_VERSION} 185 | COMPATIBILITY SameMajorVersion 186 | ) 187 | # Since we have no dependencies, use export file directly as config file 188 | install(EXPORT ZopfliTargets 189 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Zopfli 190 | NAMESPACE Zopfli:: 191 | FILE ZopfliConfig.cmake 192 | ) 193 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ZopfliConfigVersion.cmake 194 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Zopfli 195 | ) 196 | endif() 197 | endif() 198 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) 6 | (CLA), which you can do online. The CLA is necessary mainly because you own the 7 | copyright to your changes, even after your contribution becomes part of our 8 | codebase, so we need your permission to use and distribute your code. We also 9 | need to be sure of various other things—for instance that you'll tell us if you 10 | know that your code infringes on other people's patents. You don't have to sign 11 | the CLA until after you've submitted your code for review and a member has 12 | approved it, but you must do it before we can put your code into our codebase. 13 | Before you start working on a larger contribution, you should get in touch with 14 | us first through the issue tracker with your idea so that we can help out and 15 | possibly guide you. Coordinating up front makes it much easier to avoid 16 | frustration later on. 17 | 18 | ### Code reviews 19 | All submissions, including submissions by project members, require review. We 20 | use Github pull requests for this purpose. 21 | 22 | ### The small print 23 | Contributions made by corporations are covered by a different agreement than 24 | the one above, the Software Grant and Corporate Contributor License Agreement. 25 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Mark Adler 2 | Jyrki Alakuijala 3 | Frédéric Kayser 4 | Jeffrey Lim 5 | Daniel Reed 6 | Huzaifa Sidhpurwala 7 | Péter Szabó 8 | Lode Vandevenne 9 | Derek Buitenhuis 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2011 Google Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | CXX ?= g++ 3 | 4 | override CFLAGS := -W -Wall -Wextra -ansi -pedantic -lm -O3 -Wno-unused-function -fPIC $(CFLAGS) 5 | override CXXFLAGS := -W -Wall -Wextra -ansi -pedantic -O3 -fPIC $(CXXFLAGS) 6 | 7 | ZOPFLILIB_SRC = src/zopfli/blocksplitter.c src/zopfli/cache.c\ 8 | src/zopfli/deflate.c src/zopfli/gzip_container.c\ 9 | src/zopfli/hash.c src/zopfli/katajainen.c\ 10 | src/zopfli/lz77.c src/zopfli/squeeze.c\ 11 | src/zopfli/tree.c src/zopfli/util.c\ 12 | src/zopfli/zlib_container.c src/zopfli/zopfli_lib.c 13 | ZOPFLILIB_OBJ := $(patsubst %.c,obj/%.o,$(ZOPFLILIB_SRC)) 14 | ZOPFLIBIN_SRC := src/zopfli/zopfli_bin.c 15 | ZOPFLIBIN_OBJ := $(patsubst %.c,obj/%.o,$(ZOPFLIBIN_SRC)) 16 | LODEPNG_SRC := src/zopflipng/lodepng/lodepng.cpp src/zopflipng/lodepng/lodepng_util.cpp 17 | LODEPNG_OBJ := $(patsubst %.cpp,obj/%.o,$(LODEPNG_SRC)) 18 | ZOPFLIPNGLIB_SRC := src/zopflipng/zopflipng_lib.cc 19 | ZOPFLIPNGLIB_OBJ := $(patsubst %.cc,obj/%.o,$(ZOPFLIPNGLIB_SRC)) 20 | ZOPFLIPNGBIN_SRC := src/zopflipng/zopflipng_bin.cc 21 | ZOPFLIPNGBIN_OBJ := $(patsubst %.cc,obj/%.o,$(ZOPFLIPNGBIN_SRC)) 22 | 23 | .PHONY: all libzopfli libzopflipng 24 | 25 | all: zopfli libzopfli libzopfli.a zopflipng libzopflipng libzopflipng.a 26 | 27 | obj/%.o: %.c 28 | @mkdir -p `dirname $@` 29 | $(CC) $(CFLAGS) -c $< -o $@ 30 | 31 | obj/%.o: %.cc 32 | @mkdir -p `dirname $@` 33 | $(CXX) $(CXXFLAGS) -c $< -o $@ 34 | 35 | obj/%.o: %.cpp 36 | @mkdir -p `dirname $@` 37 | $(CXX) $(CXXFLAGS) -c $< -o $@ 38 | 39 | # Zopfli binary 40 | zopfli: $(ZOPFLILIB_OBJ) $(ZOPFLIBIN_OBJ) 41 | $(CC) $^ $(CFLAGS) -o $@ $(LDFLAGS) 42 | 43 | # Zopfli shared library 44 | libzopfli: $(ZOPFLILIB_OBJ) 45 | $(CC) $^ $(CFLAGS) -shared -Wl,-soname,libzopfli.so.1 -o libzopfli.so.1.0.3 $(LDFLAGS) 46 | 47 | # Zopfli static library 48 | libzopfli.a: $(ZOPFLILIB_OBJ) 49 | ar rcs $@ $^ 50 | 51 | # ZopfliPNG binary 52 | zopflipng: $(ZOPFLILIB_OBJ) $(LODEPNG_OBJ) $(ZOPFLIPNGLIB_OBJ) $(ZOPFLIPNGBIN_OBJ) 53 | $(CXX) $^ $(CFLAGS) -o $@ $(LDFLAGS) 54 | 55 | # ZopfliPNG shared library 56 | libzopflipng: $(ZOPFLILIB_OBJ) $(LODEPNG_OBJ) $(ZOPFLIPNGLIB_OBJ) 57 | $(CXX) $^ $(CFLAGS) --shared -Wl,-soname,libzopflipng.so.1 -o libzopflipng.so.1.0.3 $(LDFLAGS) 58 | 59 | # ZopfliPNG static library 60 | libzopflipng.a: $(LODEPNG_OBJ) $(ZOPFLIPNGLIB_OBJ) 61 | ar rcs $@ $^ 62 | 63 | # Remove all libraries and binaries 64 | clean: 65 | rm -f zopflipng zopfli $(ZOPFLILIB_OBJ) $(ZOPFLIBIN_OBJ) $(LODEPNG_OBJ) $(ZOPFLIPNGLIB_OBJ) $(ZOPFLIPNGBIN_OBJ) libzopfli* 66 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Zopfli Compression Algorithm is a compression library programmed in C to perform 2 | very good, but slow, deflate or zlib compression. 3 | 4 | The basic function to compress data is ZopfliCompress in zopfli.h. Use the 5 | ZopfliOptions object to set parameters that affect the speed and compression. 6 | Use the ZopfliInitOptions function to place the default values in the 7 | ZopfliOptions first. 8 | 9 | ZopfliCompress supports deflate, gzip and zlib output format with a parameter. 10 | To support only one individual format, you can instead use ZopfliDeflate in 11 | deflate.h, ZopfliZlibCompress in zlib_container.h or ZopfliGzipCompress in 12 | gzip_container.h. 13 | 14 | ZopfliDeflate creates a valid deflate stream in memory, see: 15 | http://www.ietf.org/rfc/rfc1951.txt 16 | ZopfliZlibCompress creates a valid zlib stream in memory, see: 17 | http://www.ietf.org/rfc/rfc1950.txt 18 | ZopfliGzipCompress creates a valid gzip stream in memory, see: 19 | http://www.ietf.org/rfc/rfc1952.txt 20 | 21 | This library can only compress, not decompress. Existing zlib or deflate 22 | libraries can decompress the data. 23 | 24 | zopfli_bin.c is separate from the library and contains an example program to 25 | create very well compressed gzip files. Currently the makefile builds this 26 | program with the library statically linked in. 27 | 28 | The source code of Zopfli is under src/zopfli. Build instructions: 29 | 30 | To build zopfli, compile all .c source files under src/zopfli to a single binary 31 | with C, and link to the standard C math library, e.g.: 32 | gcc src/zopfli/*.c -O2 -W -Wall -Wextra -Wno-unused-function -ansi -pedantic -lm -o zopfli 33 | 34 | A makefile is provided as well, but only for linux. Use "make" to build the 35 | binary, "make libzopfli" to build it as a shared library. For other platforms, 36 | please use the build instructions above instead. 37 | 38 | Zopfli Compression Algorithm was created by Lode Vandevenne and Jyrki 39 | Alakuijala, based on an algorithm by Jyrki Alakuijala. 40 | -------------------------------------------------------------------------------- /README.zopflipng: -------------------------------------------------------------------------------- 1 | ZopfliPNG is a command line program to optimize the Portable Network Graphics 2 | (PNG) images. This version has the following features: 3 | - uses Zopfli compression for the Deflate compression, 4 | - compares several strategies for choosing scanline filter codes, 5 | - chooses a suitable color type to losslessly encode the image, 6 | - removes all chunks that are unimportant for the typical web use (metadata, 7 | text, etc...), 8 | - optionally alters the hidden colors of fully transparent pixels for more 9 | compression, and, 10 | - optionally converts 16-bit color channels to 8-bit. 11 | 12 | This is an alpha-release for testing while improvements, particularly to add 13 | palette selection, are still being made. Feedback and bug reports are welcome. 14 | 15 | Important: 16 | 17 | This PNG optimizer removes ancillary chunks (pieces of metadata) from the 18 | PNG image that normally do not affect rendering. However in special 19 | circumstances you may wish to keep some. For example for a design using 20 | custom gamma correction, keeping it may be desired. Visually check in the 21 | target renderer after using ZopfliPNG. Use --keepchunks to keep chunks, e.g. 22 | --keepchunks=gAMA,pHYs to keep gamma and DPI information. This will increase 23 | file size. The following page contains a list of ancillary PNG chunks: 24 | http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html 25 | 26 | Build instructions: 27 | 28 | To build ZopfliPNG, compile all .c, .cc and .cpp files from src/zopfli, 29 | src/zopflipng and src/zopflipng/lodepng, except src/zopfli/zopfli_bin.c, to a 30 | single binary with C++, e.g.: 31 | g++ src/zopfli/{blocksplitter,cache,deflate,gzip_container,hash,katajainen,lz77,squeeze,tree,util,zlib_container,zopfli_lib}.c src/zopflipng/*.cc src/zopflipng/lodepng/*.cpp -O2 -W -Wall -Wextra -Wno-unused-function -ansi -pedantic -o zopflipng 32 | 33 | A makefile is provided as well, but only for linux: use "make zopflipng" with 34 | the Zopfli makefile. For other platforms, please use the build instructions 35 | above instead. 36 | 37 | The main compression algorithm in ZopfliPNG is ported from WebP lossless, but 38 | naturally cannot give as much compression gain for PNGs as it does for a more 39 | modern compression codec like WebP 40 | https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification. 41 | 42 | Compared to libpng -- an often used PNG encoder implementation -- ZopfliPNG uses 43 | 2-3 orders of magnitude more CPU time for compression. Initial testing using a 44 | corpus of 1000 PNGs with translucency, randomly selected from the internet, 45 | gives a compression improvement of 12% compared to convert -q 95, but only 0.5% 46 | compared to pngout (from better of /f0 and /f5 runs). 47 | 48 | By releasing this software we hope to make images on the web load faster without 49 | a new image format, but the opportunities for optimization within PNG are 50 | limited. When targeting Android, Chrome, Opera, and Yandex browsers, or by using 51 | suitable plugins for other browsers, it is good to note that WebP lossless 52 | images are still 26 % smaller than images recompressed with ZopfliPNG. 53 | 54 | 2013-05-07, Lode Vandevenne and Jyrki Alakuijala 55 | -------------------------------------------------------------------------------- /go/zopfli/zopfli.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package zopfli provides a simple Go interface for Zopfli compression. 16 | package zopfli 17 | 18 | /* 19 | #cgo LDFLAGS: -lzopfli -lm 20 | #include // for INT_MAX 21 | #include // for free() 22 | #include // for memmove() 23 | #include "zopfli.h" 24 | */ 25 | import "C" 26 | import "unsafe" 27 | 28 | // Zopfli can't handle empty input, so we use a static result. 29 | const emptyGzip = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00" 30 | 31 | // Gzip compresses data with Zopfli using default settings and gzip format. 32 | // The Zopfli library does not return errors, and there are no (detectable) 33 | // failure cases, hence no error return. 34 | func Gzip(inputSlice []byte) []byte { 35 | var options C.struct_ZopfliOptions 36 | C.ZopfliInitOptions(&options) 37 | 38 | inputSize := (C.size_t)(len(inputSlice)) 39 | if inputSize == 0 { 40 | return []byte(emptyGzip) 41 | } 42 | input := (*C.uchar)(unsafe.Pointer(&inputSlice[0])) 43 | var compressed *C.uchar 44 | var compressedLength C.size_t 45 | 46 | C.ZopfliCompress(&options, C.ZOPFLI_FORMAT_GZIP, 47 | input, inputSize, 48 | &compressed, &compressedLength) 49 | defer C.free(unsafe.Pointer(compressed)) 50 | 51 | // GoBytes only accepts int, not C.size_t. The code below does the same minus 52 | // protection against zero-length values, but compressedLength is never 0 due 53 | // to headers. 54 | result := make([]byte, compressedLength) 55 | C.memmove(unsafe.Pointer(&result[0]), unsafe.Pointer(compressed), 56 | compressedLength) 57 | return result 58 | } 59 | -------------------------------------------------------------------------------- /go/zopfli/zopfli_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package zopfli 15 | 16 | import ( 17 | "bytes" 18 | "compress/gzip" 19 | "io/ioutil" 20 | "math/rand" 21 | "strings" 22 | "testing" 23 | ) 24 | 25 | func getRandomBytes(length uint64) []byte { 26 | rng := rand.New(rand.NewSource(1)) // Make test repeatable. 27 | data := make([]byte, length) 28 | for i := uint64(0); i < length; i++ { 29 | data[i] = (byte)(rng.Int()) 30 | } 31 | return data 32 | } 33 | 34 | // TestGzip verifies that Gzip compresses data correctly. 35 | func TestGzip(t *testing.T) { 36 | compressibleString := "compressthis" + strings.Repeat("_foobar", 1000) + "$" 37 | 38 | for _, test := range []struct { 39 | name string 40 | data []byte 41 | maxSize int 42 | }{ 43 | {"compressible string", []byte(compressibleString), 500}, 44 | {"random binary data", getRandomBytes(3000), 3100}, 45 | {"empty string", []byte(""), 20}, 46 | } { 47 | compressed := Gzip(test.data) 48 | gzipReader, err := gzip.NewReader(bytes.NewReader(compressed)) 49 | if err != nil { 50 | t.Errorf("%s: gzip.NewReader: got error %v, expected no error", 51 | test.name, err) 52 | continue 53 | } 54 | decompressed, err := ioutil.ReadAll(gzipReader) 55 | if err != nil { 56 | t.Errorf("%s: reading gzip stream: got error %v, expected no error", 57 | test.name, err) 58 | continue 59 | } 60 | if bytes.Compare(test.data, decompressed) != 0 { 61 | t.Errorf("%s: mismatch between input and decompressed data", test.name) 62 | continue 63 | } 64 | if test.maxSize > 0 && len(compressed) > test.maxSize { 65 | t.Errorf("%s: compressed data is %d bytes, expected %d or less", 66 | test.name, len(compressed), test.maxSize) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /go/zopflipng/testdata/zoidberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/zopfli/ccf9f0588d4a4509cb1040310ec122243e670ee6/go/zopflipng/testdata/zoidberg.png -------------------------------------------------------------------------------- /go/zopflipng/zopflipng.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package zopflipng 15 | 16 | import ( 17 | "fmt" 18 | ) 19 | 20 | /* 21 | #cgo LDFLAGS: -lzopflipng -lzopfli -lstdc++ -lm 22 | #include 23 | #include 24 | #include "zopflipng_lib.h" 25 | */ 26 | import "C" 27 | import "unsafe" 28 | 29 | // Options allows overriding of some internal parameters. 30 | type Options struct { 31 | LossyTransparent bool 32 | Lossy8bit bool 33 | NumIterations int 34 | NumIterationsLarge int 35 | } 36 | 37 | // NewOptions creates an options struct with the default parameters. 38 | func NewOptions() *Options { 39 | ret := &Options{ 40 | LossyTransparent: false, 41 | Lossy8bit: false, 42 | NumIterations: 15, 43 | NumIterationsLarge: 5, 44 | } 45 | return ret 46 | } 47 | 48 | // Compress recompresses a PNG using Zopfli. 49 | func Compress(inputSlice []byte) ([]byte, error) { 50 | return CompressWithOptions(inputSlice, NewOptions()) 51 | } 52 | 53 | // CompressWithOptions allows overriding some internal parameters. 54 | func CompressWithOptions(inputSlice []byte, options *Options) ([]byte, error) { 55 | cOptions := createCOptions(options) 56 | input := (*C.uchar)(unsafe.Pointer(&inputSlice[0])) 57 | inputSize := (C.size_t)(len(inputSlice)) 58 | var compressed *C.uchar 59 | var compressedLength C.size_t 60 | errCode := int(C.CZopfliPNGOptimize(input, inputSize, &cOptions, 0, &compressed, &compressedLength)) 61 | defer C.free(unsafe.Pointer(compressed)) 62 | if errCode != 0 { 63 | return nil, fmt.Errorf("ZopfliPng failed with code: %d", errCode) 64 | } 65 | 66 | result := make([]byte, compressedLength) 67 | C.memmove(unsafe.Pointer(&result[0]), unsafe.Pointer(compressed), compressedLength) 68 | return result, nil 69 | } 70 | 71 | func createCOptions(options *Options) C.struct_CZopfliPNGOptions { 72 | var cOptions C.struct_CZopfliPNGOptions 73 | C.CZopfliPNGSetDefaults(&cOptions) 74 | cOptions.lossy_transparent = boolToInt(options.LossyTransparent) 75 | cOptions.lossy_8bit = boolToInt(options.Lossy8bit) 76 | cOptions.num_iterations = C.int(options.NumIterations) 77 | cOptions.num_iterations_large = C.int(options.NumIterationsLarge) 78 | return cOptions 79 | } 80 | 81 | func boolToInt(b bool) C.int { 82 | if b { 83 | return C.int(1) 84 | } 85 | return C.int(0) 86 | } 87 | -------------------------------------------------------------------------------- /go/zopflipng/zopflipng_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package zopflipng 15 | 16 | import ( 17 | "io/ioutil" 18 | "testing" 19 | ) 20 | 21 | // TestCompress verifies that ZopfliPng compresses PNGs correctly. 22 | func TestCompress(t *testing.T) { 23 | path := "testdata/zoidberg.png" 24 | contents, err := ioutil.ReadFile(path) 25 | if err != nil { 26 | t.Errorf("Failed to load testdata: %s", path) 27 | } 28 | compressed, err := Compress(contents) 29 | if err != nil { 30 | t.Error("ZopfliPNG failed: ", err) 31 | } 32 | if len(compressed) >= len(contents) { 33 | t.Error("ZopfliPNG did not compress png") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/zopfli/blocksplitter.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "blocksplitter.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "deflate.h" 27 | #include "squeeze.h" 28 | #include "tree.h" 29 | #include "util.h" 30 | 31 | /* 32 | The "f" for the FindMinimum function below. 33 | i: the current parameter of f(i) 34 | context: for your implementation 35 | */ 36 | typedef double FindMinimumFun(size_t i, void* context); 37 | 38 | /* 39 | Finds minimum of function f(i) where is is of type size_t, f(i) is of type 40 | double, i is in range start-end (excluding end). 41 | Outputs the minimum value in *smallest and returns the index of this value. 42 | */ 43 | static size_t FindMinimum(FindMinimumFun f, void* context, 44 | size_t start, size_t end, double* smallest) { 45 | if (end - start < 1024) { 46 | double best = ZOPFLI_LARGE_FLOAT; 47 | size_t result = start; 48 | size_t i; 49 | for (i = start; i < end; i++) { 50 | double v = f(i, context); 51 | if (v < best) { 52 | best = v; 53 | result = i; 54 | } 55 | } 56 | *smallest = best; 57 | return result; 58 | } else { 59 | /* Try to find minimum faster by recursively checking multiple points. */ 60 | #define NUM 9 /* Good value: 9. */ 61 | size_t i; 62 | size_t p[NUM]; 63 | double vp[NUM]; 64 | size_t besti; 65 | double best; 66 | double lastbest = ZOPFLI_LARGE_FLOAT; 67 | size_t pos = start; 68 | 69 | for (;;) { 70 | if (end - start <= NUM) break; 71 | 72 | for (i = 0; i < NUM; i++) { 73 | p[i] = start + (i + 1) * ((end - start) / (NUM + 1)); 74 | vp[i] = f(p[i], context); 75 | } 76 | besti = 0; 77 | best = vp[0]; 78 | for (i = 1; i < NUM; i++) { 79 | if (vp[i] < best) { 80 | best = vp[i]; 81 | besti = i; 82 | } 83 | } 84 | if (best > lastbest) break; 85 | 86 | start = besti == 0 ? start : p[besti - 1]; 87 | end = besti == NUM - 1 ? end : p[besti + 1]; 88 | 89 | pos = p[besti]; 90 | lastbest = best; 91 | } 92 | *smallest = lastbest; 93 | return pos; 94 | #undef NUM 95 | } 96 | } 97 | 98 | /* 99 | Returns estimated cost of a block in bits. It includes the size to encode the 100 | tree and the size to encode all literal, length and distance symbols and their 101 | extra bits. 102 | 103 | litlens: lz77 lit/lengths 104 | dists: ll77 distances 105 | lstart: start of block 106 | lend: end of block (not inclusive) 107 | */ 108 | static double EstimateCost(const ZopfliLZ77Store* lz77, 109 | size_t lstart, size_t lend) { 110 | return ZopfliCalculateBlockSizeAutoType(lz77, lstart, lend); 111 | } 112 | 113 | typedef struct SplitCostContext { 114 | const ZopfliLZ77Store* lz77; 115 | size_t start; 116 | size_t end; 117 | } SplitCostContext; 118 | 119 | 120 | /* 121 | Gets the cost which is the sum of the cost of the left and the right section 122 | of the data. 123 | type: FindMinimumFun 124 | */ 125 | static double SplitCost(size_t i, void* context) { 126 | SplitCostContext* c = (SplitCostContext*)context; 127 | return EstimateCost(c->lz77, c->start, i) + EstimateCost(c->lz77, i, c->end); 128 | } 129 | 130 | static void AddSorted(size_t value, size_t** out, size_t* outsize) { 131 | size_t i; 132 | ZOPFLI_APPEND_DATA(value, out, outsize); 133 | for (i = 0; i + 1 < *outsize; i++) { 134 | if ((*out)[i] > value) { 135 | size_t j; 136 | for (j = *outsize - 1; j > i; j--) { 137 | (*out)[j] = (*out)[j - 1]; 138 | } 139 | (*out)[i] = value; 140 | break; 141 | } 142 | } 143 | } 144 | 145 | /* 146 | Prints the block split points as decimal and hex values in the terminal. 147 | */ 148 | static void PrintBlockSplitPoints(const ZopfliLZ77Store* lz77, 149 | const size_t* lz77splitpoints, 150 | size_t nlz77points) { 151 | size_t* splitpoints = 0; 152 | size_t npoints = 0; 153 | size_t i; 154 | /* The input is given as lz77 indices, but we want to see the uncompressed 155 | index values. */ 156 | size_t pos = 0; 157 | if (nlz77points > 0) { 158 | for (i = 0; i < lz77->size; i++) { 159 | size_t length = lz77->dists[i] == 0 ? 1 : lz77->litlens[i]; 160 | if (lz77splitpoints[npoints] == i) { 161 | ZOPFLI_APPEND_DATA(pos, &splitpoints, &npoints); 162 | if (npoints == nlz77points) break; 163 | } 164 | pos += length; 165 | } 166 | } 167 | assert(npoints == nlz77points); 168 | 169 | fprintf(stderr, "block split points: "); 170 | for (i = 0; i < npoints; i++) { 171 | fprintf(stderr, "%d ", (int)splitpoints[i]); 172 | } 173 | fprintf(stderr, "(hex:"); 174 | for (i = 0; i < npoints; i++) { 175 | fprintf(stderr, " %x", (int)splitpoints[i]); 176 | } 177 | fprintf(stderr, ")\n"); 178 | 179 | free(splitpoints); 180 | } 181 | 182 | /* 183 | Finds next block to try to split, the largest of the available ones. 184 | The largest is chosen to make sure that if only a limited amount of blocks is 185 | requested, their sizes are spread evenly. 186 | lz77size: the size of the LL77 data, which is the size of the done array here. 187 | done: array indicating which blocks starting at that position are no longer 188 | splittable (splitting them increases rather than decreases cost). 189 | splitpoints: the splitpoints found so far. 190 | npoints: the amount of splitpoints found so far. 191 | lstart: output variable, giving start of block. 192 | lend: output variable, giving end of block. 193 | returns 1 if a block was found, 0 if no block found (all are done). 194 | */ 195 | static int FindLargestSplittableBlock( 196 | size_t lz77size, const unsigned char* done, 197 | const size_t* splitpoints, size_t npoints, 198 | size_t* lstart, size_t* lend) { 199 | size_t longest = 0; 200 | int found = 0; 201 | size_t i; 202 | for (i = 0; i <= npoints; i++) { 203 | size_t start = i == 0 ? 0 : splitpoints[i - 1]; 204 | size_t end = i == npoints ? lz77size - 1 : splitpoints[i]; 205 | if (!done[start] && end - start > longest) { 206 | *lstart = start; 207 | *lend = end; 208 | found = 1; 209 | longest = end - start; 210 | } 211 | } 212 | return found; 213 | } 214 | 215 | void ZopfliBlockSplitLZ77(const ZopfliOptions* options, 216 | const ZopfliLZ77Store* lz77, size_t maxblocks, 217 | size_t** splitpoints, size_t* npoints) { 218 | size_t lstart, lend; 219 | size_t i; 220 | size_t llpos = 0; 221 | size_t numblocks = 1; 222 | unsigned char* done; 223 | double splitcost, origcost; 224 | 225 | if (lz77->size < 10) return; /* This code fails on tiny files. */ 226 | 227 | done = (unsigned char*)malloc(lz77->size); 228 | if (!done) exit(-1); /* Allocation failed. */ 229 | for (i = 0; i < lz77->size; i++) done[i] = 0; 230 | 231 | lstart = 0; 232 | lend = lz77->size; 233 | for (;;) { 234 | SplitCostContext c; 235 | 236 | if (maxblocks > 0 && numblocks >= maxblocks) { 237 | break; 238 | } 239 | 240 | c.lz77 = lz77; 241 | c.start = lstart; 242 | c.end = lend; 243 | assert(lstart < lend); 244 | llpos = FindMinimum(SplitCost, &c, lstart + 1, lend, &splitcost); 245 | 246 | assert(llpos > lstart); 247 | assert(llpos < lend); 248 | 249 | origcost = EstimateCost(lz77, lstart, lend); 250 | 251 | if (splitcost > origcost || llpos == lstart + 1 || llpos == lend) { 252 | done[lstart] = 1; 253 | } else { 254 | AddSorted(llpos, splitpoints, npoints); 255 | numblocks++; 256 | } 257 | 258 | if (!FindLargestSplittableBlock( 259 | lz77->size, done, *splitpoints, *npoints, &lstart, &lend)) { 260 | break; /* No further split will probably reduce compression. */ 261 | } 262 | 263 | if (lend - lstart < 10) { 264 | break; 265 | } 266 | } 267 | 268 | if (options->verbose) { 269 | PrintBlockSplitPoints(lz77, *splitpoints, *npoints); 270 | } 271 | 272 | free(done); 273 | } 274 | 275 | void ZopfliBlockSplit(const ZopfliOptions* options, 276 | const unsigned char* in, size_t instart, size_t inend, 277 | size_t maxblocks, size_t** splitpoints, size_t* npoints) { 278 | size_t pos = 0; 279 | size_t i; 280 | ZopfliBlockState s; 281 | size_t* lz77splitpoints = 0; 282 | size_t nlz77points = 0; 283 | ZopfliLZ77Store store; 284 | ZopfliHash hash; 285 | ZopfliHash* h = &hash; 286 | 287 | ZopfliInitLZ77Store(in, &store); 288 | ZopfliInitBlockState(options, instart, inend, 0, &s); 289 | ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h); 290 | 291 | *npoints = 0; 292 | *splitpoints = 0; 293 | 294 | /* Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal 295 | results in better blocks. */ 296 | ZopfliLZ77Greedy(&s, in, instart, inend, &store, h); 297 | 298 | ZopfliBlockSplitLZ77(options, 299 | &store, maxblocks, 300 | &lz77splitpoints, &nlz77points); 301 | 302 | /* Convert LZ77 positions to positions in the uncompressed input. */ 303 | pos = instart; 304 | if (nlz77points > 0) { 305 | for (i = 0; i < store.size; i++) { 306 | size_t length = store.dists[i] == 0 ? 1 : store.litlens[i]; 307 | if (lz77splitpoints[*npoints] == i) { 308 | ZOPFLI_APPEND_DATA(pos, splitpoints, npoints); 309 | if (*npoints == nlz77points) break; 310 | } 311 | pos += length; 312 | } 313 | } 314 | assert(*npoints == nlz77points); 315 | 316 | free(lz77splitpoints); 317 | ZopfliCleanBlockState(&s); 318 | ZopfliCleanLZ77Store(&store); 319 | ZopfliCleanHash(h); 320 | } 321 | 322 | void ZopfliBlockSplitSimple(const unsigned char* in, 323 | size_t instart, size_t inend, 324 | size_t blocksize, 325 | size_t** splitpoints, size_t* npoints) { 326 | size_t i = instart; 327 | while (i < inend) { 328 | ZOPFLI_APPEND_DATA(i, splitpoints, npoints); 329 | i += blocksize; 330 | } 331 | (void)in; 332 | } 333 | -------------------------------------------------------------------------------- /src/zopfli/blocksplitter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Functions to choose good boundaries for block splitting. Deflate allows encoding 22 | the data in multiple blocks, with a separate Huffman tree for each block. The 23 | Huffman tree itself requires some bytes to encode, so by choosing certain 24 | blocks, you can either hurt, or enhance compression. These functions choose good 25 | ones that enhance it. 26 | */ 27 | 28 | #ifndef ZOPFLI_BLOCKSPLITTER_H_ 29 | #define ZOPFLI_BLOCKSPLITTER_H_ 30 | 31 | #include 32 | 33 | #include "lz77.h" 34 | #include "zopfli.h" 35 | 36 | 37 | /* 38 | Does blocksplitting on LZ77 data. 39 | The output splitpoints are indices in the LZ77 data. 40 | maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit. 41 | */ 42 | void ZopfliBlockSplitLZ77(const ZopfliOptions* options, 43 | const ZopfliLZ77Store* lz77, size_t maxblocks, 44 | size_t** splitpoints, size_t* npoints); 45 | 46 | /* 47 | Does blocksplitting on uncompressed data. 48 | The output splitpoints are indices in the uncompressed bytes. 49 | 50 | options: general program options. 51 | in: uncompressed input data 52 | instart: where to start splitting 53 | inend: where to end splitting (not inclusive) 54 | maxblocks: maximum amount of blocks to split into, or 0 for no limit 55 | splitpoints: dynamic array to put the resulting split point coordinates into. 56 | The coordinates are indices in the input array. 57 | npoints: pointer to amount of splitpoints, for the dynamic array. The amount of 58 | blocks is the amount of splitpoitns + 1. 59 | */ 60 | void ZopfliBlockSplit(const ZopfliOptions* options, 61 | const unsigned char* in, size_t instart, size_t inend, 62 | size_t maxblocks, size_t** splitpoints, size_t* npoints); 63 | 64 | /* 65 | Divides the input into equal blocks, does not even take LZ77 lengths into 66 | account. 67 | */ 68 | void ZopfliBlockSplitSimple(const unsigned char* in, 69 | size_t instart, size_t inend, 70 | size_t blocksize, 71 | size_t** splitpoints, size_t* npoints); 72 | 73 | #endif /* ZOPFLI_BLOCKSPLITTER_H_ */ 74 | -------------------------------------------------------------------------------- /src/zopfli/cache.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "cache.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef ZOPFLI_LONGEST_MATCH_CACHE 27 | 28 | void ZopfliInitCache(size_t blocksize, ZopfliLongestMatchCache* lmc) { 29 | size_t i; 30 | lmc->length = (unsigned short*)malloc(sizeof(unsigned short) * blocksize); 31 | lmc->dist = (unsigned short*)malloc(sizeof(unsigned short) * blocksize); 32 | /* Rather large amount of memory. */ 33 | lmc->sublen = (unsigned char*)malloc(ZOPFLI_CACHE_LENGTH * 3 * blocksize); 34 | if(lmc->sublen == NULL) { 35 | fprintf(stderr, 36 | "Error: Out of memory. Tried allocating %lu bytes of memory.\n", 37 | (unsigned long)ZOPFLI_CACHE_LENGTH * 3 * blocksize); 38 | exit (EXIT_FAILURE); 39 | } 40 | 41 | /* length > 0 and dist 0 is invalid combination, which indicates on purpose 42 | that this cache value is not filled in yet. */ 43 | for (i = 0; i < blocksize; i++) lmc->length[i] = 1; 44 | for (i = 0; i < blocksize; i++) lmc->dist[i] = 0; 45 | for (i = 0; i < ZOPFLI_CACHE_LENGTH * blocksize * 3; i++) lmc->sublen[i] = 0; 46 | } 47 | 48 | void ZopfliCleanCache(ZopfliLongestMatchCache* lmc) { 49 | free(lmc->length); 50 | free(lmc->dist); 51 | free(lmc->sublen); 52 | } 53 | 54 | void ZopfliSublenToCache(const unsigned short* sublen, 55 | size_t pos, size_t length, 56 | ZopfliLongestMatchCache* lmc) { 57 | size_t i; 58 | size_t j = 0; 59 | unsigned bestlength = 0; 60 | unsigned char* cache; 61 | 62 | #if ZOPFLI_CACHE_LENGTH == 0 63 | return; 64 | #endif 65 | 66 | cache = &lmc->sublen[ZOPFLI_CACHE_LENGTH * pos * 3]; 67 | if (length < 3) return; 68 | for (i = 3; i <= length; i++) { 69 | if (i == length || sublen[i] != sublen[i + 1]) { 70 | cache[j * 3] = i - 3; 71 | cache[j * 3 + 1] = sublen[i] % 256; 72 | cache[j * 3 + 2] = (sublen[i] >> 8) % 256; 73 | bestlength = i; 74 | j++; 75 | if (j >= ZOPFLI_CACHE_LENGTH) break; 76 | } 77 | } 78 | if (j < ZOPFLI_CACHE_LENGTH) { 79 | assert(bestlength == length); 80 | cache[(ZOPFLI_CACHE_LENGTH - 1) * 3] = bestlength - 3; 81 | } else { 82 | assert(bestlength <= length); 83 | } 84 | assert(bestlength == ZopfliMaxCachedSublen(lmc, pos, length)); 85 | } 86 | 87 | void ZopfliCacheToSublen(const ZopfliLongestMatchCache* lmc, 88 | size_t pos, size_t length, 89 | unsigned short* sublen) { 90 | size_t i, j; 91 | unsigned maxlength = ZopfliMaxCachedSublen(lmc, pos, length); 92 | unsigned prevlength = 0; 93 | unsigned char* cache; 94 | #if ZOPFLI_CACHE_LENGTH == 0 95 | return; 96 | #endif 97 | if (length < 3) return; 98 | cache = &lmc->sublen[ZOPFLI_CACHE_LENGTH * pos * 3]; 99 | for (j = 0; j < ZOPFLI_CACHE_LENGTH; j++) { 100 | unsigned length = cache[j * 3] + 3; 101 | unsigned dist = cache[j * 3 + 1] + 256 * cache[j * 3 + 2]; 102 | for (i = prevlength; i <= length; i++) { 103 | sublen[i] = dist; 104 | } 105 | if (length == maxlength) break; 106 | prevlength = length + 1; 107 | } 108 | } 109 | 110 | /* 111 | Returns the length up to which could be stored in the cache. 112 | */ 113 | unsigned ZopfliMaxCachedSublen(const ZopfliLongestMatchCache* lmc, 114 | size_t pos, size_t length) { 115 | unsigned char* cache; 116 | #if ZOPFLI_CACHE_LENGTH == 0 117 | return 0; 118 | #endif 119 | cache = &lmc->sublen[ZOPFLI_CACHE_LENGTH * pos * 3]; 120 | (void)length; 121 | if (cache[1] == 0 && cache[2] == 0) return 0; /* No sublen cached. */ 122 | return cache[(ZOPFLI_CACHE_LENGTH - 1) * 3] + 3; 123 | } 124 | 125 | #endif /* ZOPFLI_LONGEST_MATCH_CACHE */ 126 | -------------------------------------------------------------------------------- /src/zopfli/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | The cache that speeds up ZopfliFindLongestMatch of lz77.c. 22 | */ 23 | 24 | #ifndef ZOPFLI_CACHE_H_ 25 | #define ZOPFLI_CACHE_H_ 26 | 27 | #include "util.h" 28 | 29 | #ifdef ZOPFLI_LONGEST_MATCH_CACHE 30 | 31 | /* 32 | Cache used by ZopfliFindLongestMatch to remember previously found length/dist 33 | values. 34 | This is needed because the squeeze runs will ask these values multiple times for 35 | the same position. 36 | Uses large amounts of memory, since it has to remember the distance belonging 37 | to every possible shorter-than-the-best length (the so called "sublen" array). 38 | */ 39 | typedef struct ZopfliLongestMatchCache { 40 | unsigned short* length; 41 | unsigned short* dist; 42 | unsigned char* sublen; 43 | } ZopfliLongestMatchCache; 44 | 45 | /* Initializes the ZopfliLongestMatchCache. */ 46 | void ZopfliInitCache(size_t blocksize, ZopfliLongestMatchCache* lmc); 47 | 48 | /* Frees up the memory of the ZopfliLongestMatchCache. */ 49 | void ZopfliCleanCache(ZopfliLongestMatchCache* lmc); 50 | 51 | /* Stores sublen array in the cache. */ 52 | void ZopfliSublenToCache(const unsigned short* sublen, 53 | size_t pos, size_t length, 54 | ZopfliLongestMatchCache* lmc); 55 | 56 | /* Extracts sublen array from the cache. */ 57 | void ZopfliCacheToSublen(const ZopfliLongestMatchCache* lmc, 58 | size_t pos, size_t length, 59 | unsigned short* sublen); 60 | /* Returns the length up to which could be stored in the cache. */ 61 | unsigned ZopfliMaxCachedSublen(const ZopfliLongestMatchCache* lmc, 62 | size_t pos, size_t length); 63 | 64 | #endif /* ZOPFLI_LONGEST_MATCH_CACHE */ 65 | 66 | #endif /* ZOPFLI_CACHE_H_ */ 67 | -------------------------------------------------------------------------------- /src/zopfli/deflate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #ifndef ZOPFLI_DEFLATE_H_ 21 | #define ZOPFLI_DEFLATE_H_ 22 | 23 | /* 24 | Functions to compress according to the DEFLATE specification, using the 25 | "squeeze" LZ77 compression backend. 26 | */ 27 | 28 | #include "lz77.h" 29 | #include "zopfli.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /* 36 | Compresses according to the deflate specification and append the compressed 37 | result to the output. 38 | This function will usually output multiple deflate blocks. If final is 1, then 39 | the final bit will be set on the last block. 40 | 41 | options: global program options 42 | btype: the deflate block type. Use 2 for best compression. 43 | -0: non compressed blocks (00) 44 | -1: blocks with fixed tree (01) 45 | -2: blocks with dynamic tree (10) 46 | final: whether this is the last section of the input, sets the final bit to the 47 | last deflate block. 48 | in: the input bytes 49 | insize: number of input bytes 50 | bp: bit pointer for the output array. This must initially be 0, and for 51 | consecutive calls must be reused (it can have values from 0-7). This is 52 | because deflate appends blocks as bit-based data, rather than on byte 53 | boundaries. 54 | out: pointer to the dynamic output array to which the result is appended. Must 55 | be freed after use. 56 | outsize: pointer to the dynamic output array size. 57 | */ 58 | void ZopfliDeflate(const ZopfliOptions* options, int btype, int final, 59 | const unsigned char* in, size_t insize, 60 | unsigned char* bp, unsigned char** out, size_t* outsize); 61 | 62 | /* 63 | Like ZopfliDeflate, but allows to specify start and end byte with instart and 64 | inend. Only that part is compressed, but earlier bytes are still used for the 65 | back window. 66 | */ 67 | void ZopfliDeflatePart(const ZopfliOptions* options, int btype, int final, 68 | const unsigned char* in, size_t instart, size_t inend, 69 | unsigned char* bp, unsigned char** out, 70 | size_t* outsize); 71 | 72 | /* 73 | Calculates block size in bits. 74 | litlens: lz77 lit/lengths 75 | dists: ll77 distances 76 | lstart: start of block 77 | lend: end of block (not inclusive) 78 | */ 79 | double ZopfliCalculateBlockSize(const ZopfliLZ77Store* lz77, 80 | size_t lstart, size_t lend, int btype); 81 | 82 | /* 83 | Calculates block size in bits, automatically using the best btype. 84 | */ 85 | double ZopfliCalculateBlockSizeAutoType(const ZopfliLZ77Store* lz77, 86 | size_t lstart, size_t lend); 87 | 88 | #ifdef __cplusplus 89 | } // extern "C" 90 | #endif 91 | 92 | #endif /* ZOPFLI_DEFLATE_H_ */ 93 | -------------------------------------------------------------------------------- /src/zopfli/gzip_container.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "gzip_container.h" 21 | #include "util.h" 22 | 23 | #include 24 | 25 | #include "deflate.h" 26 | 27 | /* CRC polynomial: 0xedb88320 */ 28 | static const unsigned long crc32_table[256] = { 29 | 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 30 | 3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u, 31 | 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 32 | 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, 33 | 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 34 | 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 35 | 1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u, 36 | 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 37 | 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 38 | 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, 39 | 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 40 | 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, 41 | 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 42 | 2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u, 43 | 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, 44 | 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 45 | 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 46 | 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 47 | 1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u, 48 | 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, 49 | 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 50 | 3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u, 51 | 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 52 | 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, 53 | 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 54 | 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 55 | 4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u, 56 | 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 57 | 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 58 | 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, 59 | 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 60 | 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, 61 | 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 62 | 1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u, 63 | 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, 64 | 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 65 | 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 66 | 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 67 | 2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u, 68 | 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, 69 | 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 70 | 1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u, 71 | 3020668471u, 3272380065u, 1510334235u, 755167117u 72 | }; 73 | 74 | /* Returns the CRC32 */ 75 | static unsigned long CRC(const unsigned char* data, size_t size) { 76 | unsigned long result = 0xffffffffu; 77 | for (; size > 0; size--) { 78 | result = crc32_table[(result ^ *(data++)) & 0xff] ^ (result >> 8); 79 | } 80 | return result ^ 0xffffffffu; 81 | } 82 | 83 | /* Compresses the data according to the gzip specification, RFC 1952. */ 84 | void ZopfliGzipCompress(const ZopfliOptions* options, 85 | const unsigned char* in, size_t insize, 86 | unsigned char** out, size_t* outsize) { 87 | unsigned long crcvalue = CRC(in, insize); 88 | unsigned char bp = 0; 89 | 90 | ZOPFLI_APPEND_DATA(31, out, outsize); /* ID1 */ 91 | ZOPFLI_APPEND_DATA(139, out, outsize); /* ID2 */ 92 | ZOPFLI_APPEND_DATA(8, out, outsize); /* CM */ 93 | ZOPFLI_APPEND_DATA(0, out, outsize); /* FLG */ 94 | /* MTIME */ 95 | ZOPFLI_APPEND_DATA(0, out, outsize); 96 | ZOPFLI_APPEND_DATA(0, out, outsize); 97 | ZOPFLI_APPEND_DATA(0, out, outsize); 98 | ZOPFLI_APPEND_DATA(0, out, outsize); 99 | 100 | ZOPFLI_APPEND_DATA(2, out, outsize); /* XFL, 2 indicates best compression. */ 101 | ZOPFLI_APPEND_DATA(3, out, outsize); /* OS follows Unix conventions. */ 102 | 103 | ZopfliDeflate(options, 2 /* Dynamic block */, 1, 104 | in, insize, &bp, out, outsize); 105 | 106 | /* CRC */ 107 | ZOPFLI_APPEND_DATA(crcvalue % 256, out, outsize); 108 | ZOPFLI_APPEND_DATA((crcvalue >> 8) % 256, out, outsize); 109 | ZOPFLI_APPEND_DATA((crcvalue >> 16) % 256, out, outsize); 110 | ZOPFLI_APPEND_DATA((crcvalue >> 24) % 256, out, outsize); 111 | 112 | /* ISIZE */ 113 | ZOPFLI_APPEND_DATA(insize % 256, out, outsize); 114 | ZOPFLI_APPEND_DATA((insize >> 8) % 256, out, outsize); 115 | ZOPFLI_APPEND_DATA((insize >> 16) % 256, out, outsize); 116 | ZOPFLI_APPEND_DATA((insize >> 24) % 256, out, outsize); 117 | 118 | if (options->verbose) { 119 | fprintf(stderr, 120 | "Original Size: %d, Gzip: %d, Compression: %f%% Removed\n", 121 | (int)insize, (int)*outsize, 122 | 100.0 * (double)(insize - *outsize) / (double)insize); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/zopfli/gzip_container.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #ifndef ZOPFLI_GZIP_H_ 21 | #define ZOPFLI_GZIP_H_ 22 | 23 | /* 24 | Functions to compress according to the Gzip specification. 25 | */ 26 | 27 | #include "zopfli.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* 34 | Compresses according to the gzip specification and append the compressed 35 | result to the output. 36 | 37 | options: global program options 38 | out: pointer to the dynamic output array to which the result is appended. Must 39 | be freed after use. 40 | outsize: pointer to the dynamic output array size. 41 | */ 42 | void ZopfliGzipCompress(const ZopfliOptions* options, 43 | const unsigned char* in, size_t insize, 44 | unsigned char** out, size_t* outsize); 45 | 46 | #ifdef __cplusplus 47 | } // extern "C" 48 | #endif 49 | 50 | #endif /* ZOPFLI_GZIP_H_ */ 51 | -------------------------------------------------------------------------------- /src/zopfli/hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "hash.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #define HASH_SHIFT 5 27 | #define HASH_MASK 32767 28 | 29 | void ZopfliAllocHash(size_t window_size, ZopfliHash* h) { 30 | h->head = (int*)malloc(sizeof(*h->head) * 65536); 31 | h->prev = (unsigned short*)malloc(sizeof(*h->prev) * window_size); 32 | h->hashval = (int*)malloc(sizeof(*h->hashval) * window_size); 33 | 34 | #ifdef ZOPFLI_HASH_SAME 35 | h->same = (unsigned short*)malloc(sizeof(*h->same) * window_size); 36 | #endif 37 | 38 | #ifdef ZOPFLI_HASH_SAME_HASH 39 | h->head2 = (int*)malloc(sizeof(*h->head2) * 65536); 40 | h->prev2 = (unsigned short*)malloc(sizeof(*h->prev2) * window_size); 41 | h->hashval2 = (int*)malloc(sizeof(*h->hashval2) * window_size); 42 | #endif 43 | } 44 | 45 | void ZopfliResetHash(size_t window_size, ZopfliHash* h) { 46 | size_t i; 47 | 48 | h->val = 0; 49 | for (i = 0; i < 65536; i++) { 50 | h->head[i] = -1; /* -1 indicates no head so far. */ 51 | } 52 | for (i = 0; i < window_size; i++) { 53 | h->prev[i] = i; /* If prev[j] == j, then prev[j] is uninitialized. */ 54 | h->hashval[i] = -1; 55 | } 56 | 57 | #ifdef ZOPFLI_HASH_SAME 58 | for (i = 0; i < window_size; i++) { 59 | h->same[i] = 0; 60 | } 61 | #endif 62 | 63 | #ifdef ZOPFLI_HASH_SAME_HASH 64 | h->val2 = 0; 65 | for (i = 0; i < 65536; i++) { 66 | h->head2[i] = -1; 67 | } 68 | for (i = 0; i < window_size; i++) { 69 | h->prev2[i] = i; 70 | h->hashval2[i] = -1; 71 | } 72 | #endif 73 | } 74 | 75 | void ZopfliCleanHash(ZopfliHash* h) { 76 | free(h->head); 77 | free(h->prev); 78 | free(h->hashval); 79 | 80 | #ifdef ZOPFLI_HASH_SAME_HASH 81 | free(h->head2); 82 | free(h->prev2); 83 | free(h->hashval2); 84 | #endif 85 | 86 | #ifdef ZOPFLI_HASH_SAME 87 | free(h->same); 88 | #endif 89 | } 90 | 91 | /* 92 | Update the sliding hash value with the given byte. All calls to this function 93 | must be made on consecutive input characters. Since the hash value exists out 94 | of multiple input bytes, a few warmups with this function are needed initially. 95 | */ 96 | static void UpdateHashValue(ZopfliHash* h, unsigned char c) { 97 | h->val = (((h->val) << HASH_SHIFT) ^ (c)) & HASH_MASK; 98 | } 99 | 100 | void ZopfliUpdateHash(const unsigned char* array, size_t pos, size_t end, 101 | ZopfliHash* h) { 102 | unsigned short hpos = pos & ZOPFLI_WINDOW_MASK; 103 | #ifdef ZOPFLI_HASH_SAME 104 | size_t amount = 0; 105 | #endif 106 | 107 | UpdateHashValue(h, pos + ZOPFLI_MIN_MATCH <= end ? 108 | array[pos + ZOPFLI_MIN_MATCH - 1] : 0); 109 | h->hashval[hpos] = h->val; 110 | if (h->head[h->val] != -1 && h->hashval[h->head[h->val]] == h->val) { 111 | h->prev[hpos] = h->head[h->val]; 112 | } 113 | else h->prev[hpos] = hpos; 114 | h->head[h->val] = hpos; 115 | 116 | #ifdef ZOPFLI_HASH_SAME 117 | /* Update "same". */ 118 | if (h->same[(pos - 1) & ZOPFLI_WINDOW_MASK] > 1) { 119 | amount = h->same[(pos - 1) & ZOPFLI_WINDOW_MASK] - 1; 120 | } 121 | while (pos + amount + 1 < end && 122 | array[pos] == array[pos + amount + 1] && amount < (unsigned short)(-1)) { 123 | amount++; 124 | } 125 | h->same[hpos] = amount; 126 | #endif 127 | 128 | #ifdef ZOPFLI_HASH_SAME_HASH 129 | h->val2 = ((h->same[hpos] - ZOPFLI_MIN_MATCH) & 255) ^ h->val; 130 | h->hashval2[hpos] = h->val2; 131 | if (h->head2[h->val2] != -1 && h->hashval2[h->head2[h->val2]] == h->val2) { 132 | h->prev2[hpos] = h->head2[h->val2]; 133 | } 134 | else h->prev2[hpos] = hpos; 135 | h->head2[h->val2] = hpos; 136 | #endif 137 | } 138 | 139 | void ZopfliWarmupHash(const unsigned char* array, size_t pos, size_t end, 140 | ZopfliHash* h) { 141 | UpdateHashValue(h, array[pos + 0]); 142 | if (pos + 1 < end) UpdateHashValue(h, array[pos + 1]); 143 | } 144 | -------------------------------------------------------------------------------- /src/zopfli/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | The hash for ZopfliFindLongestMatch of lz77.c. 22 | */ 23 | 24 | #ifndef ZOPFLI_HASH_H_ 25 | #define ZOPFLI_HASH_H_ 26 | 27 | #include "util.h" 28 | 29 | typedef struct ZopfliHash { 30 | int* head; /* Hash value to index of its most recent occurrence. */ 31 | unsigned short* prev; /* Index to index of prev. occurrence of same hash. */ 32 | int* hashval; /* Index to hash value at this index. */ 33 | int val; /* Current hash value. */ 34 | 35 | #ifdef ZOPFLI_HASH_SAME_HASH 36 | /* Fields with similar purpose as the above hash, but for the second hash with 37 | a value that is calculated differently. */ 38 | int* head2; /* Hash value to index of its most recent occurrence. */ 39 | unsigned short* prev2; /* Index to index of prev. occurrence of same hash. */ 40 | int* hashval2; /* Index to hash value at this index. */ 41 | int val2; /* Current hash value. */ 42 | #endif 43 | 44 | #ifdef ZOPFLI_HASH_SAME 45 | unsigned short* same; /* Amount of repetitions of same byte after this .*/ 46 | #endif 47 | } ZopfliHash; 48 | 49 | /* Allocates ZopfliHash memory. */ 50 | void ZopfliAllocHash(size_t window_size, ZopfliHash* h); 51 | 52 | /* Resets all fields of ZopfliHash. */ 53 | void ZopfliResetHash(size_t window_size, ZopfliHash* h); 54 | 55 | /* Frees ZopfliHash memory. */ 56 | void ZopfliCleanHash(ZopfliHash* h); 57 | 58 | /* 59 | Updates the hash values based on the current position in the array. All calls 60 | to this must be made for consecutive bytes. 61 | */ 62 | void ZopfliUpdateHash(const unsigned char* array, size_t pos, size_t end, 63 | ZopfliHash* h); 64 | 65 | /* 66 | Prepopulates hash: 67 | Fills in the initial values in the hash, before ZopfliUpdateHash can be used 68 | correctly. 69 | */ 70 | void ZopfliWarmupHash(const unsigned char* array, size_t pos, size_t end, 71 | ZopfliHash* h); 72 | 73 | #endif /* ZOPFLI_HASH_H_ */ 74 | -------------------------------------------------------------------------------- /src/zopfli/katajainen.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Bounded package merge algorithm, based on the paper 22 | "A Fast and Space-Economical Algorithm for Length-Limited Coding 23 | Jyrki Katajainen, Alistair Moffat, Andrew Turpin". 24 | */ 25 | 26 | #include "katajainen.h" 27 | #include 28 | #include 29 | #include 30 | 31 | typedef struct Node Node; 32 | 33 | /* 34 | Nodes forming chains. Also used to represent leaves. 35 | */ 36 | struct Node { 37 | size_t weight; /* Total weight (symbol count) of this chain. */ 38 | Node* tail; /* Previous node(s) of this chain, or 0 if none. */ 39 | int count; /* Leaf symbol index, or number of leaves before this chain. */ 40 | }; 41 | 42 | /* 43 | Memory pool for nodes. 44 | */ 45 | typedef struct NodePool { 46 | Node* next; /* Pointer to a free node in the pool. */ 47 | } NodePool; 48 | 49 | /* 50 | Initializes a chain node with the given values and marks it as in use. 51 | */ 52 | static void InitNode(size_t weight, int count, Node* tail, Node* node) { 53 | node->weight = weight; 54 | node->count = count; 55 | node->tail = tail; 56 | } 57 | 58 | /* 59 | Performs a Boundary Package-Merge step. Puts a new chain in the given list. The 60 | new chain is, depending on the weights, a leaf or a combination of two chains 61 | from the previous list. 62 | lists: The lists of chains. 63 | maxbits: Number of lists. 64 | leaves: The leaves, one per symbol. 65 | numsymbols: Number of leaves. 66 | pool: the node memory pool. 67 | index: The index of the list in which a new chain or leaf is required. 68 | */ 69 | static void BoundaryPM(Node* (*lists)[2], Node* leaves, int numsymbols, 70 | NodePool* pool, int index) { 71 | Node* newchain; 72 | Node* oldchain; 73 | int lastcount = lists[index][1]->count; /* Count of last chain of list. */ 74 | 75 | if (index == 0 && lastcount >= numsymbols) return; 76 | 77 | newchain = pool->next++; 78 | oldchain = lists[index][1]; 79 | 80 | /* These are set up before the recursive calls below, so that there is a list 81 | pointing to the new node, to let the garbage collection know it's in use. */ 82 | lists[index][0] = oldchain; 83 | lists[index][1] = newchain; 84 | 85 | if (index == 0) { 86 | /* New leaf node in list 0. */ 87 | InitNode(leaves[lastcount].weight, lastcount + 1, 0, newchain); 88 | } else { 89 | size_t sum = lists[index - 1][0]->weight + lists[index - 1][1]->weight; 90 | if (lastcount < numsymbols && sum > leaves[lastcount].weight) { 91 | /* New leaf inserted in list, so count is incremented. */ 92 | InitNode(leaves[lastcount].weight, lastcount + 1, oldchain->tail, 93 | newchain); 94 | } else { 95 | InitNode(sum, lastcount, lists[index - 1][1], newchain); 96 | /* Two lookahead chains of previous list used up, create new ones. */ 97 | BoundaryPM(lists, leaves, numsymbols, pool, index - 1); 98 | BoundaryPM(lists, leaves, numsymbols, pool, index - 1); 99 | } 100 | } 101 | } 102 | 103 | static void BoundaryPMFinal(Node* (*lists)[2], 104 | Node* leaves, int numsymbols, NodePool* pool, int index) { 105 | int lastcount = lists[index][1]->count; /* Count of last chain of list. */ 106 | 107 | size_t sum = lists[index - 1][0]->weight + lists[index - 1][1]->weight; 108 | 109 | if (lastcount < numsymbols && sum > leaves[lastcount].weight) { 110 | Node* newchain = pool->next; 111 | Node* oldchain = lists[index][1]->tail; 112 | 113 | lists[index][1] = newchain; 114 | newchain->count = lastcount + 1; 115 | newchain->tail = oldchain; 116 | } else { 117 | lists[index][1]->tail = lists[index - 1][1]; 118 | } 119 | } 120 | 121 | /* 122 | Initializes each list with as lookahead chains the two leaves with lowest 123 | weights. 124 | */ 125 | static void InitLists( 126 | NodePool* pool, const Node* leaves, int maxbits, Node* (*lists)[2]) { 127 | int i; 128 | Node* node0 = pool->next++; 129 | Node* node1 = pool->next++; 130 | InitNode(leaves[0].weight, 1, 0, node0); 131 | InitNode(leaves[1].weight, 2, 0, node1); 132 | for (i = 0; i < maxbits; i++) { 133 | lists[i][0] = node0; 134 | lists[i][1] = node1; 135 | } 136 | } 137 | 138 | /* 139 | Converts result of boundary package-merge to the bitlengths. The result in the 140 | last chain of the last list contains the amount of active leaves in each list. 141 | chain: Chain to extract the bit length from (last chain from last list). 142 | */ 143 | static void ExtractBitLengths(Node* chain, Node* leaves, unsigned* bitlengths) { 144 | int counts[16] = {0}; 145 | unsigned end = 16; 146 | unsigned ptr = 15; 147 | unsigned value = 1; 148 | Node* node; 149 | int val; 150 | 151 | for (node = chain; node; node = node->tail) { 152 | counts[--end] = node->count; 153 | } 154 | 155 | val = counts[15]; 156 | while (ptr >= end) { 157 | for (; val > counts[ptr - 1]; val--) { 158 | bitlengths[leaves[val - 1].count] = value; 159 | } 160 | ptr--; 161 | value++; 162 | } 163 | } 164 | 165 | /* 166 | Comparator for sorting the leaves. Has the function signature for qsort. 167 | */ 168 | static int LeafComparator(const void* a, const void* b) { 169 | return ((const Node*)a)->weight - ((const Node*)b)->weight; 170 | } 171 | 172 | int ZopfliLengthLimitedCodeLengths( 173 | const size_t* frequencies, int n, int maxbits, unsigned* bitlengths) { 174 | NodePool pool; 175 | int i; 176 | int numsymbols = 0; /* Amount of symbols with frequency > 0. */ 177 | int numBoundaryPMRuns; 178 | Node* nodes; 179 | 180 | /* Array of lists of chains. Each list requires only two lookahead chains at 181 | a time, so each list is a array of two Node*'s. */ 182 | Node* (*lists)[2]; 183 | 184 | /* One leaf per symbol. Only numsymbols leaves will be used. */ 185 | Node* leaves = (Node*)malloc(n * sizeof(*leaves)); 186 | 187 | /* Initialize all bitlengths at 0. */ 188 | for (i = 0; i < n; i++) { 189 | bitlengths[i] = 0; 190 | } 191 | 192 | /* Count used symbols and place them in the leaves. */ 193 | for (i = 0; i < n; i++) { 194 | if (frequencies[i]) { 195 | leaves[numsymbols].weight = frequencies[i]; 196 | leaves[numsymbols].count = i; /* Index of symbol this leaf represents. */ 197 | numsymbols++; 198 | } 199 | } 200 | 201 | /* Check special cases and error conditions. */ 202 | if ((1 << maxbits) < numsymbols) { 203 | free(leaves); 204 | return 1; /* Error, too few maxbits to represent symbols. */ 205 | } 206 | if (numsymbols == 0) { 207 | free(leaves); 208 | return 0; /* No symbols at all. OK. */ 209 | } 210 | if (numsymbols == 1) { 211 | bitlengths[leaves[0].count] = 1; 212 | free(leaves); 213 | return 0; /* Only one symbol, give it bitlength 1, not 0. OK. */ 214 | } 215 | if (numsymbols == 2) { 216 | bitlengths[leaves[0].count]++; 217 | bitlengths[leaves[1].count]++; 218 | free(leaves); 219 | return 0; 220 | } 221 | 222 | /* Sort the leaves from lightest to heaviest. Add count into the same 223 | variable for stable sorting. */ 224 | for (i = 0; i < numsymbols; i++) { 225 | if (leaves[i].weight >= 226 | ((size_t)1 << (sizeof(leaves[0].weight) * CHAR_BIT - 9))) { 227 | free(leaves); 228 | return 1; /* Error, we need 9 bits for the count. */ 229 | } 230 | leaves[i].weight = (leaves[i].weight << 9) | leaves[i].count; 231 | } 232 | qsort(leaves, numsymbols, sizeof(Node), LeafComparator); 233 | for (i = 0; i < numsymbols; i++) { 234 | leaves[i].weight >>= 9; 235 | } 236 | 237 | if (numsymbols - 1 < maxbits) { 238 | maxbits = numsymbols - 1; 239 | } 240 | 241 | /* Initialize node memory pool. */ 242 | nodes = (Node*)malloc(maxbits * 2 * numsymbols * sizeof(Node)); 243 | pool.next = nodes; 244 | 245 | lists = (Node* (*)[2])malloc(maxbits * sizeof(*lists)); 246 | InitLists(&pool, leaves, maxbits, lists); 247 | 248 | /* In the last list, 2 * numsymbols - 2 active chains need to be created. Two 249 | are already created in the initialization. Each BoundaryPM run creates one. */ 250 | numBoundaryPMRuns = 2 * numsymbols - 4; 251 | for (i = 0; i < numBoundaryPMRuns - 1; i++) { 252 | BoundaryPM(lists, leaves, numsymbols, &pool, maxbits - 1); 253 | } 254 | BoundaryPMFinal(lists, leaves, numsymbols, &pool, maxbits - 1); 255 | 256 | ExtractBitLengths(lists[maxbits - 1][1], leaves, bitlengths); 257 | 258 | free(lists); 259 | free(leaves); 260 | free(nodes); 261 | return 0; /* OK. */ 262 | } 263 | -------------------------------------------------------------------------------- /src/zopfli/katajainen.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #ifndef ZOPFLI_KATAJAINEN_H_ 21 | #define ZOPFLI_KATAJAINEN_H_ 22 | 23 | #include 24 | 25 | /* 26 | Outputs minimum-redundancy length-limited code bitlengths for symbols with the 27 | given counts. The bitlengths are limited by maxbits. 28 | 29 | The output is tailored for DEFLATE: symbols that never occur, get a bit length 30 | of 0, and if only a single symbol occurs at least once, its bitlength will be 1, 31 | and not 0 as would theoretically be needed for a single symbol. 32 | 33 | frequencies: The amount of occurrences of each symbol. 34 | n: The amount of symbols. 35 | maxbits: Maximum bit length, inclusive. 36 | bitlengths: Output, the bitlengths for the symbol prefix codes. 37 | return: 0 for OK, non-0 for error. 38 | */ 39 | int ZopfliLengthLimitedCodeLengths( 40 | const size_t* frequencies, int n, int maxbits, unsigned* bitlengths); 41 | 42 | #endif /* ZOPFLI_KATAJAINEN_H_ */ 43 | -------------------------------------------------------------------------------- /src/zopfli/lz77.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Functions for basic LZ77 compression and utilities for the "squeeze" LZ77 22 | compression. 23 | */ 24 | 25 | #ifndef ZOPFLI_LZ77_H_ 26 | #define ZOPFLI_LZ77_H_ 27 | 28 | #include 29 | 30 | #include "cache.h" 31 | #include "hash.h" 32 | #include "zopfli.h" 33 | 34 | /* 35 | Stores lit/length and dist pairs for LZ77. 36 | Parameter litlens: Contains the literal symbols or length values. 37 | Parameter dists: Contains the distances. A value is 0 to indicate that there is 38 | no dist and the corresponding litlens value is a literal instead of a length. 39 | Parameter size: The size of both the litlens and dists arrays. 40 | The memory can best be managed by using ZopfliInitLZ77Store to initialize it, 41 | ZopfliCleanLZ77Store to destroy it, and ZopfliStoreLitLenDist to append values. 42 | 43 | */ 44 | typedef struct ZopfliLZ77Store { 45 | unsigned short* litlens; /* Lit or len. */ 46 | unsigned short* dists; /* If 0: indicates literal in corresponding litlens, 47 | if > 0: length in corresponding litlens, this is the distance. */ 48 | size_t size; 49 | 50 | const unsigned char* data; /* original data */ 51 | size_t* pos; /* position in data where this LZ77 command begins */ 52 | 53 | unsigned short* ll_symbol; 54 | unsigned short* d_symbol; 55 | 56 | /* Cumulative histograms wrapping around per chunk. Each chunk has the amount 57 | of distinct symbols as length, so using 1 value per LZ77 symbol, we have a 58 | precise histogram at every N symbols, and the rest can be calculated by 59 | looping through the actual symbols of this chunk. */ 60 | size_t* ll_counts; 61 | size_t* d_counts; 62 | } ZopfliLZ77Store; 63 | 64 | void ZopfliInitLZ77Store(const unsigned char* data, ZopfliLZ77Store* store); 65 | void ZopfliCleanLZ77Store(ZopfliLZ77Store* store); 66 | void ZopfliCopyLZ77Store(const ZopfliLZ77Store* source, ZopfliLZ77Store* dest); 67 | void ZopfliStoreLitLenDist(unsigned short length, unsigned short dist, 68 | size_t pos, ZopfliLZ77Store* store); 69 | void ZopfliAppendLZ77Store(const ZopfliLZ77Store* store, 70 | ZopfliLZ77Store* target); 71 | /* Gets the amount of raw bytes that this range of LZ77 symbols spans. */ 72 | size_t ZopfliLZ77GetByteRange(const ZopfliLZ77Store* lz77, 73 | size_t lstart, size_t lend); 74 | /* Gets the histogram of lit/len and dist symbols in the given range, using the 75 | cumulative histograms, so faster than adding one by one for large range. Does 76 | not add the one end symbol of value 256. */ 77 | void ZopfliLZ77GetHistogram(const ZopfliLZ77Store* lz77, 78 | size_t lstart, size_t lend, 79 | size_t* ll_counts, size_t* d_counts); 80 | 81 | /* 82 | Some state information for compressing a block. 83 | This is currently a bit under-used (with mainly only the longest match cache), 84 | but is kept for easy future expansion. 85 | */ 86 | typedef struct ZopfliBlockState { 87 | const ZopfliOptions* options; 88 | 89 | #ifdef ZOPFLI_LONGEST_MATCH_CACHE 90 | /* Cache for length/distance pairs found so far. */ 91 | ZopfliLongestMatchCache* lmc; 92 | #endif 93 | 94 | /* The start (inclusive) and end (not inclusive) of the current block. */ 95 | size_t blockstart; 96 | size_t blockend; 97 | } ZopfliBlockState; 98 | 99 | void ZopfliInitBlockState(const ZopfliOptions* options, 100 | size_t blockstart, size_t blockend, int add_lmc, 101 | ZopfliBlockState* s); 102 | void ZopfliCleanBlockState(ZopfliBlockState* s); 103 | 104 | /* 105 | Finds the longest match (length and corresponding distance) for LZ77 106 | compression. 107 | Even when not using "sublen", it can be more efficient to provide an array, 108 | because only then the caching is used. 109 | array: the data 110 | pos: position in the data to find the match for 111 | size: size of the data 112 | limit: limit length to maximum this value (default should be 258). This allows 113 | finding a shorter dist for that length (= less extra bits). Must be 114 | in the range [ZOPFLI_MIN_MATCH, ZOPFLI_MAX_MATCH]. 115 | sublen: output array of 259 elements, or null. Has, for each length, the 116 | smallest distance required to reach this length. Only 256 of its 259 values 117 | are used, the first 3 are ignored (the shortest length is 3. It is purely 118 | for convenience that the array is made 3 longer). 119 | */ 120 | void ZopfliFindLongestMatch( 121 | ZopfliBlockState *s, const ZopfliHash* h, const unsigned char* array, 122 | size_t pos, size_t size, size_t limit, 123 | unsigned short* sublen, unsigned short* distance, unsigned short* length); 124 | 125 | /* 126 | Verifies if length and dist are indeed valid, only used for assertion. 127 | */ 128 | void ZopfliVerifyLenDist(const unsigned char* data, size_t datasize, size_t pos, 129 | unsigned short dist, unsigned short length); 130 | 131 | /* 132 | Does LZ77 using an algorithm similar to gzip, with lazy matching, rather than 133 | with the slow but better "squeeze" implementation. 134 | The result is placed in the ZopfliLZ77Store. 135 | If instart is larger than 0, it uses values before instart as starting 136 | dictionary. 137 | */ 138 | void ZopfliLZ77Greedy(ZopfliBlockState* s, const unsigned char* in, 139 | size_t instart, size_t inend, 140 | ZopfliLZ77Store* store, ZopfliHash* h); 141 | 142 | #endif /* ZOPFLI_LZ77_H_ */ 143 | -------------------------------------------------------------------------------- /src/zopfli/squeeze.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "squeeze.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "blocksplitter.h" 27 | #include "deflate.h" 28 | #include "symbols.h" 29 | #include "tree.h" 30 | #include "util.h" 31 | 32 | typedef struct SymbolStats { 33 | /* The literal and length symbols. */ 34 | size_t litlens[ZOPFLI_NUM_LL]; 35 | /* The 32 unique dist symbols, not the 32768 possible dists. */ 36 | size_t dists[ZOPFLI_NUM_D]; 37 | 38 | /* Length of each lit/len symbol in bits. */ 39 | double ll_symbols[ZOPFLI_NUM_LL]; 40 | /* Length of each dist symbol in bits. */ 41 | double d_symbols[ZOPFLI_NUM_D]; 42 | } SymbolStats; 43 | 44 | /* Sets everything to 0. */ 45 | static void InitStats(SymbolStats* stats) { 46 | memset(stats->litlens, 0, ZOPFLI_NUM_LL * sizeof(stats->litlens[0])); 47 | memset(stats->dists, 0, ZOPFLI_NUM_D * sizeof(stats->dists[0])); 48 | 49 | memset(stats->ll_symbols, 0, ZOPFLI_NUM_LL * sizeof(stats->ll_symbols[0])); 50 | memset(stats->d_symbols, 0, ZOPFLI_NUM_D * sizeof(stats->d_symbols[0])); 51 | } 52 | 53 | static void CopyStats(SymbolStats* source, SymbolStats* dest) { 54 | memcpy(dest->litlens, source->litlens, 55 | ZOPFLI_NUM_LL * sizeof(dest->litlens[0])); 56 | memcpy(dest->dists, source->dists, ZOPFLI_NUM_D * sizeof(dest->dists[0])); 57 | 58 | memcpy(dest->ll_symbols, source->ll_symbols, 59 | ZOPFLI_NUM_LL * sizeof(dest->ll_symbols[0])); 60 | memcpy(dest->d_symbols, source->d_symbols, 61 | ZOPFLI_NUM_D * sizeof(dest->d_symbols[0])); 62 | } 63 | 64 | /* Adds the bit lengths. */ 65 | static void AddWeighedStatFreqs(const SymbolStats* stats1, double w1, 66 | const SymbolStats* stats2, double w2, 67 | SymbolStats* result) { 68 | size_t i; 69 | for (i = 0; i < ZOPFLI_NUM_LL; i++) { 70 | result->litlens[i] = 71 | (size_t) (stats1->litlens[i] * w1 + stats2->litlens[i] * w2); 72 | } 73 | for (i = 0; i < ZOPFLI_NUM_D; i++) { 74 | result->dists[i] = 75 | (size_t) (stats1->dists[i] * w1 + stats2->dists[i] * w2); 76 | } 77 | result->litlens[256] = 1; /* End symbol. */ 78 | } 79 | 80 | typedef struct RanState { 81 | unsigned int m_w, m_z; 82 | } RanState; 83 | 84 | static void InitRanState(RanState* state) { 85 | state->m_w = 1; 86 | state->m_z = 2; 87 | } 88 | 89 | /* Get random number: "Multiply-With-Carry" generator of G. Marsaglia */ 90 | static unsigned int Ran(RanState* state) { 91 | state->m_z = 36969 * (state->m_z & 65535) + (state->m_z >> 16); 92 | state->m_w = 18000 * (state->m_w & 65535) + (state->m_w >> 16); 93 | return (state->m_z << 16) + state->m_w; /* 32-bit result. */ 94 | } 95 | 96 | static void RandomizeFreqs(RanState* state, size_t* freqs, int n) { 97 | int i; 98 | for (i = 0; i < n; i++) { 99 | if ((Ran(state) >> 4) % 3 == 0) freqs[i] = freqs[Ran(state) % n]; 100 | } 101 | } 102 | 103 | static void RandomizeStatFreqs(RanState* state, SymbolStats* stats) { 104 | RandomizeFreqs(state, stats->litlens, ZOPFLI_NUM_LL); 105 | RandomizeFreqs(state, stats->dists, ZOPFLI_NUM_D); 106 | stats->litlens[256] = 1; /* End symbol. */ 107 | } 108 | 109 | static void ClearStatFreqs(SymbolStats* stats) { 110 | size_t i; 111 | for (i = 0; i < ZOPFLI_NUM_LL; i++) stats->litlens[i] = 0; 112 | for (i = 0; i < ZOPFLI_NUM_D; i++) stats->dists[i] = 0; 113 | } 114 | 115 | /* 116 | Function that calculates a cost based on a model for the given LZ77 symbol. 117 | litlen: means literal symbol if dist is 0, length otherwise. 118 | */ 119 | typedef double CostModelFun(unsigned litlen, unsigned dist, void* context); 120 | 121 | /* 122 | Cost model which should exactly match fixed tree. 123 | type: CostModelFun 124 | */ 125 | static double GetCostFixed(unsigned litlen, unsigned dist, void* unused) { 126 | (void)unused; 127 | if (dist == 0) { 128 | if (litlen <= 143) return 8; 129 | else return 9; 130 | } else { 131 | int dbits = ZopfliGetDistExtraBits(dist); 132 | int lbits = ZopfliGetLengthExtraBits(litlen); 133 | int lsym = ZopfliGetLengthSymbol(litlen); 134 | int cost = 0; 135 | if (lsym <= 279) cost += 7; 136 | else cost += 8; 137 | cost += 5; /* Every dist symbol has length 5. */ 138 | return cost + dbits + lbits; 139 | } 140 | } 141 | 142 | /* 143 | Cost model based on symbol statistics. 144 | type: CostModelFun 145 | */ 146 | static double GetCostStat(unsigned litlen, unsigned dist, void* context) { 147 | SymbolStats* stats = (SymbolStats*)context; 148 | if (dist == 0) { 149 | return stats->ll_symbols[litlen]; 150 | } else { 151 | int lsym = ZopfliGetLengthSymbol(litlen); 152 | int lbits = ZopfliGetLengthExtraBits(litlen); 153 | int dsym = ZopfliGetDistSymbol(dist); 154 | int dbits = ZopfliGetDistExtraBits(dist); 155 | return lbits + dbits + stats->ll_symbols[lsym] + stats->d_symbols[dsym]; 156 | } 157 | } 158 | 159 | /* 160 | Finds the minimum possible cost this cost model can return for valid length and 161 | distance symbols. 162 | */ 163 | static double GetCostModelMinCost(CostModelFun* costmodel, void* costcontext) { 164 | double mincost; 165 | int bestlength = 0; /* length that has lowest cost in the cost model */ 166 | int bestdist = 0; /* distance that has lowest cost in the cost model */ 167 | int i; 168 | /* 169 | Table of distances that have a different distance symbol in the deflate 170 | specification. Each value is the first distance that has a new symbol. Only 171 | different symbols affect the cost model so only these need to be checked. 172 | See RFC 1951 section 3.2.5. Compressed blocks (length and distance codes). 173 | */ 174 | static const int dsymbols[30] = { 175 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 176 | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 177 | }; 178 | 179 | mincost = ZOPFLI_LARGE_FLOAT; 180 | for (i = 3; i < 259; i++) { 181 | double c = costmodel(i, 1, costcontext); 182 | if (c < mincost) { 183 | bestlength = i; 184 | mincost = c; 185 | } 186 | } 187 | 188 | mincost = ZOPFLI_LARGE_FLOAT; 189 | for (i = 0; i < 30; i++) { 190 | double c = costmodel(3, dsymbols[i], costcontext); 191 | if (c < mincost) { 192 | bestdist = dsymbols[i]; 193 | mincost = c; 194 | } 195 | } 196 | 197 | return costmodel(bestlength, bestdist, costcontext); 198 | } 199 | 200 | static size_t zopfli_min(size_t a, size_t b) { 201 | return a < b ? a : b; 202 | } 203 | 204 | /* 205 | Performs the forward pass for "squeeze". Gets the most optimal length to reach 206 | every byte from a previous byte, using cost calculations. 207 | s: the ZopfliBlockState 208 | in: the input data array 209 | instart: where to start 210 | inend: where to stop (not inclusive) 211 | costmodel: function to calculate the cost of some lit/len/dist pair. 212 | costcontext: abstract context for the costmodel function 213 | length_array: output array of size (inend - instart) which will receive the best 214 | length to reach this byte from a previous byte. 215 | returns the cost that was, according to the costmodel, needed to get to the end. 216 | */ 217 | static double GetBestLengths(ZopfliBlockState *s, 218 | const unsigned char* in, 219 | size_t instart, size_t inend, 220 | CostModelFun* costmodel, void* costcontext, 221 | unsigned short* length_array, 222 | ZopfliHash* h, float* costs) { 223 | /* Best cost to get here so far. */ 224 | size_t blocksize = inend - instart; 225 | size_t i = 0, k, kend; 226 | unsigned short leng; 227 | unsigned short dist; 228 | unsigned short sublen[259]; 229 | size_t windowstart = instart > ZOPFLI_WINDOW_SIZE 230 | ? instart - ZOPFLI_WINDOW_SIZE : 0; 231 | double result; 232 | double mincost = GetCostModelMinCost(costmodel, costcontext); 233 | double mincostaddcostj; 234 | 235 | if (instart == inend) return 0; 236 | 237 | ZopfliResetHash(ZOPFLI_WINDOW_SIZE, h); 238 | ZopfliWarmupHash(in, windowstart, inend, h); 239 | for (i = windowstart; i < instart; i++) { 240 | ZopfliUpdateHash(in, i, inend, h); 241 | } 242 | 243 | for (i = 1; i < blocksize + 1; i++) costs[i] = ZOPFLI_LARGE_FLOAT; 244 | costs[0] = 0; /* Because it's the start. */ 245 | length_array[0] = 0; 246 | 247 | for (i = instart; i < inend; i++) { 248 | size_t j = i - instart; /* Index in the costs array and length_array. */ 249 | ZopfliUpdateHash(in, i, inend, h); 250 | 251 | #ifdef ZOPFLI_SHORTCUT_LONG_REPETITIONS 252 | /* If we're in a long repetition of the same character and have more than 253 | ZOPFLI_MAX_MATCH characters before and after our position. */ 254 | if (h->same[i & ZOPFLI_WINDOW_MASK] > ZOPFLI_MAX_MATCH * 2 255 | && i > instart + ZOPFLI_MAX_MATCH + 1 256 | && i + ZOPFLI_MAX_MATCH * 2 + 1 < inend 257 | && h->same[(i - ZOPFLI_MAX_MATCH) & ZOPFLI_WINDOW_MASK] 258 | > ZOPFLI_MAX_MATCH) { 259 | double symbolcost = costmodel(ZOPFLI_MAX_MATCH, 1, costcontext); 260 | /* Set the length to reach each one to ZOPFLI_MAX_MATCH, and the cost to 261 | the cost corresponding to that length. Doing this, we skip 262 | ZOPFLI_MAX_MATCH values to avoid calling ZopfliFindLongestMatch. */ 263 | for (k = 0; k < ZOPFLI_MAX_MATCH; k++) { 264 | costs[j + ZOPFLI_MAX_MATCH] = costs[j] + symbolcost; 265 | length_array[j + ZOPFLI_MAX_MATCH] = ZOPFLI_MAX_MATCH; 266 | i++; 267 | j++; 268 | ZopfliUpdateHash(in, i, inend, h); 269 | } 270 | } 271 | #endif 272 | 273 | ZopfliFindLongestMatch(s, h, in, i, inend, ZOPFLI_MAX_MATCH, sublen, 274 | &dist, &leng); 275 | 276 | /* Literal. */ 277 | if (i + 1 <= inend) { 278 | double newCost = costmodel(in[i], 0, costcontext) + costs[j]; 279 | assert(newCost >= 0); 280 | if (newCost < costs[j + 1]) { 281 | costs[j + 1] = newCost; 282 | length_array[j + 1] = 1; 283 | } 284 | } 285 | /* Lengths. */ 286 | kend = zopfli_min(leng, inend-i); 287 | mincostaddcostj = mincost + costs[j]; 288 | for (k = 3; k <= kend; k++) { 289 | double newCost; 290 | 291 | /* Calling the cost model is expensive, avoid this if we are already at 292 | the minimum possible cost that it can return. */ 293 | if (costs[j + k] <= mincostaddcostj) continue; 294 | 295 | newCost = costmodel(k, sublen[k], costcontext) + costs[j]; 296 | assert(newCost >= 0); 297 | if (newCost < costs[j + k]) { 298 | assert(k <= ZOPFLI_MAX_MATCH); 299 | costs[j + k] = newCost; 300 | length_array[j + k] = k; 301 | } 302 | } 303 | } 304 | 305 | assert(costs[blocksize] >= 0); 306 | result = costs[blocksize]; 307 | 308 | return result; 309 | } 310 | 311 | /* 312 | Calculates the optimal path of lz77 lengths to use, from the calculated 313 | length_array. The length_array must contain the optimal length to reach that 314 | byte. The path will be filled with the lengths to use, so its data size will be 315 | the amount of lz77 symbols. 316 | */ 317 | static void TraceBackwards(size_t size, const unsigned short* length_array, 318 | unsigned short** path, size_t* pathsize) { 319 | size_t index = size; 320 | if (size == 0) return; 321 | for (;;) { 322 | ZOPFLI_APPEND_DATA(length_array[index], path, pathsize); 323 | assert(length_array[index] <= index); 324 | assert(length_array[index] <= ZOPFLI_MAX_MATCH); 325 | assert(length_array[index] != 0); 326 | index -= length_array[index]; 327 | if (index == 0) break; 328 | } 329 | 330 | /* Mirror result. */ 331 | for (index = 0; index < *pathsize / 2; index++) { 332 | unsigned short temp = (*path)[index]; 333 | (*path)[index] = (*path)[*pathsize - index - 1]; 334 | (*path)[*pathsize - index - 1] = temp; 335 | } 336 | } 337 | 338 | static void FollowPath(ZopfliBlockState* s, 339 | const unsigned char* in, size_t instart, size_t inend, 340 | unsigned short* path, size_t pathsize, 341 | ZopfliLZ77Store* store, ZopfliHash *h) { 342 | size_t i, j, pos = 0; 343 | size_t windowstart = instart > ZOPFLI_WINDOW_SIZE 344 | ? instart - ZOPFLI_WINDOW_SIZE : 0; 345 | 346 | size_t total_length_test = 0; 347 | 348 | if (instart == inend) return; 349 | 350 | ZopfliResetHash(ZOPFLI_WINDOW_SIZE, h); 351 | ZopfliWarmupHash(in, windowstart, inend, h); 352 | for (i = windowstart; i < instart; i++) { 353 | ZopfliUpdateHash(in, i, inend, h); 354 | } 355 | 356 | pos = instart; 357 | for (i = 0; i < pathsize; i++) { 358 | unsigned short length = path[i]; 359 | unsigned short dummy_length; 360 | unsigned short dist; 361 | assert(pos < inend); 362 | 363 | ZopfliUpdateHash(in, pos, inend, h); 364 | 365 | /* Add to output. */ 366 | if (length >= ZOPFLI_MIN_MATCH) { 367 | /* Get the distance by recalculating longest match. The found length 368 | should match the length from the path. */ 369 | ZopfliFindLongestMatch(s, h, in, pos, inend, length, 0, 370 | &dist, &dummy_length); 371 | assert(!(dummy_length != length && length > 2 && dummy_length > 2)); 372 | ZopfliVerifyLenDist(in, inend, pos, dist, length); 373 | ZopfliStoreLitLenDist(length, dist, pos, store); 374 | total_length_test += length; 375 | } else { 376 | length = 1; 377 | ZopfliStoreLitLenDist(in[pos], 0, pos, store); 378 | total_length_test++; 379 | } 380 | 381 | 382 | assert(pos + length <= inend); 383 | for (j = 1; j < length; j++) { 384 | ZopfliUpdateHash(in, pos + j, inend, h); 385 | } 386 | 387 | pos += length; 388 | } 389 | } 390 | 391 | /* Calculates the entropy of the statistics */ 392 | static void CalculateStatistics(SymbolStats* stats) { 393 | ZopfliCalculateEntropy(stats->litlens, ZOPFLI_NUM_LL, stats->ll_symbols); 394 | ZopfliCalculateEntropy(stats->dists, ZOPFLI_NUM_D, stats->d_symbols); 395 | } 396 | 397 | /* Appends the symbol statistics from the store. */ 398 | static void GetStatistics(const ZopfliLZ77Store* store, SymbolStats* stats) { 399 | size_t i; 400 | for (i = 0; i < store->size; i++) { 401 | if (store->dists[i] == 0) { 402 | stats->litlens[store->litlens[i]]++; 403 | } else { 404 | stats->litlens[ZopfliGetLengthSymbol(store->litlens[i])]++; 405 | stats->dists[ZopfliGetDistSymbol(store->dists[i])]++; 406 | } 407 | } 408 | stats->litlens[256] = 1; /* End symbol. */ 409 | 410 | CalculateStatistics(stats); 411 | } 412 | 413 | /* 414 | Does a single run for ZopfliLZ77Optimal. For good compression, repeated runs 415 | with updated statistics should be performed. 416 | s: the block state 417 | in: the input data array 418 | instart: where to start 419 | inend: where to stop (not inclusive) 420 | path: pointer to dynamically allocated memory to store the path 421 | pathsize: pointer to the size of the dynamic path array 422 | length_array: array of size (inend - instart) used to store lengths 423 | costmodel: function to use as the cost model for this squeeze run 424 | costcontext: abstract context for the costmodel function 425 | store: place to output the LZ77 data 426 | returns the cost that was, according to the costmodel, needed to get to the end. 427 | This is not the actual cost. 428 | */ 429 | static double LZ77OptimalRun(ZopfliBlockState* s, 430 | const unsigned char* in, size_t instart, size_t inend, 431 | unsigned short** path, size_t* pathsize, 432 | unsigned short* length_array, CostModelFun* costmodel, 433 | void* costcontext, ZopfliLZ77Store* store, 434 | ZopfliHash* h, float* costs) { 435 | double cost = GetBestLengths(s, in, instart, inend, costmodel, 436 | costcontext, length_array, h, costs); 437 | free(*path); 438 | *path = 0; 439 | *pathsize = 0; 440 | TraceBackwards(inend - instart, length_array, path, pathsize); 441 | FollowPath(s, in, instart, inend, *path, *pathsize, store, h); 442 | assert(cost < ZOPFLI_LARGE_FLOAT); 443 | return cost; 444 | } 445 | 446 | void ZopfliLZ77Optimal(ZopfliBlockState *s, 447 | const unsigned char* in, size_t instart, size_t inend, 448 | int numiterations, 449 | ZopfliLZ77Store* store) { 450 | /* Dist to get to here with smallest cost. */ 451 | size_t blocksize = inend - instart; 452 | unsigned short* length_array = 453 | (unsigned short*)malloc(sizeof(unsigned short) * (blocksize + 1)); 454 | unsigned short* path = 0; 455 | size_t pathsize = 0; 456 | ZopfliLZ77Store currentstore; 457 | ZopfliHash hash; 458 | ZopfliHash* h = &hash; 459 | SymbolStats stats, beststats, laststats; 460 | int i; 461 | float* costs = (float*)malloc(sizeof(float) * (blocksize + 1)); 462 | double cost; 463 | double bestcost = ZOPFLI_LARGE_FLOAT; 464 | double lastcost = 0; 465 | /* Try randomizing the costs a bit once the size stabilizes. */ 466 | RanState ran_state; 467 | int lastrandomstep = -1; 468 | 469 | if (!costs) exit(-1); /* Allocation failed. */ 470 | if (!length_array) exit(-1); /* Allocation failed. */ 471 | 472 | InitRanState(&ran_state); 473 | InitStats(&stats); 474 | ZopfliInitLZ77Store(in, ¤tstore); 475 | ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h); 476 | 477 | /* Do regular deflate, then loop multiple shortest path runs, each time using 478 | the statistics of the previous run. */ 479 | 480 | /* Initial run. */ 481 | ZopfliLZ77Greedy(s, in, instart, inend, ¤tstore, h); 482 | GetStatistics(¤tstore, &stats); 483 | 484 | /* Repeat statistics with each time the cost model from the previous stat 485 | run. */ 486 | for (i = 0; i < numiterations; i++) { 487 | ZopfliCleanLZ77Store(¤tstore); 488 | ZopfliInitLZ77Store(in, ¤tstore); 489 | LZ77OptimalRun(s, in, instart, inend, &path, &pathsize, 490 | length_array, GetCostStat, (void*)&stats, 491 | ¤tstore, h, costs); 492 | cost = ZopfliCalculateBlockSize(¤tstore, 0, currentstore.size, 2); 493 | if (s->options->verbose_more || (s->options->verbose && cost < bestcost)) { 494 | fprintf(stderr, "Iteration %d: %d bit\n", i, (int) cost); 495 | } 496 | if (cost < bestcost) { 497 | /* Copy to the output store. */ 498 | ZopfliCopyLZ77Store(¤tstore, store); 499 | CopyStats(&stats, &beststats); 500 | bestcost = cost; 501 | } 502 | CopyStats(&stats, &laststats); 503 | ClearStatFreqs(&stats); 504 | GetStatistics(¤tstore, &stats); 505 | if (lastrandomstep != -1) { 506 | /* This makes it converge slower but better. Do it only once the 507 | randomness kicks in so that if the user does few iterations, it gives a 508 | better result sooner. */ 509 | AddWeighedStatFreqs(&stats, 1.0, &laststats, 0.5, &stats); 510 | CalculateStatistics(&stats); 511 | } 512 | if (i > 5 && cost == lastcost) { 513 | CopyStats(&beststats, &stats); 514 | RandomizeStatFreqs(&ran_state, &stats); 515 | CalculateStatistics(&stats); 516 | lastrandomstep = i; 517 | } 518 | lastcost = cost; 519 | } 520 | 521 | free(length_array); 522 | free(path); 523 | free(costs); 524 | ZopfliCleanLZ77Store(¤tstore); 525 | ZopfliCleanHash(h); 526 | } 527 | 528 | void ZopfliLZ77OptimalFixed(ZopfliBlockState *s, 529 | const unsigned char* in, 530 | size_t instart, size_t inend, 531 | ZopfliLZ77Store* store) 532 | { 533 | /* Dist to get to here with smallest cost. */ 534 | size_t blocksize = inend - instart; 535 | unsigned short* length_array = 536 | (unsigned short*)malloc(sizeof(unsigned short) * (blocksize + 1)); 537 | unsigned short* path = 0; 538 | size_t pathsize = 0; 539 | ZopfliHash hash; 540 | ZopfliHash* h = &hash; 541 | float* costs = (float*)malloc(sizeof(float) * (blocksize + 1)); 542 | 543 | if (!costs) exit(-1); /* Allocation failed. */ 544 | if (!length_array) exit(-1); /* Allocation failed. */ 545 | 546 | ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h); 547 | 548 | s->blockstart = instart; 549 | s->blockend = inend; 550 | 551 | /* Shortest path for fixed tree This one should give the shortest possible 552 | result for fixed tree, no repeated runs are needed since the tree is known. */ 553 | LZ77OptimalRun(s, in, instart, inend, &path, &pathsize, 554 | length_array, GetCostFixed, 0, store, h, costs); 555 | 556 | free(length_array); 557 | free(path); 558 | free(costs); 559 | ZopfliCleanHash(h); 560 | } 561 | -------------------------------------------------------------------------------- /src/zopfli/squeeze.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | The squeeze functions do enhanced LZ77 compression by optimal parsing with a 22 | cost model, rather than greedily choosing the longest length or using a single 23 | step of lazy matching like regular implementations. 24 | 25 | Since the cost model is based on the Huffman tree that can only be calculated 26 | after the LZ77 data is generated, there is a chicken and egg problem, and 27 | multiple runs are done with updated cost models to converge to a better 28 | solution. 29 | */ 30 | 31 | #ifndef ZOPFLI_SQUEEZE_H_ 32 | #define ZOPFLI_SQUEEZE_H_ 33 | 34 | #include "lz77.h" 35 | 36 | /* 37 | Calculates lit/len and dist pairs for given data. 38 | If instart is larger than 0, it uses values before instart as starting 39 | dictionary. 40 | */ 41 | void ZopfliLZ77Optimal(ZopfliBlockState *s, 42 | const unsigned char* in, size_t instart, size_t inend, 43 | int numiterations, 44 | ZopfliLZ77Store* store); 45 | 46 | /* 47 | Does the same as ZopfliLZ77Optimal, but optimized for the fixed tree of the 48 | deflate standard. 49 | The fixed tree never gives the best compression. But this gives the best 50 | possible LZ77 encoding possible with the fixed tree. 51 | This does not create or output any fixed tree, only LZ77 data optimized for 52 | using with a fixed tree. 53 | If instart is larger than 0, it uses values before instart as starting 54 | dictionary. 55 | */ 56 | void ZopfliLZ77OptimalFixed(ZopfliBlockState *s, 57 | const unsigned char* in, 58 | size_t instart, size_t inend, 59 | ZopfliLZ77Store* store); 60 | 61 | #endif /* ZOPFLI_SQUEEZE_H_ */ 62 | -------------------------------------------------------------------------------- /src/zopfli/symbols.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Utilities for using the lz77 symbols of the deflate spec. 22 | */ 23 | 24 | #ifndef ZOPFLI_SYMBOLS_H_ 25 | #define ZOPFLI_SYMBOLS_H_ 26 | 27 | /* __has_builtin available in clang */ 28 | #ifdef __has_builtin 29 | # if __has_builtin(__builtin_clz) 30 | # define ZOPFLI_HAS_BUILTIN_CLZ 31 | # endif 32 | /* __builtin_clz available beginning with GCC 3.4 */ 33 | #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 304 34 | # define ZOPFLI_HAS_BUILTIN_CLZ 35 | #endif 36 | 37 | /* Gets the amount of extra bits for the given dist, cfr. the DEFLATE spec. */ 38 | static int ZopfliGetDistExtraBits(int dist) { 39 | #ifdef ZOPFLI_HAS_BUILTIN_CLZ 40 | if (dist < 5) return 0; 41 | return (31 ^ __builtin_clz(dist - 1)) - 1; /* log2(dist - 1) - 1 */ 42 | #else 43 | if (dist < 5) return 0; 44 | else if (dist < 9) return 1; 45 | else if (dist < 17) return 2; 46 | else if (dist < 33) return 3; 47 | else if (dist < 65) return 4; 48 | else if (dist < 129) return 5; 49 | else if (dist < 257) return 6; 50 | else if (dist < 513) return 7; 51 | else if (dist < 1025) return 8; 52 | else if (dist < 2049) return 9; 53 | else if (dist < 4097) return 10; 54 | else if (dist < 8193) return 11; 55 | else if (dist < 16385) return 12; 56 | else return 13; 57 | #endif 58 | } 59 | 60 | /* Gets value of the extra bits for the given dist, cfr. the DEFLATE spec. */ 61 | static int ZopfliGetDistExtraBitsValue(int dist) { 62 | #ifdef ZOPFLI_HAS_BUILTIN_CLZ 63 | if (dist < 5) { 64 | return 0; 65 | } else { 66 | int l = 31 ^ __builtin_clz(dist - 1); /* log2(dist - 1) */ 67 | return (dist - (1 + (1 << l))) & ((1 << (l - 1)) - 1); 68 | } 69 | #else 70 | if (dist < 5) return 0; 71 | else if (dist < 9) return (dist - 5) & 1; 72 | else if (dist < 17) return (dist - 9) & 3; 73 | else if (dist < 33) return (dist - 17) & 7; 74 | else if (dist < 65) return (dist - 33) & 15; 75 | else if (dist < 129) return (dist - 65) & 31; 76 | else if (dist < 257) return (dist - 129) & 63; 77 | else if (dist < 513) return (dist - 257) & 127; 78 | else if (dist < 1025) return (dist - 513) & 255; 79 | else if (dist < 2049) return (dist - 1025) & 511; 80 | else if (dist < 4097) return (dist - 2049) & 1023; 81 | else if (dist < 8193) return (dist - 4097) & 2047; 82 | else if (dist < 16385) return (dist - 8193) & 4095; 83 | else return (dist - 16385) & 8191; 84 | #endif 85 | } 86 | 87 | /* Gets the symbol for the given dist, cfr. the DEFLATE spec. */ 88 | static int ZopfliGetDistSymbol(int dist) { 89 | #ifdef ZOPFLI_HAS_BUILTIN_CLZ 90 | if (dist < 5) { 91 | return dist - 1; 92 | } else { 93 | int l = (31 ^ __builtin_clz(dist - 1)); /* log2(dist - 1) */ 94 | int r = ((dist - 1) >> (l - 1)) & 1; 95 | return l * 2 + r; 96 | } 97 | #else 98 | if (dist < 193) { 99 | if (dist < 13) { /* dist 0..13. */ 100 | if (dist < 5) return dist - 1; 101 | else if (dist < 7) return 4; 102 | else if (dist < 9) return 5; 103 | else return 6; 104 | } else { /* dist 13..193. */ 105 | if (dist < 17) return 7; 106 | else if (dist < 25) return 8; 107 | else if (dist < 33) return 9; 108 | else if (dist < 49) return 10; 109 | else if (dist < 65) return 11; 110 | else if (dist < 97) return 12; 111 | else if (dist < 129) return 13; 112 | else return 14; 113 | } 114 | } else { 115 | if (dist < 2049) { /* dist 193..2049. */ 116 | if (dist < 257) return 15; 117 | else if (dist < 385) return 16; 118 | else if (dist < 513) return 17; 119 | else if (dist < 769) return 18; 120 | else if (dist < 1025) return 19; 121 | else if (dist < 1537) return 20; 122 | else return 21; 123 | } else { /* dist 2049..32768. */ 124 | if (dist < 3073) return 22; 125 | else if (dist < 4097) return 23; 126 | else if (dist < 6145) return 24; 127 | else if (dist < 8193) return 25; 128 | else if (dist < 12289) return 26; 129 | else if (dist < 16385) return 27; 130 | else if (dist < 24577) return 28; 131 | else return 29; 132 | } 133 | } 134 | #endif 135 | } 136 | 137 | /* Gets the amount of extra bits for the given length, cfr. the DEFLATE spec. */ 138 | static int ZopfliGetLengthExtraBits(int l) { 139 | static const int table[259] = { 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 141 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 142 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 143 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 144 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 145 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 146 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 147 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 148 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 149 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 150 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 151 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 152 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 153 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 154 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 155 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 156 | }; 157 | return table[l]; 158 | } 159 | 160 | /* Gets value of the extra bits for the given length, cfr. the DEFLATE spec. */ 161 | static int ZopfliGetLengthExtraBitsValue(int l) { 162 | static const int table[259] = { 163 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 0, 164 | 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 165 | 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 166 | 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 167 | 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 168 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 169 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 170 | 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 171 | 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 172 | 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 173 | 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 174 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0 175 | }; 176 | return table[l]; 177 | } 178 | 179 | /* 180 | Gets the symbol for the given length, cfr. the DEFLATE spec. 181 | Returns the symbol in the range [257-285] (inclusive) 182 | */ 183 | static int ZopfliGetLengthSymbol(int l) { 184 | static const int table[259] = { 185 | 0, 0, 0, 257, 258, 259, 260, 261, 262, 263, 264, 186 | 265, 265, 266, 266, 267, 267, 268, 268, 187 | 269, 269, 269, 269, 270, 270, 270, 270, 188 | 271, 271, 271, 271, 272, 272, 272, 272, 189 | 273, 273, 273, 273, 273, 273, 273, 273, 190 | 274, 274, 274, 274, 274, 274, 274, 274, 191 | 275, 275, 275, 275, 275, 275, 275, 275, 192 | 276, 276, 276, 276, 276, 276, 276, 276, 193 | 277, 277, 277, 277, 277, 277, 277, 277, 194 | 277, 277, 277, 277, 277, 277, 277, 277, 195 | 278, 278, 278, 278, 278, 278, 278, 278, 196 | 278, 278, 278, 278, 278, 278, 278, 278, 197 | 279, 279, 279, 279, 279, 279, 279, 279, 198 | 279, 279, 279, 279, 279, 279, 279, 279, 199 | 280, 280, 280, 280, 280, 280, 280, 280, 200 | 280, 280, 280, 280, 280, 280, 280, 280, 201 | 281, 281, 281, 281, 281, 281, 281, 281, 202 | 281, 281, 281, 281, 281, 281, 281, 281, 203 | 281, 281, 281, 281, 281, 281, 281, 281, 204 | 281, 281, 281, 281, 281, 281, 281, 281, 205 | 282, 282, 282, 282, 282, 282, 282, 282, 206 | 282, 282, 282, 282, 282, 282, 282, 282, 207 | 282, 282, 282, 282, 282, 282, 282, 282, 208 | 282, 282, 282, 282, 282, 282, 282, 282, 209 | 283, 283, 283, 283, 283, 283, 283, 283, 210 | 283, 283, 283, 283, 283, 283, 283, 283, 211 | 283, 283, 283, 283, 283, 283, 283, 283, 212 | 283, 283, 283, 283, 283, 283, 283, 283, 213 | 284, 284, 284, 284, 284, 284, 284, 284, 214 | 284, 284, 284, 284, 284, 284, 284, 284, 215 | 284, 284, 284, 284, 284, 284, 284, 284, 216 | 284, 284, 284, 284, 284, 284, 284, 285 217 | }; 218 | return table[l]; 219 | } 220 | 221 | /* Gets the amount of extra bits for the given length symbol. */ 222 | static int ZopfliGetLengthSymbolExtraBits(int s) { 223 | static const int table[29] = { 224 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 225 | 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 226 | }; 227 | return table[s - 257]; 228 | } 229 | 230 | /* Gets the amount of extra bits for the given distance symbol. */ 231 | static int ZopfliGetDistSymbolExtraBits(int s) { 232 | static const int table[30] = { 233 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 234 | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 235 | }; 236 | return table[s]; 237 | } 238 | 239 | #endif /* ZOPFLI_SYMBOLS_H_ */ 240 | -------------------------------------------------------------------------------- /src/zopfli/tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "tree.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "katajainen.h" 28 | #include "util.h" 29 | 30 | void ZopfliLengthsToSymbols(const unsigned* lengths, size_t n, unsigned maxbits, 31 | unsigned* symbols) { 32 | size_t* bl_count = (size_t*)malloc(sizeof(size_t) * (maxbits + 1)); 33 | size_t* next_code = (size_t*)malloc(sizeof(size_t) * (maxbits + 1)); 34 | unsigned bits, i; 35 | unsigned code; 36 | 37 | for (i = 0; i < n; i++) { 38 | symbols[i] = 0; 39 | } 40 | 41 | /* 1) Count the number of codes for each code length. Let bl_count[N] be the 42 | number of codes of length N, N >= 1. */ 43 | for (bits = 0; bits <= maxbits; bits++) { 44 | bl_count[bits] = 0; 45 | } 46 | for (i = 0; i < n; i++) { 47 | assert(lengths[i] <= maxbits); 48 | bl_count[lengths[i]]++; 49 | } 50 | /* 2) Find the numerical value of the smallest code for each code length. */ 51 | code = 0; 52 | bl_count[0] = 0; 53 | for (bits = 1; bits <= maxbits; bits++) { 54 | code = (code + bl_count[bits-1]) << 1; 55 | next_code[bits] = code; 56 | } 57 | /* 3) Assign numerical values to all codes, using consecutive values for all 58 | codes of the same length with the base values determined at step 2. */ 59 | for (i = 0; i < n; i++) { 60 | unsigned len = lengths[i]; 61 | if (len != 0) { 62 | symbols[i] = next_code[len]; 63 | next_code[len]++; 64 | } 65 | } 66 | 67 | free(bl_count); 68 | free(next_code); 69 | } 70 | 71 | void ZopfliCalculateEntropy(const size_t* count, size_t n, double* bitlengths) { 72 | static const double kInvLog2 = 1.4426950408889; /* 1.0 / log(2.0) */ 73 | unsigned sum = 0; 74 | unsigned i; 75 | double log2sum; 76 | for (i = 0; i < n; ++i) { 77 | sum += count[i]; 78 | } 79 | log2sum = (sum == 0 ? log(n) : log(sum)) * kInvLog2; 80 | for (i = 0; i < n; ++i) { 81 | /* When the count of the symbol is 0, but its cost is requested anyway, it 82 | means the symbol will appear at least once anyway, so give it the cost as if 83 | its count is 1.*/ 84 | if (count[i] == 0) bitlengths[i] = log2sum; 85 | else bitlengths[i] = log2sum - log(count[i]) * kInvLog2; 86 | /* Depending on compiler and architecture, the above subtraction of two 87 | floating point numbers may give a negative result very close to zero 88 | instead of zero (e.g. -5.973954e-17 with gcc 4.1.2 on Ubuntu 11.4). Clamp 89 | it to zero. These floating point imprecisions do not affect the cost model 90 | significantly so this is ok. */ 91 | if (bitlengths[i] < 0 && bitlengths[i] > -1e-5) bitlengths[i] = 0; 92 | assert(bitlengths[i] >= 0); 93 | } 94 | } 95 | 96 | void ZopfliCalculateBitLengths(const size_t* count, size_t n, int maxbits, 97 | unsigned* bitlengths) { 98 | int error = ZopfliLengthLimitedCodeLengths(count, n, maxbits, bitlengths); 99 | (void) error; 100 | assert(!error); 101 | } 102 | -------------------------------------------------------------------------------- /src/zopfli/tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Utilities for creating and using Huffman trees. 22 | */ 23 | 24 | #ifndef ZOPFLI_TREE_H_ 25 | #define ZOPFLI_TREE_H_ 26 | 27 | #include 28 | 29 | /* 30 | Calculates the bitlengths for the Huffman tree, based on the counts of each 31 | symbol. 32 | */ 33 | void ZopfliCalculateBitLengths(const size_t* count, size_t n, int maxbits, 34 | unsigned *bitlengths); 35 | 36 | /* 37 | Converts a series of Huffman tree bitlengths, to the bit values of the symbols. 38 | */ 39 | void ZopfliLengthsToSymbols(const unsigned* lengths, size_t n, unsigned maxbits, 40 | unsigned* symbols); 41 | 42 | /* 43 | Calculates the entropy of each symbol, based on the counts of each symbol. The 44 | result is similar to the result of ZopfliCalculateBitLengths, but with the 45 | actual theoritical bit lengths according to the entropy. Since the resulting 46 | values are fractional, they cannot be used to encode the tree specified by 47 | DEFLATE. 48 | */ 49 | void ZopfliCalculateEntropy(const size_t* count, size_t n, double* bitlengths); 50 | 51 | #endif /* ZOPFLI_TREE_H_ */ 52 | -------------------------------------------------------------------------------- /src/zopfli/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "util.h" 21 | 22 | #include "zopfli.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | void ZopfliInitOptions(ZopfliOptions* options) { 29 | options->verbose = 0; 30 | options->verbose_more = 0; 31 | options->numiterations = 15; 32 | options->blocksplitting = 1; 33 | options->blocksplittinglast = 0; 34 | options->blocksplittingmax = 15; 35 | } 36 | -------------------------------------------------------------------------------- /src/zopfli/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Several utilities, including: #defines to try different compression results, 22 | basic deflate specification values and generic program options. 23 | */ 24 | 25 | #ifndef ZOPFLI_UTIL_H_ 26 | #define ZOPFLI_UTIL_H_ 27 | 28 | #include 29 | #include 30 | 31 | /* Minimum and maximum length that can be encoded in deflate. */ 32 | #define ZOPFLI_MAX_MATCH 258 33 | #define ZOPFLI_MIN_MATCH 3 34 | 35 | /* Number of distinct literal/length and distance symbols in DEFLATE */ 36 | #define ZOPFLI_NUM_LL 288 37 | #define ZOPFLI_NUM_D 32 38 | 39 | /* 40 | The window size for deflate. Must be a power of two. This should be 32768, the 41 | maximum possible by the deflate spec. Anything less hurts compression more than 42 | speed. 43 | */ 44 | #define ZOPFLI_WINDOW_SIZE 32768 45 | 46 | /* 47 | The window mask used to wrap indices into the window. This is why the 48 | window size must be a power of two. 49 | */ 50 | #define ZOPFLI_WINDOW_MASK (ZOPFLI_WINDOW_SIZE - 1) 51 | 52 | /* 53 | A block structure of huge, non-smart, blocks to divide the input into, to allow 54 | operating on huge files without exceeding memory, such as the 1GB wiki9 corpus. 55 | The whole compression algorithm, including the smarter block splitting, will 56 | be executed independently on each huge block. 57 | Dividing into huge blocks hurts compression, but not much relative to the size. 58 | Set it to 0 to disable master blocks. 59 | */ 60 | #define ZOPFLI_MASTER_BLOCK_SIZE 1000000 61 | 62 | /* 63 | Used to initialize costs for example 64 | */ 65 | #define ZOPFLI_LARGE_FLOAT 1e30 66 | 67 | /* 68 | For longest match cache. max 256. Uses huge amounts of memory but makes it 69 | faster. Uses this many times three bytes per single byte of the input data. 70 | This is so because longest match finding has to find the exact distance 71 | that belongs to each length for the best lz77 strategy. 72 | Good values: e.g. 5, 8. 73 | */ 74 | #define ZOPFLI_CACHE_LENGTH 8 75 | 76 | /* 77 | limit the max hash chain hits for this hash value. This has an effect only 78 | on files where the hash value is the same very often. On these files, this 79 | gives worse compression (the value should ideally be 32768, which is the 80 | ZOPFLI_WINDOW_SIZE, while zlib uses 4096 even for best level), but makes it 81 | faster on some specific files. 82 | Good value: e.g. 8192. 83 | */ 84 | #define ZOPFLI_MAX_CHAIN_HITS 8192 85 | 86 | /* 87 | Whether to use the longest match cache for ZopfliFindLongestMatch. This cache 88 | consumes a lot of memory but speeds it up. No effect on compression size. 89 | */ 90 | #define ZOPFLI_LONGEST_MATCH_CACHE 91 | 92 | /* 93 | Enable to remember amount of successive identical bytes in the hash chain for 94 | finding longest match 95 | required for ZOPFLI_HASH_SAME_HASH and ZOPFLI_SHORTCUT_LONG_REPETITIONS 96 | This has no effect on the compression result, and enabling it increases speed. 97 | */ 98 | #define ZOPFLI_HASH_SAME 99 | 100 | /* 101 | Switch to a faster hash based on the info from ZOPFLI_HASH_SAME once the 102 | best length so far is long enough. This is way faster for files with lots of 103 | identical bytes, on which the compressor is otherwise too slow. Regular files 104 | are unaffected or maybe a tiny bit slower. 105 | This has no effect on the compression result, only on speed. 106 | */ 107 | #define ZOPFLI_HASH_SAME_HASH 108 | 109 | /* 110 | Enable this, to avoid slowness for files which are a repetition of the same 111 | character more than a multiple of ZOPFLI_MAX_MATCH times. This should not affect 112 | the compression result. 113 | */ 114 | #define ZOPFLI_SHORTCUT_LONG_REPETITIONS 115 | 116 | /* 117 | Whether to use lazy matching in the greedy LZ77 implementation. This gives a 118 | better result of ZopfliLZ77Greedy, but the effect this has on the optimal LZ77 119 | varies from file to file. 120 | */ 121 | #define ZOPFLI_LAZY_MATCHING 122 | 123 | /* 124 | Appends value to dynamically allocated memory, doubling its allocation size 125 | whenever needed. 126 | 127 | value: the value to append, type T 128 | data: pointer to the dynamic array to append to, type T** 129 | size: pointer to the size of the array to append to, type size_t*. This is the 130 | size that you consider the array to be, not the internal allocation size. 131 | Precondition: allocated size of data is at least a power of two greater than or 132 | equal than *size. 133 | */ 134 | #ifdef __cplusplus /* C++ cannot assign void* from malloc to *data */ 135 | #define ZOPFLI_APPEND_DATA(/* T */ value, /* T** */ data, /* size_t* */ size) {\ 136 | if (!((*size) & ((*size) - 1))) {\ 137 | /*double alloc size if it's a power of two*/\ 138 | void** data_void = reinterpret_cast(data);\ 139 | *data_void = (*size) == 0 ? malloc(sizeof(**data))\ 140 | : realloc((*data), (*size) * 2 * sizeof(**data));\ 141 | }\ 142 | (*data)[(*size)] = (value);\ 143 | (*size)++;\ 144 | } 145 | #else /* C gives problems with strict-aliasing rules for (void**) cast */ 146 | #define ZOPFLI_APPEND_DATA(/* T */ value, /* T** */ data, /* size_t* */ size) {\ 147 | if (!((*size) & ((*size) - 1))) {\ 148 | /*double alloc size if it's a power of two*/\ 149 | (*data) = (*size) == 0 ? malloc(sizeof(**data))\ 150 | : realloc((*data), (*size) * 2 * sizeof(**data));\ 151 | }\ 152 | (*data)[(*size)] = (value);\ 153 | (*size)++;\ 154 | } 155 | #endif 156 | 157 | 158 | #endif /* ZOPFLI_UTIL_H_ */ 159 | -------------------------------------------------------------------------------- /src/zopfli/zlib_container.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "zlib_container.h" 21 | #include "util.h" 22 | 23 | #include 24 | 25 | #include "deflate.h" 26 | 27 | 28 | /* Calculates the adler32 checksum of the data */ 29 | static unsigned adler32(const unsigned char* data, size_t size) 30 | { 31 | static const unsigned sums_overflow = 5550; 32 | unsigned s1 = 1; 33 | unsigned s2 = 1 >> 16; 34 | 35 | while (size > 0) { 36 | size_t amount = size > sums_overflow ? sums_overflow : size; 37 | size -= amount; 38 | while (amount > 0) { 39 | s1 += (*data++); 40 | s2 += s1; 41 | amount--; 42 | } 43 | s1 %= 65521; 44 | s2 %= 65521; 45 | } 46 | 47 | return (s2 << 16) | s1; 48 | } 49 | 50 | void ZopfliZlibCompress(const ZopfliOptions* options, 51 | const unsigned char* in, size_t insize, 52 | unsigned char** out, size_t* outsize) { 53 | unsigned char bitpointer = 0; 54 | unsigned checksum = adler32(in, (unsigned)insize); 55 | unsigned cmf = 120; /* CM 8, CINFO 7. See zlib spec.*/ 56 | unsigned flevel = 3; 57 | unsigned fdict = 0; 58 | unsigned cmfflg = 256 * cmf + fdict * 32 + flevel * 64; 59 | unsigned fcheck = 31 - cmfflg % 31; 60 | cmfflg += fcheck; 61 | 62 | ZOPFLI_APPEND_DATA(cmfflg / 256, out, outsize); 63 | ZOPFLI_APPEND_DATA(cmfflg % 256, out, outsize); 64 | 65 | ZopfliDeflate(options, 2 /* dynamic block */, 1 /* final */, 66 | in, insize, &bitpointer, out, outsize); 67 | 68 | ZOPFLI_APPEND_DATA((checksum >> 24) % 256, out, outsize); 69 | ZOPFLI_APPEND_DATA((checksum >> 16) % 256, out, outsize); 70 | ZOPFLI_APPEND_DATA((checksum >> 8) % 256, out, outsize); 71 | ZOPFLI_APPEND_DATA(checksum % 256, out, outsize); 72 | 73 | if (options->verbose) { 74 | fprintf(stderr, 75 | "Original Size: %d, Zlib: %d, Compression: %f%% Removed\n", 76 | (int)insize, (int)*outsize, 77 | 100.0 * (double)(insize - *outsize) / (double)insize); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/zopfli/zlib_container.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #ifndef ZOPFLI_ZLIB_H_ 21 | #define ZOPFLI_ZLIB_H_ 22 | 23 | /* 24 | Functions to compress according to the Zlib specification. 25 | */ 26 | 27 | #include "zopfli.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* 34 | Compresses according to the zlib specification and append the compressed 35 | result to the output. 36 | 37 | options: global program options 38 | out: pointer to the dynamic output array to which the result is appended. Must 39 | be freed after use. 40 | outsize: pointer to the dynamic output array size. 41 | */ 42 | void ZopfliZlibCompress(const ZopfliOptions* options, 43 | const unsigned char* in, size_t insize, 44 | unsigned char** out, size_t* outsize); 45 | 46 | #ifdef __cplusplus 47 | } // extern "C" 48 | #endif 49 | 50 | #endif /* ZOPFLI_ZLIB_H_ */ 51 | -------------------------------------------------------------------------------- /src/zopfli/zopfli.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #ifndef ZOPFLI_ZOPFLI_H_ 21 | #define ZOPFLI_ZOPFLI_H_ 22 | 23 | #include 24 | #include /* for size_t */ 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /* 31 | Options used throughout the program. 32 | */ 33 | typedef struct ZopfliOptions { 34 | /* Whether to print output */ 35 | int verbose; 36 | 37 | /* Whether to print more detailed output */ 38 | int verbose_more; 39 | 40 | /* 41 | Maximum amount of times to rerun forward and backward pass to optimize LZ77 42 | compression cost. Good values: 10, 15 for small files, 5 for files over 43 | several MB in size or it will be too slow. 44 | */ 45 | int numiterations; 46 | 47 | /* 48 | If true, splits the data in multiple deflate blocks with optimal choice 49 | for the block boundaries. Block splitting gives better compression. Default: 50 | true (1). 51 | */ 52 | int blocksplitting; 53 | 54 | /* 55 | No longer used, left for compatibility. 56 | */ 57 | int blocksplittinglast; 58 | 59 | /* 60 | Maximum amount of blocks to split into (0 for unlimited, but this can give 61 | extreme results that hurt compression on some files). Default value: 15. 62 | */ 63 | int blocksplittingmax; 64 | } ZopfliOptions; 65 | 66 | /* Initializes options with default values. */ 67 | void ZopfliInitOptions(ZopfliOptions* options); 68 | 69 | /* Output format */ 70 | typedef enum { 71 | ZOPFLI_FORMAT_GZIP, 72 | ZOPFLI_FORMAT_ZLIB, 73 | ZOPFLI_FORMAT_DEFLATE 74 | } ZopfliFormat; 75 | 76 | /* 77 | Compresses according to the given output format and appends the result to the 78 | output. 79 | 80 | options: global program options 81 | output_type: the output format to use 82 | out: pointer to the dynamic output array to which the result is appended. Must 83 | be freed after use 84 | outsize: pointer to the dynamic output array size 85 | */ 86 | void ZopfliCompress(const ZopfliOptions* options, ZopfliFormat output_type, 87 | const unsigned char* in, size_t insize, 88 | unsigned char** out, size_t* outsize); 89 | 90 | #ifdef __cplusplus 91 | } // extern "C" 92 | #endif 93 | 94 | #endif /* ZOPFLI_ZOPFLI_H_ */ 95 | -------------------------------------------------------------------------------- /src/zopfli/zopfli_bin.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | /* 21 | Zopfli compressor program. It can output gzip-, zlib- or deflate-compatible 22 | data. By default it creates a .gz file. This tool can only compress, not 23 | decompress. Decompression can be done by any standard gzip, zlib or deflate 24 | decompressor. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "deflate.h" 33 | #include "gzip_container.h" 34 | #include "zlib_container.h" 35 | 36 | /* Windows workaround for stdout output. */ 37 | #if _WIN32 38 | #include 39 | #endif 40 | 41 | /* 42 | Loads a file into a memory array. Returns 1 on success, 0 if file doesn't exist 43 | or couldn't be opened. 44 | */ 45 | static int LoadFile(const char* filename, 46 | unsigned char** out, size_t* outsize) { 47 | FILE* file; 48 | 49 | *out = 0; 50 | *outsize = 0; 51 | file = fopen(filename, "rb"); 52 | if (!file) return 0; 53 | 54 | fseek(file , 0 , SEEK_END); 55 | *outsize = ftell(file); 56 | if(*outsize > 2147483647) { 57 | fprintf(stderr,"Files larger than 2GB are not supported.\n"); 58 | exit(EXIT_FAILURE); 59 | } 60 | rewind(file); 61 | 62 | *out = (unsigned char*)malloc(*outsize); 63 | 64 | if (*outsize && (*out)) { 65 | size_t testsize = fread(*out, 1, *outsize, file); 66 | if (testsize != *outsize) { 67 | /* It could be a directory */ 68 | free(*out); 69 | *out = 0; 70 | *outsize = 0; 71 | fclose(file); 72 | return 0; 73 | } 74 | } 75 | 76 | assert(!(*outsize) || out); /* If size is not zero, out must be allocated. */ 77 | fclose(file); 78 | return 1; 79 | } 80 | 81 | /* 82 | Saves a file from a memory array, overwriting the file if it existed. 83 | */ 84 | static void SaveFile(const char* filename, 85 | const unsigned char* in, size_t insize) { 86 | FILE* file = fopen(filename, "wb" ); 87 | if (file == NULL) { 88 | fprintf(stderr,"Error: Cannot write to output file, terminating.\n"); 89 | exit (EXIT_FAILURE); 90 | } 91 | assert(file); 92 | fwrite((char*)in, 1, insize, file); 93 | fclose(file); 94 | } 95 | 96 | /* 97 | outfilename: filename to write output to, or 0 to write to stdout instead 98 | */ 99 | static void CompressFile(const ZopfliOptions* options, 100 | ZopfliFormat output_type, 101 | const char* infilename, 102 | const char* outfilename) { 103 | unsigned char* in; 104 | size_t insize; 105 | unsigned char* out = 0; 106 | size_t outsize = 0; 107 | if (!LoadFile(infilename, &in, &insize)) { 108 | fprintf(stderr, "Invalid filename: %s\n", infilename); 109 | return; 110 | } 111 | 112 | ZopfliCompress(options, output_type, in, insize, &out, &outsize); 113 | 114 | if (outfilename) { 115 | SaveFile(outfilename, out, outsize); 116 | } else { 117 | #if _WIN32 118 | /* Windows workaround for stdout output. */ 119 | _setmode(_fileno(stdout), _O_BINARY); 120 | #endif 121 | fwrite(out, 1, outsize, stdout); 122 | } 123 | 124 | free(out); 125 | free(in); 126 | } 127 | 128 | /* 129 | Add two strings together. Size does not matter. Result must be freed. 130 | */ 131 | static char* AddStrings(const char* str1, const char* str2) { 132 | size_t len = strlen(str1) + strlen(str2); 133 | char* result = (char*)malloc(len + 1); 134 | if (!result) exit(-1); /* Allocation failed. */ 135 | strcpy(result, str1); 136 | strcat(result, str2); 137 | return result; 138 | } 139 | 140 | static char StringsEqual(const char* str1, const char* str2) { 141 | return strcmp(str1, str2) == 0; 142 | } 143 | 144 | int main(int argc, char* argv[]) { 145 | ZopfliOptions options; 146 | ZopfliFormat output_type = ZOPFLI_FORMAT_GZIP; 147 | const char* filename = 0; 148 | int output_to_stdout = 0; 149 | int i; 150 | 151 | ZopfliInitOptions(&options); 152 | 153 | for (i = 1; i < argc; i++) { 154 | const char* arg = argv[i]; 155 | if (StringsEqual(arg, "-v")) options.verbose = 1; 156 | else if (StringsEqual(arg, "-c")) output_to_stdout = 1; 157 | else if (StringsEqual(arg, "--deflate")) { 158 | output_type = ZOPFLI_FORMAT_DEFLATE; 159 | } 160 | else if (StringsEqual(arg, "--zlib")) output_type = ZOPFLI_FORMAT_ZLIB; 161 | else if (StringsEqual(arg, "--gzip")) output_type = ZOPFLI_FORMAT_GZIP; 162 | else if (StringsEqual(arg, "--splitlast")) /* Ignore */; 163 | else if (arg[0] == '-' && arg[1] == '-' && arg[2] == 'i' 164 | && arg[3] >= '0' && arg[3] <= '9') { 165 | options.numiterations = atoi(arg + 3); 166 | } 167 | else if (StringsEqual(arg, "-h")) { 168 | fprintf(stderr, 169 | "Usage: zopfli [OPTION]... FILE...\n" 170 | " -h gives this help\n" 171 | " -c write the result on standard output, instead of disk" 172 | " filename + '.gz'\n" 173 | " -v verbose mode\n" 174 | " --i# perform # iterations (default 15). More gives" 175 | " more compression but is slower." 176 | " Examples: --i10, --i50, --i1000\n"); 177 | fprintf(stderr, 178 | " --gzip output to gzip format (default)\n" 179 | " --zlib output to zlib format instead of gzip\n" 180 | " --deflate output to deflate format instead of gzip\n" 181 | " --splitlast ignored, left for backwards compatibility\n"); 182 | return 0; 183 | } 184 | } 185 | 186 | if (options.numiterations < 1) { 187 | fprintf(stderr, "Error: must have 1 or more iterations\n"); 188 | return 0; 189 | } 190 | 191 | for (i = 1; i < argc; i++) { 192 | if (argv[i][0] != '-') { 193 | char* outfilename; 194 | filename = argv[i]; 195 | if (output_to_stdout) { 196 | outfilename = 0; 197 | } else if (output_type == ZOPFLI_FORMAT_GZIP) { 198 | outfilename = AddStrings(filename, ".gz"); 199 | } else if (output_type == ZOPFLI_FORMAT_ZLIB) { 200 | outfilename = AddStrings(filename, ".zlib"); 201 | } else { 202 | assert(output_type == ZOPFLI_FORMAT_DEFLATE); 203 | outfilename = AddStrings(filename, ".deflate"); 204 | } 205 | if (options.verbose && outfilename) { 206 | fprintf(stderr, "Saving to: %s\n", outfilename); 207 | } 208 | CompressFile(&options, output_type, filename, outfilename); 209 | free(outfilename); 210 | } 211 | } 212 | 213 | if (!filename) { 214 | fprintf(stderr, 215 | "Please provide filename\nFor help, type: %s -h\n", argv[0]); 216 | } 217 | 218 | return 0; 219 | } 220 | -------------------------------------------------------------------------------- /src/zopfli/zopfli_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Google Inc. All Rights Reserved. 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 | Author: lode.vandevenne@gmail.com (Lode Vandevenne) 17 | Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 18 | */ 19 | 20 | #include "zopfli.h" 21 | 22 | #include "deflate.h" 23 | #include "gzip_container.h" 24 | #include "zlib_container.h" 25 | 26 | #include 27 | 28 | void ZopfliCompress(const ZopfliOptions* options, ZopfliFormat output_type, 29 | const unsigned char* in, size_t insize, 30 | unsigned char** out, size_t* outsize) { 31 | if (output_type == ZOPFLI_FORMAT_GZIP) { 32 | ZopfliGzipCompress(options, in, insize, out, outsize); 33 | } else if (output_type == ZOPFLI_FORMAT_ZLIB) { 34 | ZopfliZlibCompress(options, in, insize, out, outsize); 35 | } else if (output_type == ZOPFLI_FORMAT_DEFLATE) { 36 | unsigned char bp = 0; 37 | ZopfliDeflate(options, 2 /* Dynamic block */, 1, 38 | in, insize, &bp, out, outsize); 39 | } else { 40 | assert(0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/zopflipng/lodepng/lodepng_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | LodePNG Utils 3 | 4 | Copyright (c) 2005-2020 Lode Vandevenne 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original software. 21 | 22 | 3. This notice may not be removed or altered from any source 23 | distribution. 24 | */ 25 | 26 | /* 27 | Extra C++ utilities for LodePNG, for convenience. 28 | Not part of the stable API of lodepng, more loose separate utils. 29 | */ 30 | 31 | #ifndef LODEPNG_UTIL_H 32 | #define LODEPNG_UTIL_H 33 | 34 | #include 35 | #include 36 | #include "lodepng.h" 37 | 38 | namespace lodepng { 39 | 40 | /* 41 | Returns info from the header of the PNG by value, purely for convenience. 42 | Does NOT check for errors. Returns bogus info if the PNG has an error. 43 | Does not require cleanup of allocated memory because no palette or text chunk 44 | info is in the LodePNGInfo object after checking only the header of the PNG. 45 | */ 46 | LodePNGInfo getPNGHeaderInfo(const std::vector& png); 47 | 48 | /* 49 | Get the names and sizes of all chunks in the PNG file. 50 | Returns 0 if ok, non-0 if error happened. 51 | */ 52 | unsigned getChunkInfo(std::vector& names, std::vector& sizes, 53 | const std::vector& png); 54 | 55 | /* 56 | Returns the names and full chunks (including the name and everything else that 57 | makes up the chunk) for all chunks except IHDR, PLTE, IDAT and IEND. 58 | It separates the chunks into 3 separate lists, representing the chunks between 59 | certain critical chunks: 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND 60 | Returns 0 if ok, non-0 if error happened. 61 | */ 62 | unsigned getChunks(std::vector names[3], 63 | std::vector > chunks[3], 64 | const std::vector& png); 65 | 66 | /* 67 | Inserts chunks into the given png file. The chunks must be fully encoded, 68 | including length, type, content and CRC. 69 | The array index determines where it goes: 70 | 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. 71 | They're appended at the end of those locations within the PNG. 72 | Returns 0 if ok, non-0 if error happened. 73 | */ 74 | unsigned insertChunks(std::vector& png, 75 | const std::vector > chunks[3]); 76 | 77 | /* 78 | Get the filtertypes of each scanline in this PNG file. 79 | Returns 0 if ok, 1 if PNG decoding error happened. 80 | 81 | For a non-interlaced PNG, it returns one filtertype per scanline, in order. 82 | 83 | For interlaced PNGs, it returns a result as if it's not interlaced. It returns 84 | one filtertype per scanline, in order. The values match pass 6 and 7 of the 85 | Adam7 interlacing, alternating between the two, so that the values correspond 86 | the most to their scanlines. 87 | */ 88 | unsigned getFilterTypes(std::vector& filterTypes, const std::vector& png); 89 | 90 | /* 91 | Get the filtertypes of each scanline in every interlace pass this PNG file. 92 | Returns 0 if ok, 1 if PNG decoding error happened. 93 | 94 | For a non-interlaced PNG, it returns one filtertype per scanline, in order, in 95 | a single std::vector in filterTypes. 96 | 97 | For an interlaced PNG, it returns 7 std::vectors in filterTypes, one for each 98 | Adam7 pass. The amount of values per pass can be calculated as follows, where 99 | w and h are the size of the image and all divisions are integer divisions: 100 | pass 1: (h + 7) / 8 101 | pass 2: w <= 4 ? 0 : (h + 7) / 8 102 | pass 3: h <= 4 ? 0 : (h + 7) / 8 103 | pass 4: w <= 2 ? 0 : (h + 3) / 4 104 | pass 5: h <= 2 ? 0 : (h + 3) / 4 105 | pass 6: w <= 1 ? 0 : (h + 1) / 2 106 | pass 7: h <= 1 ? 0 : (h + 1) / 2 107 | */ 108 | unsigned getFilterTypesInterlaced(std::vector >& filterTypes, 109 | const std::vector& png); 110 | 111 | /* 112 | Returns the value of the i-th pixel in an image with 1, 2, 4 or 8-bit color. 113 | E.g. if bits is 4 and i is 5, it returns the 5th nibble (4-bit group), which 114 | is the second half of the 3th byte, in big endian (PNG's endian order). 115 | */ 116 | int getPaletteValue(const unsigned char* data, size_t i, int bits); 117 | 118 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 119 | 120 | /* Similar to convertRGBModel, but the 'to' model is sRGB. The pixel format 121 | of in and out must be the same and is given by state_in->info_raw. An 122 | error may occur if the pixel format cannot contain the new colors (e.g. palette) */ 123 | unsigned convertToSrgb(unsigned char* out, const unsigned char* in, 124 | unsigned w, unsigned h, 125 | const LodePNGState* state_in); 126 | 127 | /* Similar to convertRGBModel, but the 'from' model is sRGB. The pixel format 128 | of in and out must be the same and is given by state_out->info_raw. An 129 | error may occur if the pixel format cannot contain the new colors (e.g. palette) */ 130 | unsigned convertFromSrgb(unsigned char* out, const unsigned char* in, 131 | unsigned w, unsigned h, 132 | const LodePNGState* state_out); 133 | 134 | /* 135 | Converts from one RGB model to another RGB model. 136 | Similar to calling convertToXYZ followed by convertFromXYZ, but may be 137 | more efficient and more precise (e.g. no computation needed when both models 138 | are the same). See their documentation for more info. 139 | 140 | Parameters: 141 | 142 | *) out: output pixel data 143 | *) in: input pixel data 144 | *) w, h: image size 145 | *) state_out: output RGB color model in state_out->info_png and byte format in state_out->info_raw. 146 | *) state_in: output RGB color model in state_in->info_png and byte format in state_in->info_raw 147 | *) return value: 0 if ok, positive value if error 148 | *) rendering_intent: 1 for relative, 3 for absolute, should be relative for standard behavior. 149 | See description at convertFromXYZ. 150 | */ 151 | unsigned convertRGBModel(unsigned char* out, const unsigned char* in, 152 | unsigned w, unsigned h, 153 | const LodePNGState* state_out, 154 | const LodePNGState* state_in, 155 | unsigned rendering_intent); 156 | 157 | /* 158 | Converts the RGB color to the absolute XYZ color space given the RGB color profile 159 | chunks in the PNG info. 160 | 161 | Color space here refers to the different possible RGB spaces with different 162 | possible chromaticities or whitepoint and XYZ color from colorimetry, not the 163 | LodePNGColorType that describes the byte based encoding. 164 | 165 | You need this function only if the PNG could contain data in an arbitrary RGB 166 | color space and you wish to output to a display or format that does not provide 167 | color management for you (so you need to convert rather than pass on the profile 168 | to it) but expects a certain RGB format (e.g. sRGB). See the background info below. 169 | 170 | Supports the gAMA, cHRM, sRGB and iCCP colorimetry chunks. If no colometry chunks are present 171 | (that is, in state->info_png, the fields gama_defined, chrm_defined, srgb_defined and 172 | iccp_defined are all 0), it assumes the format is sRGB. 173 | For more information, see the chunk specifications in the PNG specification. 174 | 175 | Some background: 176 | 177 | A PNG image contains RGB data inside, but this data may use a specific RGB model (by default sRGB but 178 | different if colorimetry chunks are given). 179 | The computer display and/or operating system can have another RGB model (typically sRGB, or wider gamut 180 | or HDR formats). 181 | 182 | The PNG chunks describe what format the data inside has, not the format of the display. To correctly 183 | display a PNG image on a display, a conversion is needed from the PNG model to the display model if their 184 | models differ. Some options to achieve that are: 185 | *) If your use case already supports color management on its own, you can give it the RGB values straight from 186 | the PNG image and give it the information from the cHRM, gAMA, sRGB and iCCP chunks (which you can find 187 | in the LodePNGInfo), and the color management should then handle it correctly for you. You don't need 188 | this function here in that case. 189 | *) If your use case does not support color management, you may instead want to give it the RGB values in a 190 | consistent color model, such as sRGB, but the PNG does not necessarily have it in this desired model. 191 | In that case, use the function below (or a similar one from a CMS library if you prefer) to convert it to 192 | the absolute color space XYZ, and then you can convert it to the target RGB with the counterpart convertFromXYZ 193 | further below. 194 | 195 | Parameters: 196 | 197 | *) out: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally, not clipped if beyond), must 198 | be allocated to have 4 * w * h floats available. 199 | *) whitepoint: output argument, the whitepoint the original RGB data used, given in absolute XYZ. Needed for 200 | relative rendering intents: give these values to counterpart function convertFromXYZ. 201 | *) in: input RGB color, in byte format given by state->info_raw and RGB color profile given by info->info_png 202 | *) w, h: image size 203 | *) state (when using a LodePNG decode function that takes a LodePNGState parameter, can directly use that one): 204 | state->info_png: PNG info with possibly an RGB color model in cHRM,gAMA and/or sRGB chunks 205 | state->info_raw: byte format of in (amount of channels, bit depth) 206 | *) return value: 0 if ok, positive value if error 207 | */ 208 | unsigned convertToXYZ(float* out, float whitepoint[3], 209 | const unsigned char* in, unsigned w, unsigned h, 210 | const LodePNGState* state); 211 | 212 | /* 213 | Same as convertToXYZ but takes floating point input. Slower. 214 | The main black..white range in 0..1. Does not clip values that are outside that range. 215 | */ 216 | unsigned convertToXYZFloat(float* out, float whitepoint[3], const float* in, 217 | unsigned w, unsigned h, const LodePNGState* state); 218 | 219 | /* 220 | Converts XYZ to RGB in the RGB color model given by info and byte format by mode_out. 221 | If info has no coloremtry chunks, converts to sRGB. 222 | Parameters: 223 | *) out: output color in byte format given by state->info_raw and RGB color profile given 224 | by info->info_png. Must have enough bytes allocated to contain pixels in the given byte format. 225 | *) in: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally). 226 | *) whitepoint: input argument, the original whitepoint in absolute XYZ that the pixel data 227 | in "in" had back when it was in a previous RGB space. Needed to preserve the whitepoint 228 | in the new target RGB space for relative rendering intent. 229 | *) rendering_intent: the desired rendering intent, with numeric meaning matching the 230 | values used by ICC: 0=perceptual, 1=relative, 2=saturation, 3=absolute. 231 | Should be 1 for normal use cases, it adapts white to match that of different RGB 232 | models which is the best practice. Using 3 may change the color of white and may 233 | turn grayscale into colors of a certain tone. Using 0 and 2 will have the same 234 | effect as 1 because using those requires more data than the matrix-based RGB profiles 235 | supporetd here have. 236 | *) w, h: image size 237 | *) state: 238 | state->info_png: PNG info with possibly an RGB color profile in cHRM,gAMA and/or sRGB chunks 239 | state->info_raw: byte format of out (amount of channels, bit depth) 240 | *) return value: 0 if ok, positive value if error 241 | */ 242 | unsigned convertFromXYZ(unsigned char* out, const float* in, unsigned w, unsigned h, 243 | const LodePNGState* state, 244 | const float whitepoint[3], unsigned rendering_intent); 245 | 246 | /* 247 | Same as convertFromXYZ but outputs the RGB colors in floating point. 248 | The main black..white range in 0..1. Does not clip values that are outside that range. 249 | */ 250 | unsigned convertFromXYZFloat(float* out, const float* in, unsigned w, unsigned h, 251 | const LodePNGState* state, 252 | const float whitepoint[3], unsigned rendering_intent); 253 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 254 | 255 | /* 256 | The information for extractZlibInfo. 257 | */ 258 | struct ZlibBlockInfo { 259 | int btype; //block type (0-2) 260 | size_t compressedbits; //size of compressed block in bits 261 | size_t uncompressedbytes; //size of uncompressed block in bytes 262 | 263 | // only filled in for block type 2 264 | size_t treebits; //encoded tree size in bits 265 | int hlit; //the HLIT value that was filled in for this tree 266 | int hdist; //the HDIST value that was filled in for this tree 267 | int hclen; //the HCLEN value that was filled in for this tree 268 | std::vector clcl; //19 code length code lengths (compressed tree's tree) 269 | std::vector treecodes; //N tree codes, with values 0-18. Values 17 or 18 are followed by the repetition value. 270 | std::vector litlenlengths; //288 code lengths for lit/len symbols 271 | std::vector distlengths; //32 code lengths for dist symbols 272 | 273 | // only filled in for block types 1 or 2 274 | std::vector lz77_lcode; //LZ77 codes. 0-255: literals. 256: end symbol. 257-285: length code of length/dist pairs 275 | // the next vectors have the same size as lz77_lcode, but an element only has meaningful value if lz77_lcode contains a length code. 276 | std::vector lz77_dcode; 277 | std::vector lz77_lbits; 278 | std::vector lz77_dbits; 279 | std::vector lz77_lvalue; 280 | std::vector lz77_dvalue; 281 | size_t numlit; //number of lit codes in this block 282 | size_t numlen; //number of len codes in this block 283 | }; 284 | 285 | //Extracts all info needed from a PNG file to reconstruct the zlib compression exactly. 286 | void extractZlibInfo(std::vector& zlibinfo, const std::vector& in); 287 | 288 | } // namespace lodepng 289 | 290 | #endif /*LODEPNG_UTIL_H inclusion guard*/ 291 | -------------------------------------------------------------------------------- /src/zopflipng/zopflipng_bin.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: lode.vandevenne@gmail.com (Lode Vandevenne) 16 | // Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 17 | 18 | // Command line tool to recompress and optimize PNG images, using zopflipng_lib. 19 | 20 | #include 21 | #include 22 | 23 | #include "lodepng/lodepng.h" 24 | #include "lodepng/lodepng_util.h" 25 | #include "zopflipng_lib.h" 26 | 27 | // Returns directory path (including last slash) in dir, filename without 28 | // extension in file, extension (including the dot) in ext 29 | void GetFileNameParts(const std::string& filename, 30 | std::string* dir, std::string* file, std::string* ext) { 31 | size_t npos = (size_t)(-1); 32 | size_t slashpos = filename.find_last_of("/\\"); 33 | std::string nodir; 34 | if (slashpos == npos) { 35 | *dir = ""; 36 | nodir = filename; 37 | } else { 38 | *dir = filename.substr(0, slashpos + 1); 39 | nodir = filename.substr(slashpos + 1); 40 | } 41 | size_t dotpos = nodir.find_last_of('.'); 42 | if (dotpos == (size_t)(-1)) { 43 | *file = nodir; 44 | *ext = ""; 45 | } else { 46 | *file = nodir.substr(0, dotpos); 47 | *ext = nodir.substr(dotpos); 48 | } 49 | } 50 | 51 | // Returns whether the file exists and we have read permissions. 52 | bool FileExists(const std::string& filename) { 53 | FILE* file = fopen(filename.c_str(), "rb"); 54 | if (file) { 55 | fclose(file); 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | // Returns the size of the file, if it exists and we have read permissions. 62 | size_t GetFileSize(const std::string& filename) { 63 | size_t size; 64 | FILE* file = fopen(filename.c_str(), "rb"); 65 | if (!file) return 0; 66 | fseek(file , 0 , SEEK_END); 67 | size = static_cast(ftell(file)); 68 | fclose(file); 69 | return size; 70 | } 71 | 72 | void ShowHelp() { 73 | printf("ZopfliPNG, a Portable Network Graphics (PNG) image optimizer.\n" 74 | "\n" 75 | "Usage: zopflipng [options]... infile.png outfile.png\n" 76 | " zopflipng [options]... --prefix=[fileprefix] [files.png]...\n" 77 | "\n" 78 | "If the output file exists, it is considered a result from a" 79 | " previous run and not overwritten if its filesize is smaller.\n" 80 | "\n" 81 | "Options:\n" 82 | "-m: compress more: use more iterations (depending on file size)\n" 83 | "--prefix=[fileprefix]: Adds a prefix to output filenames. May also" 84 | " contain a directory path. When using a prefix, multiple input files" 85 | " can be given and the output filenames are generated with the" 86 | " prefix\n" 87 | " If --prefix is specified without value, 'zopfli_' is used.\n" 88 | " If input file names contain the prefix, they are not processed but" 89 | " considered as output from previous runs. This is handy when using" 90 | " *.png wildcard expansion with multiple runs.\n" 91 | "-y: do not ask about overwriting files.\n" 92 | "--lossy_transparent: remove colors behind alpha channel 0. No visual" 93 | " difference, removes hidden information.\n" 94 | "--lossy_8bit: convert 16-bit per channel image to 8-bit per" 95 | " channel.\n" 96 | "-d: dry run: don't save any files, just see the console output" 97 | " (e.g. for benchmarking)\n" 98 | "--always_zopflify: always output the image encoded by Zopfli, even if" 99 | " it's bigger than the original, for benchmarking the algorithm. Not" 100 | " good for real optimization.\n" 101 | "-q: use quick, but not very good, compression" 102 | " (e.g. for only trying the PNG filter and color types)\n" 103 | "--iterations=[number]: number of iterations, more iterations makes it" 104 | " slower but provides slightly better compression. Default: 15 for" 105 | " small files, 5 for large files.\n" 106 | "--splitting=[0-3]: ignored, left for backwards compatibility\n" 107 | "--filters=[types]: filter strategies to try:\n" 108 | " 0-4: give all scanlines PNG filter type 0-4\n" 109 | " m: minimum sum\n" 110 | " e: entropy\n" 111 | " p: predefined (keep from input, this likely overlaps another" 112 | " strategy)\n" 113 | " b: brute force (experimental)\n" 114 | " By default, if this argument is not given, one that is most likely" 115 | " the best for this image is chosen by trying faster compression with" 116 | " each type.\n" 117 | " If this argument is used, all given filter types" 118 | " are tried with slow compression and the best result retained. A good" 119 | " set of filters to try is --filters=0me.\n" 120 | "--keepchunks=nAME,nAME,...: keep metadata chunks with these names" 121 | " that would normally be removed, e.g. tEXt,zTXt,iTXt,gAMA, ... \n" 122 | " Due to adding extra data, this increases the result size. Keeping" 123 | " bKGD or sBIT chunks may cause additional worse compression due to" 124 | " forcing a certain color type, it is advised to not keep these for" 125 | " web images because web browsers do not use these chunks. By default" 126 | " ZopfliPNG only keeps (and losslessly modifies) the following chunks" 127 | " because they are essential: IHDR, PLTE, tRNS, IDAT and IEND.\n" 128 | "--keepcolortype: Keep original color type (RGB, RGBA, gray," 129 | " gray+alpha or palette) and bit depth of the PNG.\n" 130 | " This results in a loss of compression opportunities, e.g. it will no" 131 | " longer convert a 4-channel RGBA image to 2-channel gray+alpha if the" 132 | " image only had translucent gray pixels.\n" 133 | " May be useful if a device does not support decoding PNGs of a" 134 | " particular color type.\n" 135 | "\n" 136 | "Usage examples:\n" 137 | "Optimize a file and overwrite if smaller: zopflipng infile.png" 138 | " outfile.png\n" 139 | "Compress more: zopflipng -m infile.png outfile.png\n" 140 | "Optimize multiple files: zopflipng --prefix a.png b.png c.png\n" 141 | "Compress really good and trying all filter strategies: zopflipng" 142 | " --iterations=500 --filters=01234mepb --lossy_8bit" 143 | " --lossy_transparent infile.png outfile.png\n"); 144 | } 145 | 146 | void PrintSize(const char* label, size_t size) { 147 | printf("%s: %d (%dK)\n", label, (int) size, (int) size / 1024); 148 | } 149 | 150 | void PrintResultSize(const char* label, size_t oldsize, size_t newsize) { 151 | printf("%s: %d (%dK). Percentage of original: %.3f%%\n", 152 | label, (int) newsize, (int) newsize / 1024, newsize * 100.0 / oldsize); 153 | } 154 | 155 | int main(int argc, char *argv[]) { 156 | if (argc < 2) { 157 | ShowHelp(); 158 | return 0; 159 | } 160 | 161 | ZopfliPNGOptions png_options; 162 | 163 | // cmd line options 164 | bool always_zopflify = false; // overwrite file even if we have bigger result 165 | bool yes = false; // do not ask to overwrite files 166 | bool dryrun = false; // never save anything 167 | 168 | std::string user_out_filename; // output filename if no prefix is used 169 | bool use_prefix = false; 170 | std::string prefix = "zopfli_"; // prefix for output filenames 171 | 172 | std::vector files; 173 | for (int i = 1; i < argc; i++) { 174 | std::string arg = argv[i]; 175 | if (arg[0] == '-' && arg.size() > 1 && arg[1] != '-') { 176 | for (size_t pos = 1; pos < arg.size(); pos++) { 177 | char c = arg[pos]; 178 | if (c == 'y') { 179 | yes = true; 180 | } else if (c == 'd') { 181 | dryrun = true; 182 | } else if (c == 'm') { 183 | png_options.num_iterations *= 4; 184 | png_options.num_iterations_large *= 4; 185 | } else if (c == 'q') { 186 | png_options.use_zopfli = false; 187 | } else if (c == 'h') { 188 | ShowHelp(); 189 | return 0; 190 | } else { 191 | printf("Unknown flag: %c\n", c); 192 | return 0; 193 | } 194 | } 195 | } else if (arg[0] == '-' && arg.size() > 1 && arg[1] == '-') { 196 | size_t eq = arg.find('='); 197 | std::string name = arg.substr(0, eq); 198 | std::string value = eq >= arg.size() - 1 ? "" : arg.substr(eq + 1); 199 | int num = atoi(value.c_str()); 200 | if (name == "--always_zopflify") { 201 | always_zopflify = true; 202 | } else if (name == "--verbose") { 203 | png_options.verbose = true; 204 | } else if (name == "--lossy_transparent") { 205 | png_options.lossy_transparent = true; 206 | } else if (name == "--lossy_8bit") { 207 | png_options.lossy_8bit = true; 208 | } else if (name == "--iterations") { 209 | if (num < 1) num = 1; 210 | png_options.num_iterations = num; 211 | png_options.num_iterations_large = num; 212 | } else if (name == "--splitting") { 213 | // ignored 214 | } else if (name == "--filters") { 215 | for (size_t j = 0; j < value.size(); j++) { 216 | ZopfliPNGFilterStrategy strategy = kStrategyZero; 217 | char f = value[j]; 218 | switch (f) { 219 | case '0': strategy = kStrategyZero; break; 220 | case '1': strategy = kStrategyOne; break; 221 | case '2': strategy = kStrategyTwo; break; 222 | case '3': strategy = kStrategyThree; break; 223 | case '4': strategy = kStrategyFour; break; 224 | case 'm': strategy = kStrategyMinSum; break; 225 | case 'e': strategy = kStrategyEntropy; break; 226 | case 'p': strategy = kStrategyPredefined; break; 227 | case 'b': strategy = kStrategyBruteForce; break; 228 | default: 229 | printf("Unknown filter strategy: %c\n", f); 230 | return 1; 231 | } 232 | png_options.filter_strategies.push_back(strategy); 233 | // Enable auto filter strategy only if no user-specified filter is 234 | // given. 235 | png_options.auto_filter_strategy = false; 236 | } 237 | } else if (name == "--keepchunks") { 238 | bool correct = true; 239 | if ((value.size() + 1) % 5 != 0) correct = false; 240 | for (size_t i = 0; i + 4 <= value.size() && correct; i += 5) { 241 | png_options.keepchunks.push_back(value.substr(i, 4)); 242 | if (i > 4 && value[i - 1] != ',') correct = false; 243 | } 244 | if (!correct) { 245 | printf("Error: keepchunks format must be like for example:\n" 246 | " --keepchunks=gAMA,cHRM,sRGB,iCCP\n"); 247 | return 0; 248 | } 249 | } else if (name == "--keepcolortype") { 250 | png_options.keep_colortype = true; 251 | } else if (name == "--prefix") { 252 | use_prefix = true; 253 | if (!value.empty()) prefix = value; 254 | } else if (name == "--help") { 255 | ShowHelp(); 256 | return 0; 257 | } else { 258 | printf("Unknown flag: %s\n", name.c_str()); 259 | return 0; 260 | } 261 | } else { 262 | files.push_back(argv[i]); 263 | } 264 | } 265 | 266 | if (!use_prefix) { 267 | if (files.size() == 2) { 268 | // The second filename is the output instead of an input if no prefix is 269 | // given. 270 | user_out_filename = files[1]; 271 | files.resize(1); 272 | } else { 273 | printf("Please provide one input and output filename\n\n"); 274 | ShowHelp(); 275 | return 0; 276 | } 277 | } 278 | 279 | size_t total_in_size = 0; 280 | // Total output size, taking input size if the input file was smaller 281 | size_t total_out_size = 0; 282 | // Total output size that zopfli produced, even if input was smaller, for 283 | // benchmark information 284 | size_t total_out_size_zopfli = 0; 285 | size_t total_errors = 0; 286 | size_t total_files = 0; 287 | size_t total_files_smaller = 0; 288 | size_t total_files_saved = 0; 289 | size_t total_files_equal = 0; 290 | 291 | for (size_t i = 0; i < files.size(); i++) { 292 | if (use_prefix && files.size() > 1) { 293 | std::string dir, file, ext; 294 | GetFileNameParts(files[i], &dir, &file, &ext); 295 | // avoid doing filenames which were already output by this so that you 296 | // don't get zopfli_zopfli_zopfli_... files after multiple runs. 297 | if (file.find(prefix) == 0) continue; 298 | } 299 | 300 | total_files++; 301 | 302 | printf("Optimizing %s\n", files[i].c_str()); 303 | std::vector image; 304 | unsigned w, h; 305 | std::vector origpng; 306 | unsigned error; 307 | lodepng::State inputstate; 308 | std::vector resultpng; 309 | 310 | error = lodepng::load_file(origpng, files[i]); 311 | if (!error) { 312 | error = ZopfliPNGOptimize(origpng, png_options, 313 | png_options.verbose, &resultpng); 314 | } 315 | 316 | if (error) { 317 | if (error == 1) { 318 | printf("Decoding error\n"); 319 | } else { 320 | printf("Decoding error %u: %s\n", error, lodepng_error_text(error)); 321 | } 322 | } 323 | 324 | // Verify result, check that the result causes no decoding errors 325 | if (!error) { 326 | error = lodepng::decode(image, w, h, resultpng); 327 | if (!error) { 328 | std::vector origimage; 329 | unsigned origw, origh; 330 | lodepng::decode(origimage, origw, origh, origpng); 331 | if (origw != w || origh != h || origimage.size() != image.size()) { 332 | error = 1; 333 | } else { 334 | for (size_t i = 0; i < image.size(); i += 4) { 335 | bool same_alpha = image[i + 3] == origimage[i + 3]; 336 | bool same_rgb = 337 | (png_options.lossy_transparent && image[i + 3] == 0) || 338 | (image[i + 0] == origimage[i + 0] && 339 | image[i + 1] == origimage[i + 1] && 340 | image[i + 2] == origimage[i + 2]); 341 | if (!same_alpha || !same_rgb) { 342 | error = 1; 343 | break; 344 | } 345 | } 346 | } 347 | } 348 | if (error) { 349 | printf("Error: verification of result failed, keeping original." 350 | " Error: %u.\n", error); 351 | // Reset the error to 0, instead set output back to the original. The 352 | // input PNG is valid, zopfli failed on it so treat as if it could not 353 | // make it smaller. 354 | error = 0; 355 | resultpng = origpng; 356 | } 357 | } 358 | 359 | if (error) { 360 | total_errors++; 361 | } else { 362 | size_t origsize = origpng.size(); 363 | size_t resultsize = resultpng.size(); 364 | 365 | if (!png_options.keepchunks.empty()) { 366 | std::vector names; 367 | std::vector sizes; 368 | lodepng::getChunkInfo(names, sizes, resultpng); 369 | for (size_t i = 0; i < names.size(); i++) { 370 | if (names[i] == "bKGD" || names[i] == "sBIT") { 371 | printf("Forced to keep original color type due to keeping bKGD or" 372 | " sBIT chunk. Try without --keepchunks for better" 373 | " compression.\n"); 374 | break; 375 | } 376 | } 377 | } 378 | 379 | PrintSize("Input size", origsize); 380 | PrintResultSize("Result size", origsize, resultsize); 381 | if (resultsize < origsize) { 382 | printf("Result is smaller\n"); 383 | } else if (resultsize == origsize) { 384 | printf("Result has exact same size\n"); 385 | } else { 386 | printf(always_zopflify 387 | ? "Original was smaller\n" 388 | : "Preserving original PNG since it was smaller\n"); 389 | } 390 | 391 | std::string out_filename = user_out_filename; 392 | if (use_prefix) { 393 | std::string dir, file, ext; 394 | GetFileNameParts(files[i], &dir, &file, &ext); 395 | out_filename = dir + prefix + file + ext; 396 | } 397 | bool different_output_name = out_filename != files[i]; 398 | 399 | total_in_size += origsize; 400 | total_out_size_zopfli += resultpng.size(); 401 | if (resultpng.size() < origsize) total_files_smaller++; 402 | else if (resultpng.size() == origsize) total_files_equal++; 403 | 404 | if (!always_zopflify && resultpng.size() >= origsize) { 405 | // Set output file to input since zopfli didn't improve it. 406 | resultpng = origpng; 407 | } 408 | 409 | bool already_exists = FileExists(out_filename); 410 | size_t origoutfilesize = GetFileSize(out_filename); 411 | 412 | // When using a prefix, and the output file already exist, assume it's 413 | // from a previous run. If that file is smaller, it may represent a 414 | // previous run with different parameters that gave a smaller PNG image. 415 | // This also applies when not using prefix but same input as output file. 416 | // In that case, do not overwrite it. This behaviour can be removed by 417 | // adding the always_zopflify flag. 418 | bool keep_earlier_output_file = already_exists && 419 | resultpng.size() >= origoutfilesize && !always_zopflify && 420 | (use_prefix || !different_output_name); 421 | 422 | if (keep_earlier_output_file) { 423 | // An output file from a previous run is kept, add that files' size 424 | // to the output size statistics. 425 | total_out_size += origoutfilesize; 426 | if (use_prefix) { 427 | printf(resultpng.size() == origoutfilesize 428 | ? "File not written because a previous run was as good.\n" 429 | : "File not written because a previous run was better.\n"); 430 | } 431 | } else { 432 | bool confirmed = true; 433 | if (!yes && !dryrun && already_exists) { 434 | printf("File %s exists, overwrite? (y/N) ", out_filename.c_str()); 435 | char answer = 0; 436 | // Read the first character, the others and enter with getchar. 437 | while (int input = getchar()) { 438 | if (input == '\n' || input == EOF) break; 439 | else if (!answer) answer = input; 440 | } 441 | confirmed = answer == 'y' || answer == 'Y'; 442 | } 443 | if (confirmed) { 444 | if (!dryrun) { 445 | if (lodepng::save_file(resultpng, out_filename) != 0) { 446 | printf("Failed to write to file %s\n", out_filename.c_str()); 447 | } else { 448 | total_files_saved++; 449 | } 450 | } 451 | total_out_size += resultpng.size(); 452 | } else { 453 | // An output file from a previous run is kept, add that files' size 454 | // to the output size statistics. 455 | total_out_size += origoutfilesize; 456 | } 457 | } 458 | } 459 | printf("\n"); 460 | } 461 | 462 | if (total_files > 1) { 463 | printf("Summary for all files:\n"); 464 | printf("Files tried: %d\n", (int) total_files); 465 | printf("Files smaller: %d\n", (int) total_files_smaller); 466 | if (total_files_equal) { 467 | printf("Files equal: %d\n", (int) total_files_equal); 468 | } 469 | printf("Files saved: %d\n", (int) total_files_saved); 470 | if (total_errors) printf("Errors: %d\n", (int) total_errors); 471 | PrintSize("Total input size", total_in_size); 472 | PrintResultSize("Total output size", total_in_size, total_out_size); 473 | PrintResultSize("Benchmark result size", 474 | total_in_size, total_out_size_zopfli); 475 | } 476 | 477 | if (dryrun) printf("No files were written because dry run was specified\n"); 478 | 479 | return total_errors; 480 | } 481 | -------------------------------------------------------------------------------- /src/zopflipng/zopflipng_lib.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: lode.vandevenne@gmail.com (Lode Vandevenne) 16 | // Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 17 | 18 | // See zopflipng_lib.h 19 | 20 | #include "zopflipng_lib.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "lodepng/lodepng.h" 30 | #include "lodepng/lodepng_util.h" 31 | #include "../zopfli/deflate.h" 32 | 33 | ZopfliPNGOptions::ZopfliPNGOptions() 34 | : verbose(false) 35 | , lossy_transparent(false) 36 | , lossy_8bit(false) 37 | , auto_filter_strategy(true) 38 | , keep_colortype(false) 39 | , use_zopfli(true) 40 | , num_iterations(15) 41 | , num_iterations_large(5) 42 | , block_split_strategy(1) { 43 | } 44 | 45 | // Deflate compressor passed as fuction pointer to LodePNG to have it use Zopfli 46 | // as its compression backend. 47 | unsigned CustomPNGDeflate(unsigned char** out, size_t* outsize, 48 | const unsigned char* in, size_t insize, 49 | const LodePNGCompressSettings* settings) { 50 | const ZopfliPNGOptions* png_options = 51 | static_cast(settings->custom_context); 52 | unsigned char bp = 0; 53 | ZopfliOptions options; 54 | ZopfliInitOptions(&options); 55 | 56 | options.verbose = png_options->verbose; 57 | options.numiterations = insize < 200000 58 | ? png_options->num_iterations : png_options->num_iterations_large; 59 | 60 | ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize); 61 | 62 | return 0; // OK 63 | } 64 | 65 | // Returns 32-bit integer value for RGBA color. 66 | static unsigned ColorIndex(const unsigned char* color) { 67 | return color[0] + 256u * color[1] + 65536u * color[2] + 16777216u * color[3]; 68 | } 69 | 70 | // Counts amount of colors in the image, up to 257. If transparent_counts_as_one 71 | // is enabled, any color with alpha channel 0 is treated as a single color with 72 | // index 0. 73 | void CountColors(std::set* unique, 74 | const unsigned char* image, unsigned w, unsigned h, 75 | bool transparent_counts_as_one) { 76 | unique->clear(); 77 | for (size_t i = 0; i < w * h; i++) { 78 | unsigned index = ColorIndex(&image[i * 4]); 79 | if (transparent_counts_as_one && image[i * 4 + 3] == 0) index = 0; 80 | unique->insert(index); 81 | if (unique->size() > 256) break; 82 | } 83 | } 84 | 85 | // Remove RGB information from pixels with alpha=0 86 | void LossyOptimizeTransparent(lodepng::State* inputstate, unsigned char* image, 87 | unsigned w, unsigned h) { 88 | // First check if we want to preserve potential color-key background color, 89 | // or instead use the last encountered RGB value all the time to save bytes. 90 | bool key = true; 91 | for (size_t i = 0; i < w * h; i++) { 92 | if (image[i * 4 + 3] > 0 && image[i * 4 + 3] < 255) { 93 | key = false; 94 | break; 95 | } 96 | } 97 | std::set count; // Color count, up to 257. 98 | CountColors(&count, image, w, h, true); 99 | // If true, means palette is possible so avoid using different RGB values for 100 | // the transparent color. 101 | bool palette = count.size() <= 256; 102 | 103 | // Choose the color key or first initial background color. 104 | int r = 0, g = 0, b = 0; 105 | if (key || palette) { 106 | for (size_t i = 0; i < w * h; i++) { 107 | if (image[i * 4 + 3] == 0) { 108 | // Use RGB value of first encountered transparent pixel. This can be 109 | // used as a valid color key, or in case of palette ensures a color 110 | // existing in the input image palette is used. 111 | r = image[i * 4 + 0]; 112 | g = image[i * 4 + 1]; 113 | b = image[i * 4 + 2]; 114 | break; 115 | } 116 | } 117 | } 118 | 119 | for (size_t i = 0; i < w * h; i++) { 120 | // if alpha is 0, alter the RGB value to a possibly more efficient one. 121 | if (image[i * 4 + 3] == 0) { 122 | image[i * 4 + 0] = r; 123 | image[i * 4 + 1] = g; 124 | image[i * 4 + 2] = b; 125 | } else { 126 | if (!key && !palette) { 127 | // Use the last encountered RGB value if no key or palette is used: that 128 | // way more values can be 0 thanks to the PNG filter types. 129 | r = image[i * 4 + 0]; 130 | g = image[i * 4 + 1]; 131 | b = image[i * 4 + 2]; 132 | } 133 | } 134 | } 135 | 136 | // If there are now less colors, update palette of input image to match this. 137 | if (palette && inputstate->info_png.color.palettesize > 0) { 138 | CountColors(&count, image, w, h, false); 139 | if (count.size() < inputstate->info_png.color.palettesize) { 140 | std::vector palette_out; 141 | unsigned char* palette_in = inputstate->info_png.color.palette; 142 | for (size_t i = 0; i < inputstate->info_png.color.palettesize; i++) { 143 | if (count.count(ColorIndex(&palette_in[i * 4])) != 0) { 144 | palette_out.push_back(palette_in[i * 4 + 0]); 145 | palette_out.push_back(palette_in[i * 4 + 1]); 146 | palette_out.push_back(palette_in[i * 4 + 2]); 147 | palette_out.push_back(palette_in[i * 4 + 3]); 148 | } 149 | } 150 | inputstate->info_png.color.palettesize = palette_out.size() / 4; 151 | for (size_t i = 0; i < palette_out.size(); i++) { 152 | palette_in[i] = palette_out[i]; 153 | } 154 | } 155 | } 156 | } 157 | 158 | // Tries to optimize given a single PNG filter strategy. 159 | // Returns 0 if ok, other value for error 160 | unsigned TryOptimize( 161 | const std::vector& image, unsigned w, unsigned h, 162 | const lodepng::State& inputstate, bool bit16, bool keep_colortype, 163 | const std::vector& origfile, 164 | ZopfliPNGFilterStrategy filterstrategy, 165 | bool use_zopfli, int windowsize, const ZopfliPNGOptions* png_options, 166 | std::vector* out) { 167 | unsigned error = 0; 168 | 169 | lodepng::State state; 170 | state.encoder.zlibsettings.windowsize = windowsize; 171 | if (use_zopfli && png_options->use_zopfli) { 172 | state.encoder.zlibsettings.custom_deflate = CustomPNGDeflate; 173 | state.encoder.zlibsettings.custom_context = png_options; 174 | } 175 | 176 | if (keep_colortype) { 177 | state.encoder.auto_convert = 0; 178 | lodepng_color_mode_copy(&state.info_png.color, &inputstate.info_png.color); 179 | } 180 | if (inputstate.info_png.color.colortype == LCT_PALETTE) { 181 | // Make it preserve the original palette order 182 | lodepng_color_mode_copy(&state.info_raw, &inputstate.info_png.color); 183 | state.info_raw.colortype = LCT_RGBA; 184 | state.info_raw.bitdepth = 8; 185 | } 186 | if (bit16) { 187 | state.info_raw.bitdepth = 16; 188 | } 189 | 190 | state.encoder.filter_palette_zero = 0; 191 | 192 | std::vector filters; 193 | switch (filterstrategy) { 194 | case kStrategyZero: 195 | state.encoder.filter_strategy = LFS_ZERO; 196 | break; 197 | case kStrategyMinSum: 198 | state.encoder.filter_strategy = LFS_MINSUM; 199 | break; 200 | case kStrategyEntropy: 201 | state.encoder.filter_strategy = LFS_ENTROPY; 202 | break; 203 | case kStrategyBruteForce: 204 | state.encoder.filter_strategy = LFS_BRUTE_FORCE; 205 | break; 206 | case kStrategyOne: 207 | state.encoder.filter_strategy = LFS_ONE; 208 | break; 209 | case kStrategyTwo: 210 | state.encoder.filter_strategy = LFS_TWO; 211 | break; 212 | case kStrategyThree: 213 | state.encoder.filter_strategy = LFS_THREE; 214 | break; 215 | case kStrategyFour: 216 | state.encoder.filter_strategy = LFS_FOUR; 217 | break; 218 | case kStrategyPredefined: 219 | lodepng::getFilterTypes(filters, origfile); 220 | if (filters.size() != h) return 1; // Error getting filters 221 | state.encoder.filter_strategy = LFS_PREDEFINED; 222 | state.encoder.predefined_filters = &filters[0]; 223 | break; 224 | default: 225 | break; 226 | } 227 | 228 | state.encoder.add_id = false; 229 | state.encoder.text_compression = 1; 230 | 231 | error = lodepng::encode(*out, image, w, h, state); 232 | 233 | // For very small output, also try without palette, it may be smaller thanks 234 | // to no palette storage overhead. 235 | if (!error && out->size() < 4096 && !keep_colortype) { 236 | if (lodepng::getPNGHeaderInfo(*out).color.colortype == LCT_PALETTE) { 237 | LodePNGColorStats stats; 238 | lodepng_color_stats_init(&stats); 239 | lodepng_compute_color_stats(&stats, &image[0], w, h, &state.info_raw); 240 | // Too small for tRNS chunk overhead. 241 | if (w * h <= 16 && stats.key) stats.alpha = 1; 242 | state.encoder.auto_convert = 0; 243 | state.info_png.color.colortype = (stats.alpha ? LCT_RGBA : LCT_RGB); 244 | state.info_png.color.bitdepth = 8; 245 | state.info_png.color.key_defined = (stats.key && !stats.alpha); 246 | if (state.info_png.color.key_defined) { 247 | state.info_png.color.key_defined = 1; 248 | state.info_png.color.key_r = (stats.key_r & 255u); 249 | state.info_png.color.key_g = (stats.key_g & 255u); 250 | state.info_png.color.key_b = (stats.key_b & 255u); 251 | } 252 | 253 | std::vector out2; 254 | error = lodepng::encode(out2, image, w, h, state); 255 | if (out2.size() < out->size()) out->swap(out2); 256 | } 257 | } 258 | 259 | if (error) { 260 | printf("Encoding error %u: %s\n", error, lodepng_error_text(error)); 261 | return error; 262 | } 263 | 264 | return 0; 265 | } 266 | 267 | // Use fast compression to check which PNG filter strategy gives the smallest 268 | // output. This allows to then do the slow and good compression only on that 269 | // filter type. 270 | unsigned AutoChooseFilterStrategy(const std::vector& image, 271 | unsigned w, unsigned h, 272 | const lodepng::State& inputstate, 273 | bool bit16, bool keep_colortype, 274 | const std::vector& origfile, 275 | int numstrategies, 276 | ZopfliPNGFilterStrategy* strategies, 277 | bool* enable) { 278 | std::vector out; 279 | size_t bestsize = 0; 280 | int bestfilter = 0; 281 | 282 | // A large window size should still be used to do the quick compression to 283 | // try out filter strategies: which filter strategy is the best depends 284 | // largely on the window size, the closer to the actual used window size the 285 | // better. 286 | int windowsize = 8192; 287 | 288 | for (int i = 0; i < numstrategies; i++) { 289 | out.clear(); 290 | unsigned error = TryOptimize(image, w, h, inputstate, bit16, keep_colortype, 291 | origfile, strategies[i], false, windowsize, 0, 292 | &out); 293 | if (error) return error; 294 | if (bestsize == 0 || out.size() < bestsize) { 295 | bestsize = out.size(); 296 | bestfilter = i; 297 | } 298 | } 299 | 300 | for (int i = 0; i < numstrategies; i++) { 301 | enable[i] = (i == bestfilter); 302 | } 303 | 304 | return 0; /* OK */ 305 | } 306 | 307 | // Outputs the intersection of keepnames and non-essential chunks which are in 308 | // the PNG image. 309 | void ChunksToKeep(const std::vector& origpng, 310 | const std::vector& keepnames, 311 | std::set* result) { 312 | std::vector names[3]; 313 | std::vector > chunks[3]; 314 | 315 | lodepng::getChunks(names, chunks, origpng); 316 | 317 | for (size_t i = 0; i < 3; i++) { 318 | for (size_t j = 0; j < names[i].size(); j++) { 319 | for (size_t k = 0; k < keepnames.size(); k++) { 320 | if (keepnames[k] == names[i][j]) { 321 | result->insert(names[i][j]); 322 | } 323 | } 324 | } 325 | } 326 | } 327 | 328 | // Keeps chunks with given names from the original png by literally copying them 329 | // into the new png 330 | void KeepChunks(const std::vector& origpng, 331 | const std::vector& keepnames, 332 | std::vector* png) { 333 | std::vector names[3]; 334 | std::vector > chunks[3]; 335 | 336 | lodepng::getChunks(names, chunks, origpng); 337 | std::vector > keepchunks[3]; 338 | 339 | // There are 3 distinct locations in a PNG file for chunks: between IHDR and 340 | // PLTE, between PLTE and IDAT, and between IDAT and IEND. Keep each chunk at 341 | // its corresponding location in the new PNG. 342 | for (size_t i = 0; i < 3; i++) { 343 | for (size_t j = 0; j < names[i].size(); j++) { 344 | for (size_t k = 0; k < keepnames.size(); k++) { 345 | if (keepnames[k] == names[i][j]) { 346 | keepchunks[i].push_back(chunks[i][j]); 347 | } 348 | } 349 | } 350 | } 351 | 352 | lodepng::insertChunks(*png, keepchunks); 353 | } 354 | 355 | int ZopfliPNGOptimize(const std::vector& origpng, 356 | const ZopfliPNGOptions& png_options, 357 | bool verbose, 358 | std::vector* resultpng) { 359 | // Use the largest possible deflate window size 360 | int windowsize = 32768; 361 | 362 | ZopfliPNGFilterStrategy filterstrategies[kNumFilterStrategies] = { 363 | kStrategyZero, kStrategyOne, kStrategyTwo, kStrategyThree, kStrategyFour, 364 | kStrategyMinSum, kStrategyEntropy, kStrategyPredefined, kStrategyBruteForce 365 | }; 366 | bool strategy_enable[kNumFilterStrategies] = { 367 | false, false, false, false, false, false, false, false, false 368 | }; 369 | std::string strategy_name[kNumFilterStrategies] = { 370 | "zero", "one", "two", "three", "four", 371 | "minimum sum", "entropy", "predefined", "brute force" 372 | }; 373 | for (size_t i = 0; i < png_options.filter_strategies.size(); i++) { 374 | strategy_enable[png_options.filter_strategies[i]] = true; 375 | } 376 | 377 | std::vector image; 378 | unsigned w, h; 379 | unsigned error; 380 | lodepng::State inputstate; 381 | error = lodepng::decode(image, w, h, inputstate, origpng); 382 | 383 | bool keep_colortype = png_options.keep_colortype; 384 | 385 | if (!png_options.keepchunks.empty()) { 386 | // If the user wants to keep the non-essential chunks bKGD or sBIT, the 387 | // input color type has to be kept since the chunks format depend on it. 388 | // This may severely hurt compression if it is not an ideal color type. 389 | // Ideally these chunks should not be kept for web images. Handling of bKGD 390 | // chunks could be improved by changing its color type but not done yet due 391 | // to its additional complexity, for sBIT such improvement is usually not 392 | // possible. 393 | std::set keepchunks; 394 | ChunksToKeep(origpng, png_options.keepchunks, &keepchunks); 395 | if (keepchunks.count("bKGD") || keepchunks.count("sBIT")) { 396 | if (!keep_colortype && verbose) { 397 | printf("Forced to keep original color type due to keeping bKGD or sBIT" 398 | " chunk.\n"); 399 | } 400 | keep_colortype = true; 401 | } 402 | } 403 | 404 | if (error) { 405 | if (verbose) { 406 | if (error == 1) { 407 | printf("Decoding error\n"); 408 | } else { 409 | printf("Decoding error %u: %s\n", error, lodepng_error_text(error)); 410 | } 411 | } 412 | return error; 413 | } 414 | 415 | bool bit16 = false; // Using 16-bit per channel raw image 416 | if (inputstate.info_png.color.bitdepth == 16 && 417 | (keep_colortype || !png_options.lossy_8bit)) { 418 | // Decode as 16-bit 419 | image.clear(); 420 | error = lodepng::decode(image, w, h, origpng, LCT_RGBA, 16); 421 | bit16 = true; 422 | } 423 | 424 | if (!error) { 425 | // If lossy_transparent, remove RGB information from pixels with alpha=0 426 | if (png_options.lossy_transparent && !bit16) { 427 | LossyOptimizeTransparent(&inputstate, &image[0], w, h); 428 | } 429 | 430 | if (png_options.auto_filter_strategy) { 431 | error = AutoChooseFilterStrategy(image, w, h, inputstate, bit16, 432 | keep_colortype, origpng, 433 | /* Don't try brute force */ 434 | kNumFilterStrategies - 1, 435 | filterstrategies, strategy_enable); 436 | } 437 | } 438 | 439 | if (!error) { 440 | size_t bestsize = 0; 441 | 442 | for (int i = 0; i < kNumFilterStrategies; i++) { 443 | if (!strategy_enable[i]) continue; 444 | 445 | std::vector temp; 446 | error = TryOptimize(image, w, h, inputstate, bit16, keep_colortype, 447 | origpng, filterstrategies[i], true /* use_zopfli */, 448 | windowsize, &png_options, &temp); 449 | if (!error) { 450 | if (verbose) { 451 | printf("Filter strategy %s: %d bytes\n", 452 | strategy_name[i].c_str(), (int) temp.size()); 453 | } 454 | if (bestsize == 0 || temp.size() < bestsize) { 455 | bestsize = temp.size(); 456 | (*resultpng).swap(temp); // Store best result so far in the output. 457 | } 458 | } 459 | } 460 | 461 | if (!png_options.keepchunks.empty()) { 462 | KeepChunks(origpng, png_options.keepchunks, resultpng); 463 | } 464 | } 465 | 466 | return error; 467 | } 468 | 469 | extern "C" void CZopfliPNGSetDefaults(CZopfliPNGOptions* png_options) { 470 | 471 | memset(png_options, 0, sizeof(*png_options)); 472 | // Constructor sets the defaults 473 | ZopfliPNGOptions opts; 474 | 475 | png_options->lossy_transparent = opts.lossy_transparent; 476 | png_options->lossy_8bit = opts.lossy_8bit; 477 | png_options->auto_filter_strategy = opts.auto_filter_strategy; 478 | png_options->use_zopfli = opts.use_zopfli; 479 | png_options->num_iterations = opts.num_iterations; 480 | png_options->num_iterations_large = opts.num_iterations_large; 481 | png_options->block_split_strategy = opts.block_split_strategy; 482 | } 483 | 484 | extern "C" int CZopfliPNGOptimize(const unsigned char* origpng, 485 | const size_t origpng_size, 486 | const CZopfliPNGOptions* png_options, 487 | int verbose, 488 | unsigned char** resultpng, 489 | size_t* resultpng_size) { 490 | ZopfliPNGOptions opts; 491 | 492 | // Copy over to the C++-style struct 493 | opts.lossy_transparent = !!png_options->lossy_transparent; 494 | opts.lossy_8bit = !!png_options->lossy_8bit; 495 | opts.auto_filter_strategy = !!png_options->auto_filter_strategy; 496 | opts.use_zopfli = !!png_options->use_zopfli; 497 | opts.num_iterations = png_options->num_iterations; 498 | opts.num_iterations_large = png_options->num_iterations_large; 499 | opts.block_split_strategy = png_options->block_split_strategy; 500 | 501 | for (int i = 0; i < png_options->num_filter_strategies; i++) { 502 | opts.filter_strategies.push_back(png_options->filter_strategies[i]); 503 | } 504 | 505 | for (int i = 0; i < png_options->num_keepchunks; i++) { 506 | opts.keepchunks.push_back(png_options->keepchunks[i]); 507 | } 508 | 509 | const std::vector origpng_cc(origpng, origpng + origpng_size); 510 | std::vector resultpng_cc; 511 | 512 | int ret = ZopfliPNGOptimize(origpng_cc, opts, !!verbose, &resultpng_cc); 513 | if (ret) { 514 | return ret; 515 | } 516 | 517 | *resultpng_size = resultpng_cc.size(); 518 | *resultpng = (unsigned char*) malloc(resultpng_cc.size()); 519 | if (!(*resultpng)) { 520 | return ENOMEM; 521 | } 522 | 523 | memcpy(*resultpng, 524 | reinterpret_cast(&resultpng_cc[0]), 525 | resultpng_cc.size()); 526 | 527 | return 0; 528 | } 529 | -------------------------------------------------------------------------------- /src/zopflipng/zopflipng_lib.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: lode.vandevenne@gmail.com (Lode Vandevenne) 16 | // Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 17 | 18 | // Library to recompress and optimize PNG images. Uses Zopfli as the compression 19 | // backend, chooses optimal PNG color model, and tries out several PNG filter 20 | // strategies. 21 | 22 | #ifndef ZOPFLIPNG_LIB_H_ 23 | #define ZOPFLIPNG_LIB_H_ 24 | 25 | #ifdef __cplusplus 26 | 27 | #include 28 | #include 29 | 30 | extern "C" { 31 | 32 | #endif 33 | 34 | #include 35 | 36 | enum ZopfliPNGFilterStrategy { 37 | kStrategyZero = 0, 38 | kStrategyOne = 1, 39 | kStrategyTwo = 2, 40 | kStrategyThree = 3, 41 | kStrategyFour = 4, 42 | kStrategyMinSum, 43 | kStrategyEntropy, 44 | kStrategyPredefined, 45 | kStrategyBruteForce, 46 | kNumFilterStrategies /* Not a strategy but used for the size of this enum */ 47 | }; 48 | 49 | typedef struct CZopfliPNGOptions { 50 | int lossy_transparent; 51 | int lossy_8bit; 52 | 53 | enum ZopfliPNGFilterStrategy* filter_strategies; 54 | // How many strategies to try. 55 | int num_filter_strategies; 56 | 57 | int auto_filter_strategy; 58 | 59 | char** keepchunks; 60 | // How many entries in keepchunks. 61 | int num_keepchunks; 62 | 63 | int use_zopfli; 64 | 65 | int num_iterations; 66 | 67 | int num_iterations_large; 68 | 69 | int block_split_strategy; 70 | } CZopfliPNGOptions; 71 | 72 | // Sets the default options 73 | // Does not allocate or set keepchunks or filter_strategies 74 | void CZopfliPNGSetDefaults(CZopfliPNGOptions *png_options); 75 | 76 | // Returns 0 on success, error code otherwise 77 | // The caller must free resultpng after use 78 | int CZopfliPNGOptimize(const unsigned char* origpng, 79 | const size_t origpng_size, 80 | const CZopfliPNGOptions* png_options, 81 | int verbose, 82 | unsigned char** resultpng, 83 | size_t* resultpng_size); 84 | 85 | #ifdef __cplusplus 86 | } // extern "C" 87 | #endif 88 | 89 | // C++ API 90 | #ifdef __cplusplus 91 | 92 | struct ZopfliPNGOptions { 93 | ZopfliPNGOptions(); 94 | 95 | bool verbose; 96 | 97 | // Allow altering hidden colors of fully transparent pixels 98 | bool lossy_transparent; 99 | // Convert 16-bit per channel images to 8-bit per channel 100 | bool lossy_8bit; 101 | 102 | // Filter strategies to try 103 | std::vector filter_strategies; 104 | 105 | // Automatically choose filter strategy using less good compression 106 | bool auto_filter_strategy; 107 | 108 | // Keep original color type (RGB, RGBA, gray, gray+alpha or palette) and bit 109 | // depth of the PNG. 110 | // This results in a loss of compression opportunities, e.g. it will no 111 | // longer convert a 4-channel RGBA image to 2-channel gray+alpha if the image 112 | // only had translucent gray pixels. 113 | // May be useful if a device does not support decoding PNGs of a particular 114 | // color type. 115 | // Default value: false. 116 | bool keep_colortype; 117 | 118 | // PNG chunks to keep 119 | // chunks to literally copy over from the original PNG to the resulting one 120 | std::vector keepchunks; 121 | 122 | // Use Zopfli deflate compression 123 | bool use_zopfli; 124 | 125 | // Zopfli number of iterations 126 | int num_iterations; 127 | 128 | // Zopfli number of iterations on large images 129 | int num_iterations_large; 130 | 131 | // Unused, left for backwards compatiblity. 132 | int block_split_strategy; 133 | }; 134 | 135 | // Returns 0 on success, error code otherwise. 136 | // If verbose is true, it will print some info while working. 137 | int ZopfliPNGOptimize(const std::vector& origpng, 138 | const ZopfliPNGOptions& png_options, 139 | bool verbose, 140 | std::vector* resultpng); 141 | 142 | #endif // __cplusplus 143 | 144 | #endif // ZOPFLIPNG_LIB_H_ 145 | --------------------------------------------------------------------------------