├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── FLIF-CLA-template.txt ├── LICENSE ├── LICENSE_Apache2 ├── LICENSE_GPL ├── LICENSE_LGPL ├── Makefile ├── README.md ├── build └── MSVC │ ├── .gitignore │ ├── Makefile │ ├── dl_make_vs.bat │ ├── dl_make_vs_x64.bat │ ├── getopt │ ├── getopt.c │ └── getopt.h │ └── make_vs.bat ├── configure.py ├── doc ├── flif.1 ├── flif.bash-completion ├── flif.magic ├── flif.pdf ├── metadata └── produce_documentation ├── extern ├── lodepng.cpp ├── lodepng.h ├── stb_image.h └── stb_image_write.h ├── raw-tools ├── raw2flif ├── raw2rggb ├── raw2rggb.bat └── sony_arw │ ├── README │ ├── arw_compress.sh │ ├── arw_decompress.sh │ ├── arw_encode.c │ └── dcraw.c ├── src ├── CMakeLists.txt ├── Makefile ├── common.cpp ├── common.hpp ├── compiler-specific.hpp ├── config.h ├── fileio.hpp ├── flif-dec.cpp ├── flif-dec.hpp ├── flif-enc.cpp ├── flif-enc.hpp ├── flif-mime.xml ├── flif-pixbuf-loader.c ├── flif.cpp ├── flif_config.h ├── image │ ├── color_range.cpp │ ├── color_range.hpp │ ├── crc32k.cpp │ ├── crc32k.hpp │ ├── image-metadata.cpp │ ├── image-metadata.hpp │ ├── image-pam.cpp │ ├── image-pam.hpp │ ├── image-png-metadata.hpp │ ├── image-png.cpp │ ├── image-png.hpp │ ├── image-pnm.cpp │ ├── image-pnm.hpp │ ├── image-rggb.cpp │ ├── image-rggb.hpp │ ├── image.cpp │ └── image.hpp ├── io.cpp ├── io.hpp ├── library │ ├── flif-interface-private.hpp │ ├── flif-interface-private_common.hpp │ ├── flif-interface-private_dec.hpp │ ├── flif-interface-private_enc.hpp │ ├── flif-interface.cpp │ ├── flif-interface_common.cpp │ ├── flif-interface_dec.cpp │ ├── flif-interface_enc.cpp │ ├── flif.h │ ├── flif_common.h │ ├── flif_dec.h │ └── flif_enc.h ├── maniac │ ├── bit.cpp │ ├── bit.hpp │ ├── chance.cpp │ ├── chance.hpp │ ├── compound.hpp │ ├── compound_enc.hpp │ ├── rac.hpp │ ├── rac_enc.hpp │ ├── symbol.cpp │ ├── symbol.hpp │ ├── symbol_enc.hpp │ └── util.hpp ├── transform │ ├── bounds.hpp │ ├── colorbuckets.hpp │ ├── factory.cpp │ ├── factory.hpp │ ├── framecombine.hpp │ ├── framedup.hpp │ ├── frameshape.hpp │ ├── palette.hpp │ ├── palette_A.hpp │ ├── palette_C.hpp │ ├── permute.hpp │ ├── transform.hpp │ ├── yc1c2.hpp │ └── ycocg.hpp └── viewflif.c ├── testFiles └── sig05-014.png └── tools ├── 2_webp_ll.png ├── apng2flif ├── bouncing_ball_frames ├── bouncing-ball-frame01.png ├── bouncing-ball-frame02.png ├── bouncing-ball-frame03.png ├── bouncing-ball-frame04.png ├── bouncing-ball-frame05.png ├── bouncing-ball-frame06.png ├── bouncing-ball-frame07.png ├── bouncing-ball-frame08.png ├── bouncing-ball-frame09.png ├── bouncing-ball-frame10.png ├── bouncing-ball-frame11.png ├── bouncing-ball-frame12.png ├── bouncing-ball-frame13.png ├── bouncing-ball-frame14.png ├── bouncing-ball-frame15.png ├── bouncing-ball-frame16.png ├── bouncing-ball-frame17.png ├── bouncing-ball-frame18.png ├── bouncing-ball-frame19.png └── bouncing-ball-frame20.png ├── build-libpng.sh ├── endless_war.gif ├── gif2flif ├── kodim01.png ├── sizes.sh ├── test-lossy.sh ├── test-metadata.sh ├── test-roundtrip.sh ├── test-roundtrip_anim.sh ├── test-roundtrip_anim_framedir.sh └── test.c /.gitignore: -------------------------------------------------------------------------------- 1 | # build system 2 | obj/ 3 | *.pyc 4 | *.pyo 5 | *.o 6 | *.cpp.d 7 | *.c.d 8 | *.h.d 9 | *.gch.d 10 | *.gch 11 | .ninja* 12 | build.ninja 13 | 14 | tags 15 | 16 | # binarys 17 | src/flif 18 | src/flif.asan 19 | src/flif.dbg 20 | src/flif.prof 21 | src/flif.stats 22 | src/libflif.dbg.so 23 | src/libflif.so 24 | src/libflif.dylib 25 | src/libflif.0.dylib 26 | 27 | src/test-interface 28 | src/viewflif 29 | src/dflif 30 | 31 | /*.png 32 | *.xcworkspace/* 33 | *.xcworkspace 34 | *.xcodeproj 35 | 36 | *.so.0 37 | *.so 38 | */*dSYM/* 39 | 40 | flif.osx 41 | 42 | *.swp 43 | 44 | #MSVC 45 | *.exe 46 | *.obj 47 | *.pdb 48 | *.ilk 49 | build/tmp-test/ 50 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | sudo: true 8 | dist: trusty 9 | 10 | env: 11 | - BUILDTYPE=GNUMAKE 12 | 13 | addons: 14 | apt: 15 | packages: 16 | - libsdl2-dev 17 | 18 | before_install: 19 | - sudo apt-get install build-essential imagemagick libimage-exiftool-perl 20 | # workaround clang not system wide, fail on sudo make install for adms 21 | - export CC=`which $CC` 22 | 23 | install: sudo ./tools/build-libpng.sh 24 | 25 | script: 26 | - if [[ "$BUILDTYPE" == "GNUMAKE" ]]; then cd src && make && make test ; fi 27 | - if [[ "$BUILDTYPE" == "ASAN" ]]; then mkdir build_cmake && cd build_cmake && cmake ../src -DMAKE_BUILD_TYPE=Release -DUSE_ASAN=ON && make && make test ; fi 28 | - if [[ "$BUILDTYPE" == "CMAKE" ]]; then mkdir build_cmake && cd build_cmake && cmake ../src -DMAKE_BUILD_TYPE=Release && make && make test ; fi 29 | 30 | notifications: 31 | webhooks: 32 | urls: 33 | - https://webhooks.gitter.im/e/d7137bab0c1e0a1d1089 34 | on_success: change # options: [always|never|change] default: always 35 | on_failure: always # options: [always|never|change] default: always 36 | on_start: never # options: [always|never|change] default: always 37 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | Thanks for you interest in contributing to FLIF! 3 | 4 | Do you want to contribute, but you do not know where to start? 5 | Take a look here: 6 | - The open issues in the main FLIF repository: https://github.com/FLIF-hub/FLIF/issues (mostly C++ / C) 7 | - poly-flif is a browser poly-fill for FLIF: https://github.com/UprootLabs/poly-flif (JS / emscripten) 8 | - UGUI: FLIF is a graphical user interface wrapper for the command-line utility: https://github.com/FLIF-hub/UGUI_FLIF (HTML / CSS / JS) 9 | - http://flif.info is the official FLIF website. It is hosted on github, and you're invited to contribute to it! https://github.com/FLIF-hub/FLIF-hub.github.io (Jekyll / HTML / CSS) 10 | - Benchmarks are useful not just to compare FLIF to other formats, but also to evaluate modifications in FLIF itself. Test images and benchmark scripts are collected here: https://github.com/FLIF-hub/benchmarks (Shell scripts / Gnuplot) 11 | - Documentation related to FLIF (including, eventually, the detailed format specification) is here: https://github.com/FLIF-hub/FLIF-doc (LaTeX) 12 | 13 | FLIF is currently licensed under the GNU LGPL v3+. The decoder library `libflif_dec` is licensed under the Apache 2.0 license. 14 | When the project is more mature, we (Jon Sneyers and Pieter Wuille, the primary/initial authors of FLIF) 15 | may want to release it under an even more permissive or a different Free Software license should that become desirable. 16 | 17 | For this reason, we ask contributors (i.e. authors of a pull request) to agree to the Contributor License Agreement (CLA) you can 18 | find in the file FLIF-CLA-template.txt in this repository. That allows us to relicense FLIF, including your contributions, if needed. 19 | 20 | More precisely, the set of _potential_ outbound licenses that can be considered, 21 | are the GPL-Compatible Free Software Licenses as listed on this page: 22 | https://gnu.org/licenses/license-list.html#GPLCompatibleLicenses 23 | 24 | Please add your signed CLA to http://github.com/jonsneyers/FLIF-CLAs/ 25 | (you can find a template in FLIF-CLA-template.txt) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | This is the reference implementation of FLIF, copyright (C) 2016 Jon Sneyers and Pieter Wuille. 3 | 4 | It is released under the terms of the GNU Lesser General Public License version 3 or later (LGPLv3+). 5 | The license terms can be found in the files LICENSE_GPL and LICENSE_LGPL. 6 | 7 | The code of the FLIF decoder (not the encoder!) is released under the terms of the Apache 2.0 license. 8 | The library libflif_dec is available under these terms. 9 | A copy of the Apache 2.0 license is available in the file LICENSE_Apache2. -------------------------------------------------------------------------------- /LICENSE_LGPL: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd src && $(MAKE) 3 | 4 | flif: 5 | cd src && $(MAKE) flif 6 | 7 | install: 8 | cd src && $(MAKE) install 9 | 10 | install-dev: 11 | cd src && $(MAKE) install-dev 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | **FLIF development has stopped since FLIF is superseded by FUIF and then again by [JPEG XL](https://jpeg.org/jpegxl/), which is based on a combination of [Pik](https://github.com/google/pik) and [FUIF](https://github.com/cloudinary/fuif). 4 | A royalty-free and open source reference implementation of JPEG XL is available on [GitHub](https://github.com/libjxl/libjxl). For more information, see [JPEG XL community page](https://jpegxl.info) or visit the [JPEG XL Discord server](https://discord.gg/DqkQgDRTFu).** 5 | 6 | --- 7 | 8 | # FLIF: Free Lossless Image Format 9 | 10 | [![Build Status](https://travis-ci.org/FLIF-hub/FLIF.svg?branch=master)](https://travis-ci.org/FLIF-hub/FLIF) 11 | [![Join the chat at https://gitter.im/jonsneyers/FLIF](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jonsneyers/FLIF?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 12 | [![flif](https://snapcraft.io//flif/badge.svg)](https://snapcraft.io/flif) 13 | 14 | FLIF is a lossless image format based on MANIAC compression. MANIAC (Meta-Adaptive Near-zero Integer Arithmetic Coding) 15 | is a variant of CABAC (context-adaptive binary arithmetic coding), where the contexts are nodes of decision trees 16 | which are dynamically learned at encode time. 17 | 18 | FLIF outperforms PNG, FFV1, lossless WebP, lossless BPG and lossless JPEG2000 in terms of compression ratio. 19 | 20 | Moreover, FLIF supports a form of progressive interlacing (essentially a generalization/improvement of PNG's Adam7) 21 | which means that any prefix (e.g. partial download) of a compressed file can be used as a reasonable lossy encoding of the entire image. 22 | 23 | For more information on FLIF, visit https://flif.info 24 | 25 | * * * 26 | 27 | ## License 28 | 29 | FLIF is copylefted free/libre software: you can redistribute it and/or modify it, provided that you share back. 30 | 31 | The reference implementation of FLIF is released under the terms of the GNU Lesser General Public License version 3 or later (LGPLv3+). 32 | 33 | The decoder library `libflif_dec` is released under a weaker, non-copyleft free software license: the Apache 2.0 license. 34 | 35 | The example application `viewflif` illustrates how to use the decode library. 36 | The example code in `viewflif.c` is in the public domain (Creative Commons CC0 1.0 Universal). 37 | 38 | * * * 39 | 40 | ## Build Instructions 41 | 42 | ### GNU/Linux 43 | 44 | #### Install the dependencies 45 | 46 | On Debian: 47 | 48 | * for the encoder/decoder: `sudo apt-get install libpng-dev` 49 | * for the viewer: `sudo apt-get install libsdl2-dev` 50 | 51 | On Fedora: 52 | 53 | * for the encoder/decoder: `sudo dnf install libpng-devel` 54 | * for the viewer: `sudo dnf install SDL-devel` 55 | 56 | On Ubuntu: 57 | 58 | * for the encoder/decoder: `sudo apt-get install libpng-dev make pkg-config` 59 | * for the viewer: `sudo apt-get install libsdl2-dev` 60 | 61 | #### Compile 62 | 63 | * Navigate to the FLIF/src directory and run `make` to compile everything, or 64 | * `make flif` to build just the `flif` command line tool 65 | * `make libflif.so` to build the LGPL'ed shared library 66 | * `make libflif_dec.so` to build the Apache licensed decode-only shared library 67 | * `make viewflif` to build the example viewer (it depends on the decode library) 68 | 69 | #### Install 70 | 71 | * `sudo make install` if you want to install it globally 72 | 73 | ### Windows 74 | 75 | * Install Visual Studio 76 | ([VS Community 2015](https://www.visualstudio.com/en-us/products/free-developer-offers-vs.aspx) 77 | is free for open source projects) 78 | * Open the `build\MSVC` folder and double-click the `dl_make_vs.bat` file. 79 | This will download required libraries and run `nmake` to build `flif.exe`. 80 | Then, run in the command line: 81 | * `nmake libflif.dll` to build the shared library 82 | * `nmake viewflif.exe` to build the example viewer 83 | 84 | ### OS X 85 | 86 | * Install [homebrew](http://brew.sh) 87 | * Install the dependencies: `brew install pkg-config libpng sdl2` 88 | * Run `make` in the FLIF/src directory 89 | 90 | 91 | * * * 92 | 93 | ## Pre-Built Binaries 94 | 95 | These will be available on the Release page 96 | 97 | * https://github.com/FLIF-hub/FLIF/releases 98 | 99 | Or, you can get the Snap package: 100 | 101 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/flif) 102 | 103 | * * * 104 | 105 | ## Related Projects 106 | 107 | * **[Poly FLIF](https://github.com/UprootLabs/poly-flif)** - A javascript polyfill that allows you to use FLIF files in the browser. ([Demo](https://uprootlabs.github.io/poly-flif)) 108 | * **[UGUI: FLIF](http://flif.info/UGUI_FLIF)** - A GUI that allows you to convert and view FLIF files. 109 | * **[Ivy, the Taggable Image Viewer](https://github.com/lehitoskin/ivy)** – An image viewer that supports FLIF via [riff](https://github.com/lehitoskin/riff) 110 | * **[flifcrush](https://github.com/FLIF-hub/flifcrush)** - A brute-force FLIF optimizer. 111 | * **[libflif.js](https://github.com/saschanaz/libflif.js/)** – A javascript FLIF encoder and decoder. ([Demo](https://saschanaz.github.io/libflif.js/)) 112 | * **[flif.rs](https://github.com/dgriffen/flif.rs)** – A work-in-progress implementation of FLIF in Rust. 113 | * **[FLIF Windows Codec](https://github.com/peirick/FlifWICCodec)** – A plugin that allows you to decode and encode FLIF files in Windows aplications using the Windows Imaging Component (WIC) API. That allows e.g., to see the files in Windows PhotoViewer and Windows Explorer. 114 | * **[FLIF Windows Plugin](https://github.com/fherzog2/flif_windows_plugin)** – This plugin enables decoding of FLIF images in applications which use the Windows Imaging Component API. In this way, FLIF images can be viewed in Windows Explorer like other common image formats. 115 | * **[qt-flif-plugin](https://github.com/spillerrec/qt-flif-plugin)** – Enables Qt4 and Qt5 applications to load images in the FLIF image format. 116 | * **[go-flif](https://github.com/chrisfelesoid/go-flif)** – Go FLIF Library Bindings. 117 | * **[Phew](https://sveinbjorn.org/phew)** - Image viewer for macOS with QuickLook plugin 118 | * **[SDWebImageFLIFCoder](https://github.com/SDWebImage/SDWebImage)** - A popular image loading framework [SDWebImage](https://github.com/SDWebImage/SDWebImage)'s coder plugin, supports iOS/macOS/tvOS/watchOS all Apple platforms. 119 | * **[libflif-Xcode](https://github.com/SDWebImage/libflif-Xcode)** - Xcode project to build libflif on iOS/macOS/tvOS/watchOS all Apple platforms. 120 | * **[flif-wasm](https://github.com/saschanaz/flif-wasm)** - Node.js-ported FLIF command-line tool. 121 | * **[node-flif](https://github.com/FLIF-hub/node-flif)** - A Node.JS wrapper that allows you to use JavaScript to interact with the CLI. 122 | * **[SimplEx FLIF](https://github.com/Atrus09/SimplEx-FLIF)** - A simple and extensive GUI intermediary for the native executables. 123 | * **[WinFLIF](https://github.com/Zaczero/WinFLIF)** - Small Windows desktop app for converting to/from FLIF/PNG stills. 124 | * **[imageio-FLIF](https://codeberg.org/monilophyta/imageio-flif)** - An [Imageio](https://imageio.github.io) (Python) plugin for reading and writing FLIF images and animations 125 | -------------------------------------------------------------------------------- /build/MSVC/.gitignore: -------------------------------------------------------------------------------- 1 | */ 2 | 3 | *.zip 4 | *.dll 5 | *.flif 6 | *.png 7 | 8 | !getopt/ 9 | 10 | !include/ 11 | include/* 12 | 13 | -------------------------------------------------------------------------------- /build/MSVC/Makefile: -------------------------------------------------------------------------------- 1 | lpngdir = libpng-libpng-1.6.20-master-signed 2 | zlibdir = zlib-1.2.8 3 | sdl2dir = SDL2-2.0.3 4 | 5 | Incdir = include 6 | 7 | !ifndef PLATFORM 8 | PLATFORM=x86 9 | !endif 10 | 11 | Rt = MD 12 | LibDir = $(PLATFORM)_$(Rt) 13 | SrcDir = ..\..\src 14 | ExtDir = ..\..\extern 15 | 16 | !if "$(Rt)" == "MT" || "$(Rt)" == "MD" 17 | CFLAGS = /nologo /WX /EHsc /GL /Ox /Oy /Gy /DNDEBUG /$(Rt) 18 | LDFLAGS= /nologo /LTCG 19 | !elseif "$(Rt)" == "MTd" || "$(Rt)" == "MDd" 20 | CFLAGS = /nologo /WX /EHsc /Zi /DDEBUG /$(Rt) 21 | LDFLAGS= /nologo /DEBUG 22 | !else 23 | !ERROR Rt=[MT|MD|MTd|MDd] 24 | !endif 25 | 26 | OBJDIR = $(LibDir)\Obj 27 | O = $(OBJDIR)\\ 28 | 29 | OBJ1 = $Oflif-dec.obj $Oflif-enc.obj $Oio.obj $Ocommon.obj $Ocolor_range.obj $Ocrc32k.obj $Obit.obj $Ochance.obj $Ofactory.obj $Oimage-metadata.obj $Olodepng.obj 30 | OBJ2 = $Oimage.obj $Oimage-pam.obj $Oimage-png.obj $Oimage-pnm.obj $Oimage-rggb.obj 31 | LIBOBJS = $(OBJ1) 32 | FLIFOBJS = $(OBJ1) $(OBJ2) 33 | 34 | all: flif.exe libflif_dec.dll viewflif.exe test-interface.exe 35 | 36 | flif.exe: $(OBJDIR) $(LibDir)\zlib.lib $(LibDir)\libpng.lib $(FLIFOBJS) 37 | cl $(CFLAGS) /I$(Incdir) /Igetopt $(SrcDir)\flif.cpp getopt\getopt.c /DSTATIC_GETOPT /Fd$O /Fo$O -c 38 | link /out:$(LibDir)\$@ $Oflif.obj $Ogetopt.obj $(FLIFOBJS) $(LibDir)\zlib.lib $(LibDir)\libpng.lib $(LDFLAGS) 39 | copy "$(LibDir)\$@" $@ 40 | 41 | libflif.dll: $(OBJDIR) $(LIBOBJS) 42 | cl $(CFLAGS) $(SrcDir)\library\flif-interface.cpp /DFLIF_BUILD_DLL /Fd$O /Fo$O -c 43 | link /dll /out:"$(LibDir)\$@" $Oflif-interface.obj $(LIBOBJS) $(LDFLAGS) 44 | copy "$(LibDir)\$@" $@ 45 | 46 | libflif_dec.dll: $(OBJDIR) $(LIBOBJS) 47 | cl $(CFLAGS) $(SrcDir)\library\flif-interface_dec.cpp /DFLIF_BUILD_DLL /Fd$O /Fo$O -c 48 | link /dll /out:"$(LibDir)\$@" $Oflif-interface_dec.obj $(LIBOBJS) $(LDFLAGS) 49 | copy "$(LibDir)\$@" $@ 50 | 51 | viewflif.exe: libflif_dec.dll 52 | cl $(CFLAGS) /I$(SrcDir)\ /I$(SrcDir)\library\ /I$(sdl2dir)\include /Tp $(SrcDir)\viewflif.c /DFLIF_USE_DLL /Fd$O /Fo$O -c 53 | link /out:$(LibDir)\$@ $Oviewflif.obj libflif_dec.lib SDL2.lib SDL2main.lib $(LDFLAGS) /SUBSYSTEM:CONSOLE /LIBPATH:$(LibDir) /LIBPATH:$(sdl2dir)\lib\$(PLATFORM)\ 54 | copy "$(LibDir)\$@" $@ 55 | copy $(sdl2dir)\lib\$(PLATFORM)\SDL2.dll SDL2.dll 56 | 57 | test: flif.exe test-interface.exe 58 | if exist output.flif del output.flif 59 | @echo ./flif.exe ../../tools/kodim01.png output.flif 60 | @powershell "Measure-Command{ ./flif.exe ../../tools/kodim01.png output.flif}" 61 | if exist output.png del output.png 62 | flif output.flif output.png 63 | @if exist "viewflif.exe" viewflif.exe output.flif 64 | @if not exist "..\tmp-test\" mkdir ..\tmp-test 65 | if exist "test-interface.exe" test-interface.exe ..\tmp-test\dummy.flif 66 | start output.png 67 | 68 | test-interface.exe: libflif.dll 69 | cl $(CFLAGS) /I$(Incdir) /I$(SrcDir)\ /I$(SrcDir)\library\ ..\..\tools\test.c /DFLIF_USE_DLL /Fd$O /Fo$O -c 70 | link /out:$(LibDir)\$@ $Otest.obj libflif.lib $(LDFLAGS) /LIBPATH:$(LibDir) 71 | copy "$(LibDir)\$@" $@ 72 | 73 | $(OBJDIR): 74 | @if not exist "$(@)/" mkdir "$(@)" 75 | 76 | $(LibDir)\zlib.lib: $(OBJDIR) 77 | @if not exist include mkdir include 78 | cd $(zlibdir) 79 | @nmake -f win32\Makefile.msc clean 80 | nmake -f win32\Makefile.msc zlib.lib CFLAGS="$(CFLAGS) /TC /Fdzlib" ARFLAGS="$(LDFLAGS)" 81 | copy zlib.lib ..\$(LibDir)\\ 82 | copy zlib.h ..\$(Incdir)\\ 83 | copy zconf.h ..\$(Incdir)\\ 84 | cd .. 85 | 86 | $(LibDir)\libpng.lib: $(LibDir)\zlib.lib 87 | @if not exist include mkdir include 88 | cd $(lpngdir) 89 | @nmake -f scripts\Makefile.vcwin32 clean 90 | nmake -f scripts\Makefile.vcwin32 libpng.lib CPPFLAGS="/I..\$(Incdir) " CFLAGS="$(CFLAGS) /TC /D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS" ARFLAGS="$(LDFLAGS)" 91 | copy libpng.lib ..\$(LibDir)\\ 92 | copy png.h ..\$(Incdir)\\ 93 | copy pngconf.h ..\$(Incdir)\\ 94 | copy pnglibconf.h ..\$(Incdir)\\ 95 | cd .. 96 | 97 | {$(SrcDir)\}.cpp{$(O)}.obj: 98 | cl $(CFLAGS) /Fd$O /Fo$O -c $< 99 | {getopt\}.c{$(O)}.obj: 100 | cl $(CFLAGS) /DSTATIC_GETOPT /Fd$O /Fo$O -c $< 101 | {$(SrcDir)\image\}.cpp{$(O)}.obj: 102 | cl $(CFLAGS) /I$(Incdir) /Fd$O /Fo$O -c $< 103 | {$(SrcDir)\maniac\}.cpp{$(O)}.obj: 104 | cl $(CFLAGS) /Fd$O /Fo$O -c $< 105 | {$(SrcDir)\transform\}.cpp{$(O)}.obj: 106 | cl $(CFLAGS) /Fd$O /Fo$O -c $< 107 | {$(ExtDir)\}.cpp{$(O)}.obj: 108 | cl $(CFLAGS) /Fd$O /Fo$O -c $< 109 | 110 | clean: 111 | -del flif.exe 112 | -del test-interface.exe 113 | -del viewflif.exe 114 | -del SDL2.dll 115 | -del libflif.dll 116 | -del libflif_dec.dll 117 | -del output.png 118 | -del output.flif 119 | -rd /s /q ..\tmp-test 120 | -rd /s /q $(LibDir) 121 | -------------------------------------------------------------------------------- /build/MSVC/dl_make_vs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set lpngurl=https://github.com/glennrp/libpng/archive/libpng-1.6.20-master-signed.zip 4 | set lpngzip=libpng-1.6.20-master-signed.zip 5 | set lpngdir=libpng-libpng-1.6.20-master-signed 6 | 7 | set zliburl=https://sourceforge.net/projects/libpng/files/zlib/1.2.8/zlib128.zip/download 8 | set zlibzip=zlib128.zip 9 | set zlibdir=zlib-1.2.8 10 | 11 | set sdl2url=https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip 12 | set sdl2zip=SDL2-devel-2.0.3-VC.zip 13 | set sdl2dir=SDL2-2.0.3 14 | 15 | set vswhereurl=https://github.com/Microsoft/vswhere/releases/download/2.4.1/vswhere.exe 16 | set vswherefile=vswhere.exe 17 | 18 | 19 | cd /d %~dp0 20 | 21 | if not exist "%vswherefile%" ( 22 | echo download %vswherefile% 23 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%vswhereurl%', '%vswherefile%')" 24 | ) 25 | 26 | if not defined VISUALSTUDIOVERSION ( 27 | for /f "usebackq tokens=1* delims=: " %%i in (`%vswherefile% -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop`) do ( 28 | if /i "%%i"=="installationPath" ( 29 | CALL "%%j\VC\Auxiliary\Build\vcvarsall.bat" x86 %1 30 | ) 31 | ) 32 | ) 33 | if not defined VISUALSTUDIOVERSION ( 34 | CALL "%VSAPPIDDIR%..\..\VC\Auxiliary\Build\vcvarsall.bat" x86 %1 35 | ) 36 | if not defined VISUALSTUDIOVERSION ( 37 | CALL "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %1 38 | ) 39 | if not defined VISUALSTUDIOVERSION ( 40 | echo visual studio not detected 41 | goto end 42 | ) 43 | if not defined PLATFORM set PLATFORM=x86 44 | 45 | cd /d %~dp0 46 | 47 | if not exist "%lpngzip%" ( 48 | echo download %lpngzip% 49 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%lpngurl%', '%lpngzip%')" 50 | ) 51 | if not exist "%lpngdir%\\" ( 52 | echo unzip %lpngzip% 53 | PowerShell "(New-Object -ComObject shell.application).NameSpace('%CD%').CopyHere((New-Object -ComObject shell.application).NameSpace('%CD%\%lpngzip%').Items())" 54 | ) 55 | 56 | if not exist "%zlibzip%" ( 57 | echo download %zlibzip% 58 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%zliburl%', '%zlibzip%')" 59 | ) 60 | if not exist "%zlibdir%\\" ( 61 | echo unzip %zlibzip% 62 | PowerShell "$s=New-Object -Com shell.application;$s.NameSpace('%CD%').CopyHere($s.NameSpace('%CD%\%zlibzip%').Items())" 63 | ) 64 | 65 | if not exist "%sdl2zip%" ( 66 | echo download %sdl2zip% 67 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%sdl2url%', '%sdl2zip%')" 68 | ) 69 | if not exist "%sdl2dir%\\" ( 70 | echo unzip %sdl2zip% 71 | PowerShell "$s=New-Object -Com shell.application;$s.NameSpace('%CD%').CopyHere($s.NameSpace('%CD%\%sdl2zip%').Items())" 72 | ) 73 | 74 | nmake Rt=MD 75 | nmake Rt=MD test 76 | rem nmake Rt=MT flif.exe 77 | rem debug MTd|MDd 78 | rem nmake Rt=MDd all 79 | 80 | :end 81 | cmd 82 | -------------------------------------------------------------------------------- /build/MSVC/dl_make_vs_x64.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set lpngurl=https://github.com/glennrp/libpng/archive/libpng-1.6.20-master-signed.zip 4 | set lpngzip=libpng-1.6.20-master-signed.zip 5 | set lpngdir=libpng-libpng-1.6.20-master-signed 6 | 7 | set zliburl=https://sourceforge.net/projects/libpng/files/zlib/1.2.8/zlib128.zip/download 8 | set zlibzip=zlib128.zip 9 | set zlibdir=zlib-1.2.8 10 | 11 | set sdl2url=https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip 12 | set sdl2zip=SDL2-devel-2.0.3-VC.zip 13 | set sdl2dir=SDL2-2.0.3 14 | 15 | set vswhereurl=https://github.com/Microsoft/vswhere/releases/download/2.4.1/vswhere.exe 16 | set vswherefile=vswhere.exe 17 | 18 | 19 | cd /d %~dp0 20 | 21 | if not exist "%vswherefile%" ( 22 | echo download %vswherefile% 23 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%vswhereurl%', '%vswherefile%')" 24 | ) 25 | 26 | if not defined VISUALSTUDIOVERSION ( 27 | for /f "usebackq tokens=1* delims=: " %%i in (`%vswherefile% -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop`) do ( 28 | if /i "%%i"=="installationPath" ( 29 | CALL "%%j\VC\Auxiliary\Build\vcvarsall.bat" amd64 %1 30 | ) 31 | ) 32 | ) 33 | if not defined VISUALSTUDIOVERSION ( 34 | CALL "%VSAPPIDDIR%..\..\VC\Auxiliary\Build\vcvarsall.bat" amd64 %1 35 | ) 36 | if not defined VISUALSTUDIOVERSION ( 37 | CALL "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %1 38 | ) 39 | if not defined VISUALSTUDIOVERSION ( 40 | echo visual studio not detected 41 | goto end 42 | ) 43 | if not defined PLATFORM set PLATFORM=x86 44 | 45 | cd /d %~dp0 46 | 47 | if not exist "%lpngzip%" ( 48 | echo download %lpngzip% 49 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%lpngurl%', '%lpngzip%')" 50 | ) 51 | if not exist "%lpngdir%\\" ( 52 | echo unzip %lpngzip% 53 | PowerShell "(New-Object -ComObject shell.application).NameSpace('%CD%').CopyHere((New-Object -ComObject shell.application).NameSpace('%CD%\%lpngzip%').Items())" 54 | ) 55 | 56 | if not exist "%zlibzip%" ( 57 | echo download %zlibzip% 58 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%zliburl%', '%zlibzip%')" 59 | ) 60 | if not exist "%zlibdir%\\" ( 61 | echo unzip %zlibzip% 62 | PowerShell "$s=New-Object -Com shell.application;$s.NameSpace('%CD%').CopyHere($s.NameSpace('%CD%\%zlibzip%').Items())" 63 | ) 64 | 65 | if not exist "%sdl2zip%" ( 66 | echo download %sdl2zip% 67 | PowerShell "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('%sdl2url%', '%sdl2zip%')" 68 | ) 69 | if not exist "%sdl2dir%\\" ( 70 | echo unzip %sdl2zip% 71 | PowerShell "$s=New-Object -Com shell.application;$s.NameSpace('%CD%').CopyHere($s.NameSpace('%CD%\%sdl2zip%').Items())" 72 | ) 73 | 74 | nmake Rt=MD 75 | nmake Rt=MD test 76 | rem nmake Rt=MT flif.exe 77 | rem debug MTd|MDd 78 | rem nmake Rt=MDd all 79 | 80 | :end 81 | cmd 82 | -------------------------------------------------------------------------------- /build/MSVC/getopt/getopt.h: -------------------------------------------------------------------------------- 1 | /* Getopt for Microsoft C 2 | This code is a modification of the Free Software Foundation, Inc. 3 | Getopt library for parsing command line argument the purpose was 4 | to provide a Microsoft Visual C friendly derivative. This code 5 | provides functionality for both Unicode and Multibyte builds. 6 | 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release 8 | Version: 1.0 9 | Comment: Supports getopt, getopt_long, and getopt_long_only 10 | and POSIXLY_CORRECT environment flag 11 | License: LGPL 12 | 13 | Revisions: 14 | 15 | 02/03/2011 - Ludvik Jerabek - Initial Release 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features 23 | 06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable 24 | 25 | **DISCLAIMER** 26 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 27 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 29 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE 30 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT 31 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY 32 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY 33 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST 34 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON 35 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE 36 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 37 | */ 38 | #ifndef __GETOPT_H_ 39 | #define __GETOPT_H_ 40 | 41 | #ifdef _GETOPT_API 42 | #undef _GETOPT_API 43 | #endif 44 | 45 | #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) 46 | #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" 47 | #elif defined(STATIC_GETOPT) 48 | #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") 49 | #define _GETOPT_API 50 | #elif defined(EXPORTS_GETOPT) 51 | #pragma message("Exporting getopt library") 52 | #define _GETOPT_API __declspec(dllexport) 53 | #else 54 | #pragma message("Importing getopt library") 55 | #define _GETOPT_API __declspec(dllimport) 56 | #endif 57 | 58 | // Change behavior for C\C++ 59 | #ifdef __cplusplus 60 | #define _BEGIN_EXTERN_C extern "C" { 61 | #define _END_EXTERN_C } 62 | #define _GETOPT_THROW throw() 63 | #else 64 | #define _BEGIN_EXTERN_C 65 | #define _END_EXTERN_C 66 | #define _GETOPT_THROW 67 | #endif 68 | 69 | // Standard GNU options 70 | #define null_argument 0 /*Argument Null*/ 71 | #define no_argument 0 /*Argument Switch Only*/ 72 | #define required_argument 1 /*Argument Required*/ 73 | #define optional_argument 2 /*Argument Optional*/ 74 | 75 | // Shorter Options 76 | #define ARG_NULL 0 /*Argument Null*/ 77 | #define ARG_NONE 0 /*Argument Switch Only*/ 78 | #define ARG_REQ 1 /*Argument Required*/ 79 | #define ARG_OPT 2 /*Argument Optional*/ 80 | 81 | #include 82 | #include 83 | 84 | _BEGIN_EXTERN_C 85 | 86 | extern _GETOPT_API int optind; 87 | extern _GETOPT_API int opterr; 88 | extern _GETOPT_API int optopt; 89 | 90 | // Ansi 91 | struct option_a 92 | { 93 | const char* name; 94 | int has_arg; 95 | int *flag; 96 | int val; 97 | }; 98 | extern _GETOPT_API char *optarg_a; 99 | extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; 100 | extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 101 | extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 102 | 103 | // Unicode 104 | struct option_w 105 | { 106 | const wchar_t* name; 107 | int has_arg; 108 | int *flag; 109 | int val; 110 | }; 111 | extern _GETOPT_API wchar_t *optarg_w; 112 | extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; 113 | extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 114 | extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 115 | 116 | _END_EXTERN_C 117 | 118 | #undef _BEGIN_EXTERN_C 119 | #undef _END_EXTERN_C 120 | #undef _GETOPT_THROW 121 | #undef _GETOPT_API 122 | 123 | #ifdef _UNICODE 124 | #define getopt getopt_w 125 | #define getopt_long getopt_long_w 126 | #define getopt_long_only getopt_long_only_w 127 | #define option option_w 128 | #define optarg optarg_w 129 | #else 130 | #define getopt getopt_a 131 | #define getopt_long getopt_long_a 132 | #define getopt_long_only getopt_long_only_a 133 | #define option option_a 134 | #define optarg optarg_a 135 | #endif 136 | #endif // __GETOPT_H_ 137 | -------------------------------------------------------------------------------- /build/MSVC/make_vs.bat: -------------------------------------------------------------------------------- 1 | echo release 2 | cl /nologo /DFLIF_USE_STB_IMAGE /Feflif.exe -I getopt\ /DSTATIC_GETOPT ..\..\src\flif.cpp ..\..\src\flif-dec.cpp ..\..\src\flif-enc.cpp ..\..\src\common.cpp ..\..\src\io.cpp ..\..\src\maniac\*.c* ..\..\src\transform\*.cpp ..\..\src\image\*.c* getopt/getopt.c ..\..\extern\lodepng.cpp /WX /EHsc /Ox /Oy /MT /DNDEBUG 3 | 4 | echo debug 5 | cl /nologo /DFLIF_USE_STB_IMAGE /Feflif-d.exe -I getopt\ /DSTATIC_GETOPT ..\..\src\flif.cpp ..\..\src\flif-dec.cpp ..\..\src\flif-enc.cpp ..\..\src\common.cpp ..\..\src\io.cpp ..\..\src\maniac\*.c* ..\..\src\transform\*.cpp ..\..\src\image\*.c* getopt/getopt.c ..\..\extern\lodepng.cpp /WX /EHsc /Zi /Oy- /MDd /DDEBUG 6 | 7 | del *.obj 8 | 9 | echo test 10 | if exist output.flif del output.flif 11 | flif ..\..\tools/kodim01.png output.flif 12 | if exist output.png del output.png 13 | flif output.flif output.png 14 | start output.png -------------------------------------------------------------------------------- /configure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | import fnmatch 5 | 6 | 7 | __doc__ = """Build configurator for FLIF. 8 | 9 | Usage: 10 | configure.py [options] [-D var]... 11 | 12 | Options: 13 | --native Enable native optimizations. 14 | -d, --debug Compile with debug. 15 | -D var Define variable. Also -D EXAMPLE=1. 16 | -o file Output ninja file [default: build.ninja]. 17 | -h, --help Show this screen. 18 | """ 19 | 20 | def find_objects(n, dirpaths): 21 | objects = [] 22 | for dirpath in dirpaths: 23 | for root, dirnames, filenames in os.walk(dirpath): 24 | for filename in fnmatch.filter(filenames, "*.cpp"): 25 | if "flif-interface" in filename: 26 | continue 27 | src = os.path.join(root, filename) 28 | obj = os.path.join("obj", os.path.splitext(src)[0] + ".o") 29 | n.build(obj, "cxx", src) 30 | objects.append(obj) 31 | return objects 32 | 33 | def write_ninja(n, args): 34 | ######################## 35 | # Generic build rules. # 36 | ######################## 37 | exe_ext = ".exe" if os.name == "nt" else "" 38 | n.variable("cxx", "g++") 39 | 40 | if args["--debug"]: 41 | n.variable("dbgflags", "-ggdb") 42 | debug_flag = "" 43 | else: 44 | n.variable("dbgflags", "") 45 | debug_flag = " -DNDEBUG" 46 | 47 | native_flag = " -march=native" if args["--native"] else "" 48 | n.variable("optflags", "-O2 -ftree-vectorize" + native_flag + debug_flag) 49 | 50 | defines = [" -D" + d for d in args["-D"]] 51 | cxxflags = "-std=c++11 -Wall -pedantic `pkg-config --cflags zlib libpng`" 52 | n.variable("cxxflags", cxxflags + "".join(defines)) 53 | n.variable("cxxlinkflags", "`pkg-config --libs libpng`") 54 | 55 | n.rule("cxx", 56 | "$cxx $xtype -MMD -MF $out.d $optflags $dbgflags $cxxflags -c $in -o $out", 57 | depfile="$out.d") 58 | 59 | n.rule("cxxlink", "$cxx $optflags $dbgflags $in $cxxlinkflags -o $out") 60 | 61 | ################### 62 | # Build commands. # 63 | ################### 64 | objects = find_objects(n, ["extern", "src"]) 65 | n.build("src/flif" + exe_ext, "cxxlink", objects) 66 | n.default("src/flif" + exe_ext) 67 | 68 | 69 | try: 70 | from docopt import docopt 71 | import ninja_syntax 72 | except ImportError: 73 | msg = """You are missing one or more dependencies, install using: 74 | 75 | {} -m pip install --user docopt ninja-syntax 76 | 77 | If you are using an old version of Python, and don't have pip, 78 | download https://bootstrap.pypa.io/get-pip.py and run it.""" 79 | 80 | print(msg.format(os.path.basename(sys.executable))) 81 | sys.exit(1) 82 | 83 | 84 | args = docopt(__doc__) 85 | 86 | # Check if we're likely running for the first time. 87 | first_time = not os.path.isfile(args["-o"]) 88 | 89 | # Write ninja build file. 90 | with open(args["-o"], "w") as ninja_file: 91 | n = ninja_syntax.Writer(ninja_file) 92 | write_ninja(n, args) 93 | 94 | # Check if we have ninja in path. 95 | path = os.environ.get("PATH", os.defpath).split(os.pathsep) 96 | if sys.platform == "win32": 97 | path.insert(0, os.curdir) 98 | pathext = os.environ.get("PATHEXT", "").split(os.pathsep) 99 | files = ["ninja" + ext for ext in pathext] 100 | else: 101 | files = ["ninja"] 102 | 103 | is_exe = lambda p: os.path.exists(p) and os.access(p, os.F_OK | os.X_OK) and not os.path.isdir(p) 104 | has_ninja = any(is_exe(os.path.join(d, f)) for d in path for f in files) 105 | 106 | if first_time: 107 | if not has_ninja: 108 | msg = """It appears you're running configure.py for the first time, but do not have 109 | ninja in your path. On Windows we recommend simply downloading the binary: 110 | 111 | https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip 112 | 113 | Extract anywhere in your path, or even inside this directory. 114 | 115 | On linux it's easiest to compile from source: 116 | 117 | wget https://github.com/ninja-build/ninja/archive/v1.6.0.tar.gz 118 | tar xf v1.6.0.tar.gz && rm v1.6.0.tar.gz && cd ninja-1.6.0 119 | {} configure.py --bootstrap 120 | sudo cp ninja /usr/local/bin 121 | 122 | This should only take half a minute or so.""" 123 | print(msg.format(os.path.basename(sys.executable))) 124 | else: 125 | print("Type 'ninja' to build FLIF.") 126 | -------------------------------------------------------------------------------- /doc/flif.bash-completion: -------------------------------------------------------------------------------- 1 | # flif(1) completion -*- shell-script -*- 2 | 3 | _flif() 4 | { 5 | local cur prev words cword split 6 | _init_completion -s || return 7 | 8 | action=unknown 9 | next_arg_needed=unknown 10 | base_name=output 11 | 12 | # scan the previous arguments to guess what we are doing: encoding or decoding? 13 | for pw in "${words[@]:1:$((cword - 1))}"; do 14 | case $pw in 15 | -d|--decode) 16 | action=decode 17 | next_arg_needed=flif 18 | ;; 19 | -i|--identify) 20 | action=identify 21 | next_arg_needed=flif 22 | ;; 23 | -t|--transcode) 24 | action=transcode 25 | next_arg_needed=flif 26 | ;; 27 | -e|--encode) 28 | action=encode 29 | next_arg_needed=nonflif 30 | ;; 31 | -*) 32 | ;; 33 | *.flif|*.flf) 34 | case $action in 35 | unknown|decode) 36 | action=decode 37 | base_name=$pw 38 | base_name=$(basename "$base_name" .flif) 39 | base_name=$(basename "$base_name" .flf) 40 | case $next_arg_needed in 41 | flif|unknown) 42 | next_arg_needed=nonflif 43 | ;; 44 | nonflif) 45 | action=transcode 46 | next_arg_needed=none 47 | ;; 48 | esac 49 | ;; 50 | transcode) 51 | case $next_arg_needed in 52 | flif) 53 | next_arg_needed=flif2 54 | base_name=$pw 55 | base_name=$(basename "$base_name" .flif) 56 | base_name=$(basename "$base_name" .flf) 57 | base_name="$base_name-transcoded" 58 | ;; 59 | flif2) 60 | next_arg_needed=none 61 | ;; 62 | esac 63 | ;; 64 | encode) 65 | next_arg_needed=none 66 | ;; 67 | esac 68 | ;; 69 | *) 70 | case $action in 71 | unknown|encode) 72 | action=encode 73 | next_arg_needed=flif 74 | base_name=$pw 75 | base_name=$(basename "$base_name" .png) 76 | base_name=$(basename "$base_name" .pnm) 77 | base_name=$(basename "$base_name" .pam) 78 | base_name=$(basename "$base_name" .ppm) 79 | base_name=$(basename "$base_name" .pgm) 80 | base_name=$(basename "$base_name" .pbm) 81 | base_name=$(basename "$base_name" .rggb) 82 | ;; 83 | decode) 84 | next_arg_needed=none 85 | ;; 86 | esac 87 | ;; 88 | esac 89 | done 90 | if [[ $cur != "" ]]; then 91 | base_name=$cur 92 | fi 93 | 94 | 95 | case $action-$next_arg_needed in 96 | # input file names 97 | decode-flif|identify-flif|transcode-flif) 98 | _filedir '@(flif|flf)' 99 | return 100 | ;; 101 | encode-nonflif) 102 | _filedir '@(png|pnm|pam|ppm|pgm|pbm|rggb)' 103 | return 104 | ;; 105 | 106 | # suggest sensible name for output file 107 | encode-flif) 108 | if [[ $cur == -* ]]; then 109 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvveh )' -- "$cur" ) ) 110 | [[ $COMPREPLY == *= ]] && compopt -o nospace 111 | return 112 | fi 113 | COMPREPLY=$base_name.flif 114 | return 115 | ;; 116 | transcode-flif2) 117 | if [[ $cur == -* ]]; then 118 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvvh )' -- "$cur" ) ) 119 | [[ $COMPREPLY == *= ]] && compopt -o nospace 120 | return 121 | fi 122 | COMPREPLY=$base_name.flif 123 | return 124 | ;; 125 | decode-nonflif) 126 | if [[ $cur == -* ]]; then 127 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvvdh )' -- "$cur" ) ) 128 | [[ $COMPREPLY == *= ]] && compopt -o nospace 129 | return 130 | fi 131 | COMPREPLY=$base_name.png 132 | return 133 | ;; 134 | 135 | # no more arguments needed, suggest options 136 | decode-none) 137 | # only show decode options 138 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvvdh)' -- "$cur") ) 139 | [[ $COMPREPLY == *= ]] && compopt -o nospace 140 | return 141 | ;; 142 | encode-none) 143 | # only show encode options 144 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvveh)' -- "$cur" ) ) 145 | [[ $COMPREPLY == *= ]] && compopt -o nospace 146 | return 147 | ;; 148 | *-none) 149 | # show all options 150 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvvh)' -- "$cur" ) ) 151 | [[ $COMPREPLY == *= ]] && compopt -o nospace 152 | return 153 | ;; 154 | esac 155 | 156 | $split && return 0 157 | 158 | if [[ $cur == -* ]]; then 159 | COMPREPLY=( $( compgen -W '$( _parse_help "$1" -vvvh )' -- "$cur" ) ) 160 | [[ $COMPREPLY == *= ]] && compopt -o nospace 161 | return 162 | fi 163 | 164 | # suggest filenames 165 | _filedir '@(flif|flf|png|pnm|pam|ppm|pgm|pbm|rggb)' 166 | } && 167 | complete -F _flif flif 168 | -------------------------------------------------------------------------------- /doc/flif.magic: -------------------------------------------------------------------------------- 1 | # Magic data for file(1) command. (append to /etc/magic) 2 | 3 | # FLIF (Free Lossless Image Format) 4 | 0 string FLIF FLIF 5 | >4 string 5 string 1 8-bit/color 7 | >5 string 2 16-bit/color 8 | >4 string 1 grayscale, non-interlaced 9 | >4 string 3 RGB, non-interlaced 10 | >4 string 4 RGBA, non-interlaced 11 | >4 string A grayscale 12 | >4 string C RGB, interlaced 13 | >4 string D RGBA, interlaced 14 | >4 string >H animation data, 15 | >4 string Q grayscale, non-interlaced 16 | >4 string S RGB, non-interlaced 17 | >4 string T RGBA, non-interlaced 18 | >4 string a grayscale 19 | >4 string c RGB, interlaced 20 | >4 string d RGBA, interlaced 21 | 22 | #TODO: parse width/height/nb_frames (can this be done?) -------------------------------------------------------------------------------- /doc/flif.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/doc/flif.pdf -------------------------------------------------------------------------------- /doc/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | Chunks are defined similar to PNG chunks, except the chunk size is encoded with a variable number of bytes, and there is no chunk CRC. 4 | Also, the first chunk (which is always "FLIF") has no explicit chunk size. 5 | 6 | Chunk names are either 4 letters (4 bytes), or 1 byte with a value below 32. 7 | 8 | The convention of using upper and lower case letters is kept, but the meaning of the bits is slightly different. 9 | - First letter: uppercase=critical, lowercase=non-critical --> non-critical chunks can be stripped while keeping a valid file (it might be rendered differently though) 10 | - Second letter: uppercase=public, lowercase=private 11 | - Third letter: uppercase=needed to correctly display the image (e.g. a color profile), lowercase=can be stripped safely without changing anything visually 12 | - Fourth letter: uppercase=safe to copy blindly (when editing the actual image data), lowercase=may depend on image data (e.g. contain a thumbnail) 13 | 14 | Variable-size integer encoding: 15 | An unsigned integer (Big-Endian, MSB first) stored on a variable number of bytes. 16 | All the bytes except the last one have a '1' as their first bit. 17 | The unsigned integer is represented as the concatenation of the remaining 7 bit codewords. 18 | 19 | All non-obligatory chunks have a contents that is compressed with DEFLATE. 20 | 21 | The simplest FLIF file is simply a FLIF chunk followed by a \0 chunk with the actual image data. 22 | 23 | 24 | Chunk name: FLIF 25 | Obligatory: yes 26 | Description: header chunk 27 | Chunk size: not encoded 28 | Contents: 29 | First byte (byte 5 in the file) : encodes number of channels, animation or not ("1"=Grayscale non-interlaced, "3"=RGB, "4"=RGBA, +0x10 for interlaced, +0x20 for animation) 30 | Second byte (byte 6) : encodes color depth ("1" = 8-bit, "2" = 16-bit, "0" = custom) 31 | Next the image width - 1, encoded in a variable number of bytes 32 | Next the image height - 1, encoded in a variable number of bytes 33 | If it's an animation, then the number of frames - 2, encoded in a variable number of bytes 34 | 35 | 36 | Chunk name: tRko 37 | Obligatory: no 38 | Description: list of truncation offsets 39 | Contents: 40 | To be defined. 41 | Will contain a list of offsets which correspond to good truncation points, 42 | e.g. for use on a web server that uses Client Hints to send truncated FLIF files. Offsets should be relative to the start of the image data (\0 chunk 43 | for a FLIF16 image). 44 | 45 | 46 | Chunk name: iCCP 47 | Obligatory: no 48 | Description: ICC color profile. If this chunk is not present, the color profile is implicitly sRGB. 49 | Contents: 50 | the raw ICC color profile data 51 | 52 | Chunk name: eXif 53 | Obligatory: no 54 | Description: Exif metadata 55 | Contents: "Exif\0\0" header followed immediately by a TIFF header and the EXIF data. 56 | 57 | Chunk name: eXmp 58 | Obligatory: no 59 | Description: XMP metadata 60 | Contents: XMP contained within a read-only xpacket with no padding. 61 | 62 | Chunk name: \0 63 | Obligatory: yes 64 | Description: image data encoded in the FLIF16 format (future revisions of the format will use a different name, we have room for 30 revisions) 65 | Chunk size: not encoded 66 | Has to be the last chunk in the stream 67 | Contains actual image data 68 | -------------------------------------------------------------------------------- /doc/produce_documentation: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for manual in flif 4 | do 5 | man -l -t ./$manual.1 | ps2pdf - $manual.pdf 6 | done 7 | -------------------------------------------------------------------------------- /raw-tools/raw2flif: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FLIF="../src/flif -vvv" 4 | TMPDIR="tmp_raw2flif" 5 | 6 | if ! $FLIF -h >/dev/null 7 | then 8 | echo FLIF not found, please compile FLIF first! 9 | exit 1 10 | fi 11 | 12 | if [ $# -lt 2 ] 13 | then 14 | echo "Usage: $0 input_raw_file output.flif" 15 | else 16 | mkdir -p $TMPDIR 17 | rm -f $TMPDIR/* 18 | if dcraw -i "$1" > $TMPDIR/__dcraw_id 19 | then 20 | # extract metadata 21 | exiv2 ex -l $TMPDIR "$1" 22 | # extract raw data by using raw2rggb 23 | ./raw2rggb "$1" $TMPDIR/_image_tmp.rggb 24 | # flif it 25 | $FLIF $TMPDIR/_image_tmp.rggb $TMPDIR/__image.flif 26 | # remove the uncompressed data 27 | rm $TMPDIR/_image_tmp.rggb 28 | # put it all (id, metadata, compressed raw data) in an archive 29 | ar r "$2" $TMPDIR/* 30 | else 31 | echo "Not a camera raw file: $1" 32 | fi 33 | rm -f $TMPDIR/* 34 | rmdir $TMPDIR 35 | fi 36 | -------------------------------------------------------------------------------- /raw-tools/raw2rggb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FLIF="./flif -vvv" 4 | 5 | if [ $# -lt 2 ] 6 | then 7 | echo "Usage: $0 input_raw_file output.rggb" 8 | else 9 | if dcraw -i "$1" > /dev/null 10 | then 11 | # get Filter pattern //Fuji_xf1: BGGRBGGRBGGRBGGR, Pana_gh3: GBRGGBRGGBRGGBRG, leica_m82: RGGBRGGBRGGBRGGB 12 | CFAPattern=`dcraw -i -v "$1" | grep "Filter pattern: " | sed "s/Filter pattern: //g"` 13 | if [ -z "$CFAPattern" ] 14 | then 15 | Raw_color=`dcraw -i -v "$1" | grep "Raw colors: " | sed "s/Raw colors: //g"` 16 | if [ "$Raw_color" == "3" ] 17 | then 18 | PNMType="P6" 19 | else 20 | echo "This raw color is unknown: $Raw_color" 21 | exit 1 22 | fi 23 | else 24 | PNMType="P5" 25 | fi 26 | Rotate="" 27 | if [ "$PNMType" == "P5" ] 28 | then 29 | # get Orientation: "Horizontal (normal)", "Rotate 90 CW", "Rotate 180 CW", "Rotate 270 CW" 30 | Orientation=`exiftool -Orientation "$1" | sed "s/Orientation : //g"` 31 | # TODO: Remove this case part when FLIF can handle the "CFAPattern" comment 32 | # case "$CFAPattern" in 33 | # RGGBRGGBRGGBRGGB) 34 | # Rotate="-t 0";; 35 | # GRBGGRBGGRBGGRBG) 36 | # Rotate="-t 270";; 37 | # BGGRBGGRBGGRBGGR) 38 | # Rotate="-t 180";; 39 | # GBRGGBRGGBRGGBRG) 40 | # Rotate="-t 90";; 41 | # *) 42 | # echo "This pattern is unknown: $CFAPattern" 43 | # exit 1 44 | # esac 45 | # Determine the CFA pattern of output image (without the -t parameter) 46 | case "$CFAPattern" in 47 | RGGBRGGBRGGBRGGB) 48 | case "$Orientation" in 49 | "Horizontal (normal)") 50 | CFAPattern="RGGB";; 51 | "Rotate 90 CW") 52 | CFAPattern="GRBG";; 53 | "Rotate 180 CW") 54 | CFAPattern="BGGR";; 55 | "Rotate 270 CW") 56 | CFAPattern="GBRG";; 57 | *) 58 | echo "This orientation is unknown: $Orientation"". Assuming Horizontal." 59 | CFAPattern="RGGB";; 60 | esac;; 61 | GRBGGRBGGRBGGRBG) 62 | case "$Orientation" in 63 | "Horizontal (normal)") 64 | CFAPattern="GRBG";; 65 | "Rotate 90 CW") 66 | CFAPattern="BGGR";; 67 | "Rotate 180 CW") 68 | CFAPattern="GBRG";; 69 | "Rotate 270 CW") 70 | CFAPattern="RGGB";; 71 | *) 72 | echo "This orientation is unknown: $Orientation"". Assuming Horizontal." 73 | CFAPattern="GRBG";; 74 | esac;; 75 | BGGRBGGRBGGRBGGR) 76 | case "$Orientation" in 77 | "Horizontal (normal)") 78 | CFAPattern="BGGR";; 79 | "Rotate 90 CW") 80 | CFAPattern="GBRG";; 81 | "Rotate 180 CW") 82 | CFAPattern="RGGB";; 83 | "Rotate 270 CW") 84 | CFAPattern="GRBG";; 85 | *) 86 | echo "This orientation is unknown: $Orientation"". Assuming Horizontal." 87 | CFAPattern="BGGR";; 88 | esac;; 89 | GBRGGBRGGBRGGBRG) 90 | case "$Orientation" in 91 | "Horizontal (normal)") 92 | CFAPattern="GBRG";; 93 | "Rotate 90 CW") 94 | CFAPattern="RGGB";; 95 | "Rotate 180 CW") 96 | CFAPattern="GRBG";; 97 | "Rotate 270 CW") 98 | CFAPattern="BGGR";; 99 | *) 100 | echo "This orientation is unknown: $Orientation"". Assuming Horizontal." 101 | CFAPattern="GBRG";; 102 | esac;; 103 | *) 104 | echo "This pattern is unknown: $CFAPattern" 105 | exit 1 106 | esac 107 | fi 108 | # Add CFAPattern comment 109 | echo "$PNMType" > "$2" 110 | if [ "$PNMType" == "P5" ] 111 | then 112 | echo "# CFAPattern: $CFAPattern" >> "$2" 113 | fi 114 | # extract raw data, presumably in some kind of RGGB format 115 | dcraw -E -4 -c "$1" | sed -b -e "1d" >> "$2" 116 | else 117 | echo "Not a camera raw file: $1" 118 | fi 119 | fi 120 | -------------------------------------------------------------------------------- /raw-tools/raw2rggb.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SET EXIFTOOL=exiftool.exe 3 | SET DCRAW=dcraw.exe 4 | SET SED=sed.exe 5 | 6 | SET CMDFI=%0 7 | SET INFI=%1 8 | SET OUTFI=%2 9 | SET NOTFI=%3 10 | 11 | IF NOT "%NOTFI%"=="" IF "%OUFI%"=="" ( 12 | ECHO Usage: raw2rggb.bat input_raw_file output.rggb 13 | EXIT /B 1 14 | ) 15 | 16 | 17 | IF "%DCRAW% -i %INFI%"=="" ( 18 | ECHO Not a camera raw file: %INFI% 19 | EXIT /B 1 20 | ) 21 | 22 | 23 | REM get Filter pattern //Fuji_xf1: BGGRBGGRBGGRBGGR, Pana_gh3: GBRGGBRGGBRGGBRG, leica_m82: RGGBRGGBRGGBRGGB 24 | SET RCOLOR= 25 | SET PNMTYPE=P5 26 | SET Rotate= 27 | SET CFAP= 28 | for /f "delims=" %%a in ('%DCRAW% -i -v %INFI% ^| findstr "Filter pattern: " ^| %SED% "s/Filter pattern: //g" ^| %SED% "s/\///g"') do @set CFAP=%%a 29 | for /f "delims=" %%a in ('%DCRAW% -i -v %INFI% ^| findstr "Raw colors: " ^| %SED% "s/Raw colors: //g"') do @set RCOLOR=%%a 30 | IF "%CFAP%"=="" ( 31 | IF "%RCOLOR%"=="3" ( 32 | SET PNMTYPE=P6 33 | GOTO GT_DECOMP 34 | ) ELSE ( 35 | ECHO This raw color is unknown: %RCOLOR% 36 | EXIT /B 1 37 | ) 38 | ) 39 | 40 | REM get Orientation: "Horizontal (normal)", "Rotate 90 CW", "Rotate 180 CW", "Rotate 270 CW" 41 | SET Orientation= 42 | for /f "delims=" %%a in ('%EXIFTOOL% -Orientation %1 ^| %SED% "s/Orientation : //g" ^| %SED% "s/ (normal)//g"') do @set Orientation=%%a 43 | IF !Orientation!=="Horizontal" SET Orientation=Horizontal 44 | IF !Orientation!=="Rotate 90 CW" SET Orientation=90CW 45 | IF !Orientation!=="Rotate 180 CW" SET Orientation=180CW 46 | IF !Orientation!=="Rotate 270 CW" SET Orientation=270CW 47 | 48 | REM SET Rotate=-t 0 49 | REM TODO: Remove this case part when FLIF can handle the "CFAP" comment 50 | REM IF "%CFAP%"=="RGGB" ( 51 | REM SET Rotate=-t 0 52 | REM) ELSE IF "%CFAP%"=="GRBG" ( 53 | REM SET Rotate=-t 270 54 | REM ) ELSE IF "%CFAP%"=="BGGR" ( 55 | REM SET Rotate=-t 180 56 | REM) ELSE IF "%CFAP%"=="GBRG" ( 57 | REM SET Rotate=-t 90 58 | REM) ELSE ( 59 | REM ECHO This pattern is unknown: %CFAP% 60 | REM EXIT /B 1 61 | REM) 62 | 63 | REM Determine the CFA pattern of output image (without the -t parameter) 64 | IF "%CFAP%"=="RGGB" ( 65 | IF "%Orientation%"=="90CW" ( 66 | SET CFAP=GRBG 67 | ) ELSE IF "%Orientation%"=="180CW" ( 68 | SET CFAP=BGGR 69 | ) ELSE IF "%Orientation%"=="270CW" ( 70 | SET CFAP=GBRG 71 | ) ELSE IF NOT "%Orientation%"=="Horizontal" ( 72 | ECHO This orientation is unknown: %Orientation%. Assuming Horizontal. 73 | ) 74 | ) ELSE IF "%CFAP%"=="GRBG" ( 75 | IF "%Orientation%"=="90CW" ( 76 | SET CFAP=BGGR 77 | ) ELSE IF "%Orientation%"=="180CW" ( 78 | SET CFAP=GBRG 79 | ) ELSE IF "%Orientation%"=="270CW" ( 80 | SET CFAP=RGGB 81 | ) ELSE IF NOT "%Orientation%"=="Horizontal" ( 82 | ECHO This orientation is unknown: %Orientation%. Assuming Horizontal. 83 | ) 84 | ) ELSE IF "%CFAP%"=="BGGR" ( 85 | IF "%Orientation%"=="90CW" ( 86 | SET CFAP=GBRG 87 | ) ELSE IF "%Orientation%"=="180CW" ( 88 | SET CFAP=RGGB 89 | ) ELSE IF "%Orientation%"=="270CW" ( 90 | SET CFAP=GRBG 91 | ) ELSE IF NOT "%Orientation%"=="Horizontal" ( 92 | ECHO This orientation is unknown: %Orientation%. Assuming Horizontal. 93 | ) 94 | ) ELSE IF "%CFAP%"=="GBRG" ( 95 | IF "%Orientation%"=="90CW" ( 96 | SET CFAP=RGGB 97 | ) ELSE IF "%Orientation%"=="180CW" ( 98 | SET CFAP=GRBG 99 | ) ELSE IF "%Orientation%"=="270CW" ( 100 | SET CFAP=BGGR 101 | ) ELSE IF NOT "%Orientation%"=="Horizontal" ( 102 | ECHO This orientation is unknown: %Orientation%. Assuming Horizontal. 103 | ) 104 | ) ELSE ( 105 | ECHO This pattern is unknown: %CFAP% 106 | EXIT /B 1 107 | ) 108 | 109 | :GT_DECOMP 110 | REM Add CFAP comment 111 | REM ECHO %PNMTYPE%>%OUTFI% 112 | IF "%PNMTYPE%"=="P5" ECHO # CFAPattern: %CFAP%>%OUTFI% 113 | REM extract raw data, presumably in some kind of RGGB format 114 | %DCRAW% -E -4 -c %INFI%>>%OUTFI% 115 | -------------------------------------------------------------------------------- /raw-tools/sony_arw/README: -------------------------------------------------------------------------------- 1 | These tools can losslessly compress and decompress a Sony ARW (RAW) image file. 2 | 3 | INSTALLATION 4 | 5 | First, compile the C stuff: 6 | $ gcc -o arw_encode arw_encode.c 7 | $ gcc -o dcraw_hack -lm dcraw.c 8 | 9 | Then, ensure that you have flif (http://flif.info/) and the binaries above 10 | in your $PATH. You'll also need ImageMagick's convert, as well as some 11 | standard tools like sha256sum and tar (see *.sh for details). 12 | 13 | USAGE 14 | 15 | To compress, use 16 | $ arw_compress.sh filename.ARW 17 | 18 | This should create a filename.ARW.flifraw that's generally 50-75% the size 19 | of the .ARW file. 20 | 21 | To recover your original .ARW file: 22 | $ arw_decompress.sh filename.ARW.flifraw 23 | 24 | LICENSE 25 | 26 | GPLv3 or later. Includes modified code of dcraw (see header of dcraw.c 27 | for details). 28 | 29 | TECHNICAL INFO 30 | 31 | These tools create a .tar.xz file which contains the ARW header (which 32 | usually includes a lossy JPG preview - this is untouched), a flif-compressed 33 | image of the raw sensor data (in 16 bits per channel), and a list of "alarms", 34 | ie. some sony-specific fixup data that allows us to recreate the original ARW 35 | perfectly. 36 | 37 | arw_encode then reads this list of "alarms" and recreates the ARW file. 38 | 39 | The need for those "alarms" arises from a funny encoding that Sony uses 40 | in their RAW files. The original sensor data is about 11-bits per pixel, 41 | but it is compressed into 8 bits, sometimes losing some detail. The 42 | compression is pretty simple: it takes 16 pixel values, encodes the 43 | minimum and the maximum value of those 16, and then encodes the remaining 14 44 | values as 8-bit differences from the minimum. There's also a "shift" amount 45 | applied in case the range of those 16 pixels is larger than 255 (that's when 46 | data loss happens). Because sometimes there's more than one "minimum" or 47 | "maximum" value pixel, there can be multiple ways that Sony can encode these. 48 | I couldn't find a consistent way in which this is encoded, so if the ARW 49 | differs from the simple heuristic I used, an "alarm" is raised and stored in 50 | an exceptions file. 51 | 52 | This exceptions file could probably be ignored and the resulting ARW file 53 | would be pixel-for-pixel identical with the original, but I wanted to make 54 | sure the compression scheme is truly lossless and preserves the file 55 | perfectly. 56 | -------------------------------------------------------------------------------- /raw-tools/sony_arw/arw_compress.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | SRC="$1" 6 | DST="$2" 7 | 8 | if [ "x$SRC" == "x" ] 9 | then 10 | echo "Need a source file!" 11 | exit 1 12 | fi 13 | 14 | if [ "x$DST" == "x" ] 15 | then 16 | DST="$SRC.flifraw" 17 | fi 18 | 19 | if [ -e "$DST" ] 20 | then 21 | echo "Destination $DST already exists, refusing to overwrite" 22 | exit 1 23 | fi 24 | 25 | DIR=$(mktemp -d "$DST.XXXXXX") 26 | 27 | cat < "$DIR"/file.list 28 | $DIR/alarms.bin 29 | $DIR/begin 30 | $DIR/orig.sha256 31 | EOL 32 | 33 | sha256sum - < "$SRC" > "$DIR"/orig.sha256 34 | dcraw_hack "$SRC" > "$DIR"/temp.rgba 2> "$DIR"/err 35 | HALF_SIZE=$(head -n1 "$DIR"/err | sed -e 's/^.*, half=\([0-9]*x[0-9]*\)$/\1/') 36 | convert -depth 16 -size $HALF_SIZE rgba:"$DIR"/temp.rgba png:"$DIR"/temp.png 37 | grep ALARM "$DIR"/err | cut -c 8- | xxd -r -ps > "$DIR"/alarms.bin 38 | LAST_LINE=$(tail -n1 "$DIR"/err) 39 | PADDING_BYTE=00 40 | if (echo "$LAST_LINE" | grep -q PADDING "$DIR"/err) 41 | then 42 | PADDING_BYTE=$(echo "$LAST_LINE" | cut -c 10-) 43 | echo $PADDING_BYTE | xxd -r -ps > "$DIR"/padding 44 | echo "$DIR"/padding >> "$DIR"/file.list 45 | fi 46 | 47 | START=$(head -n1 "$DIR"/err | sed -e 's/^.*data_at=//' -e 's/, .*$//') 48 | HALF_WIDTH=$(echo $HALF_SIZE | sed -e 's/x.*$//') 49 | 50 | flif -e --keep-invisible-rgb "$DIR"/temp.png "$DIR"/result.flif 51 | 52 | flif -d "$DIR"/result.flif "$DIR"/result.flif.png 53 | head -c $START "$SRC" > "$DIR"/begin 54 | 55 | if (cat "$DIR"/begin; convert "$DIR"/result.flif.png -depth 16 rgba:- | arw_encode $HALF_WIDTH $START "$DIR"/alarms.bin $PADDING_BYTE) | cmp - "$SRC" 56 | then 57 | cat "$DIR"/file.list | xargs tar --transform 's=^.*/==' -Jcf "$DIR"/extra.tar.xz 58 | tar --transform 's=^.*/==' -cf "$DST" "$DIR"/extra.tar.xz "$DIR"/result.flif 59 | cat "$DIR"/file.list | xargs rm "$DIR"/{extra.tar.xz,result.flif,err,result.flif.png,temp.png,temp.rgba,file.list} 60 | rmdir "$DIR" 61 | else 62 | echo data mismatch, temp stuff left in $DIR 63 | exit 1 64 | fi 65 | -------------------------------------------------------------------------------- /raw-tools/sony_arw/arw_decompress.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | SRC="$1" 6 | DST="$2" 7 | 8 | if [ "x$SRC" == "x" ] 9 | then 10 | echo "Need a source file!" 11 | exit 1 12 | fi 13 | 14 | if [ "x$DST" == "x" ] 15 | then 16 | DST=$(echo "$SRC" | sed -e 's/\.flifraw$//') 17 | fi 18 | 19 | if [ -e "$DST" ] 20 | then 21 | echo "Destination $DST already exists, refusing to overwrite" 22 | exit 1 23 | fi 24 | 25 | DIR=$(mktemp -d "$DST.XXXXXX") 26 | 27 | tar -C "$DIR" -xf "$SRC" 28 | tar -C "$DIR" -Jxf "$DIR"/extra.tar.xz 29 | START=$(stat -c '%s' "$DIR"/begin) 30 | HALF_WIDTH=$(flif -i "$DIR"/result.flif | sed -e 's/^.*FLIF image, \([0-9]*\)x.*$/\1/') 31 | PADDING=00 32 | if [ -e "$DIR"/padding ] 33 | then 34 | PADDING=$(head -c1 "$DIR/padding" | xxd -ps) 35 | rm "$DIR"/padding 36 | fi 37 | 38 | flif -d "$DIR"/result.flif "$DIR"/result.flif.png 39 | (cat "$DIR"/begin; convert "$DIR"/result.flif.png -depth 16 rgba:- | arw_encode $HALF_WIDTH $START "$DIR"/alarms.bin $PADDING) > "$DST" 40 | if ! sha256sum --quiet -c "$DIR"/orig.sha256 < "$DST" 41 | then 42 | echo "SHA mismatch, $DST broken, stuff left in $DIR :-(" 43 | exit 1 44 | fi 45 | rm "$DIR"/{extra.tar.xz,result.flif,result.flif.png,begin,orig.sha256,alarms.bin} 46 | rmdir "$DIR" 47 | -------------------------------------------------------------------------------- /raw-tools/sony_arw/arw_encode.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void writebits(uint8_t *dst, int from, int len, uint16_t data) 8 | { 9 | int bit; 10 | 11 | for(bit = 0; bit < len; bit++) { 12 | int val = (data & (1 << bit)); 13 | int obyte = (from + bit) >> 3; 14 | int bitpos = (from+bit) & 0x07; 15 | 16 | if(val) 17 | dst[obyte] = dst[obyte] | (1 << bitpos); 18 | else 19 | dst[obyte] = dst[obyte] & ~(1 << bitpos); 20 | } 21 | } 22 | 23 | struct exception { 24 | uint32_t chunk; 25 | uint8_t minmax; 26 | }; 27 | 28 | struct exception load_exception(FILE *f) 29 | { 30 | struct exception rv; 31 | unsigned char buf[5]; 32 | rv.chunk=0xffffffff; 33 | 34 | if(!f) 35 | return rv; 36 | 37 | if(fread(buf, 1, 5, f) != 5) 38 | return rv; 39 | 40 | rv.chunk = 0; 41 | rv.chunk |= buf[3]; 42 | rv.chunk |= buf[2] << 8; 43 | rv.chunk |= buf[1] << 16; 44 | rv.chunk |= buf[0] << 24; 45 | rv.minmax = buf[4]; 46 | 47 | return rv; 48 | } 49 | 50 | static inline int exception_valid(struct exception *e) 51 | { 52 | return e->chunk != 0xffffffff; 53 | } 54 | 55 | uint32_t chunk_cnt=0; 56 | struct exception exception; 57 | FILE *excf=NULL; 58 | 59 | void arw_encode(uint16_t *buf) 60 | { 61 | uint8_t outbuf[16]; 62 | uint16_t max=0, min=0xffff, imax, imin, sh; 63 | int i, pos; 64 | 65 | // find min/max 66 | if(exception_valid(&exception) && exception.chunk == chunk_cnt) { 67 | imin = exception.minmax >> 4; 68 | imax = exception.minmax & 0x0f; 69 | min = buf[imin]; 70 | max = buf[imax]; 71 | exception = load_exception(excf); 72 | } else { 73 | for(i = 0; i < 16; i++) { 74 | if(buf[i] >= max) { 75 | max = buf[i]; 76 | imax = i; 77 | } 78 | if(buf[i] < min) { 79 | min = buf[i]; 80 | imin = i; 81 | } 82 | } 83 | } 84 | 85 | // find shift 86 | for(sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); 87 | 88 | writebits(outbuf, 0, 11, max); 89 | writebits(outbuf, 11, 11, min); 90 | writebits(outbuf, 22, 4, imax); 91 | writebits(outbuf, 26, 4, imin); 92 | 93 | pos = 30; 94 | for(i = 0; i < 16; i++) { 95 | if(i != imin && i != imax) { 96 | writebits(outbuf, pos, 7, (buf[i]-min) >> sh); 97 | pos += 7; 98 | } 99 | } 100 | 101 | fwrite(outbuf, 1, 16, stdout); 102 | chunk_cnt++; 103 | } 104 | 105 | void flush_arw(uint16_t *outbuf, int *outcnt) 106 | { 107 | if(*outcnt >= 32) { 108 | uint16_t arwbuf[32]; 109 | int arwbuf_cnt = 0; 110 | 111 | int j; 112 | for(j = 0; j < 32; j+=2) { 113 | arwbuf[arwbuf_cnt++] = outbuf[j]; 114 | } 115 | for(j = 1; j < 32; j+=2) { 116 | arwbuf[arwbuf_cnt++] = outbuf[j]; 117 | } 118 | 119 | arw_encode(arwbuf); 120 | arw_encode(arwbuf+16); 121 | 122 | *outcnt = 0; 123 | } 124 | } 125 | 126 | void write_padding(long headerlen, int val) 127 | { 128 | long our_len = headerlen + chunk_cnt * 16; 129 | long shouldbe = (our_len / 0x8000) * 0x8000 + 0x8000; 130 | long missing = shouldbe - our_len; 131 | 132 | char *buf; 133 | buf = malloc(missing); 134 | if(!buf) { 135 | fprintf(stderr, "woops, can't alloc padding\n"); 136 | } else { 137 | memset(buf, val, missing); 138 | fwrite(buf, 1, missing, stdout); 139 | free(buf); 140 | } 141 | } 142 | 143 | int main(int argc, char **argv) 144 | { 145 | long width, headerlen; 146 | uint16_t *buf; 147 | uint16_t arw_buf[32]; 148 | int arw_buf_cnt = 0; 149 | int padding = 0; 150 | 151 | if(argc < 3) { 152 | fprintf(stderr, "need at least a width, a headerlen, and possibly an exceptions file\n"); 153 | return 1; 154 | } 155 | 156 | width = atol(argv[1]); 157 | headerlen = atol(argv[2]); 158 | 159 | buf = malloc(sizeof(uint16_t) * width * 4); 160 | if(!buf) { 161 | fprintf(stderr, "alloc error\n"); 162 | return 1; 163 | } 164 | 165 | if(argc > 3) 166 | excf = fopen(argv[3], "r"); 167 | 168 | if(argc > 4) 169 | padding = strtol(argv[4], NULL, 16); 170 | 171 | exception = load_exception(excf); 172 | 173 | while(!feof(stdin)) { 174 | size_t rv; 175 | int i; 176 | if((rv=fread(buf, sizeof(uint16_t), width*4, stdin)) != width*4) { 177 | if(rv != 0) 178 | fprintf(stderr, "read only %lu\n", (unsigned long) rv); 179 | continue; 180 | } 181 | 182 | for(i = 0; i < width * 4; i += 4) { 183 | arw_buf[arw_buf_cnt++] = buf[i] >> 5; 184 | arw_buf[arw_buf_cnt++] = buf[i+1] >> 5; 185 | flush_arw(arw_buf, &arw_buf_cnt); 186 | } 187 | for(i = 0; i < width * 4; i += 4) { 188 | arw_buf[arw_buf_cnt++] = buf[i+3] >> 5; 189 | arw_buf[arw_buf_cnt++] = buf[i+2] >> 5; 190 | flush_arw(arw_buf, &arw_buf_cnt); 191 | } 192 | } 193 | 194 | free(buf); 195 | 196 | write_padding(headerlen, padding); 197 | 198 | return 0; 199 | } 200 | -------------------------------------------------------------------------------- /src/compiler-specific.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _MSC_VER 4 | #define ATTRIBUTE_HOT 5 | #else 6 | #define ATTRIBUTE_HOT __attribute__ ((hot)) 7 | #endif -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*****************************************/ 4 | /* OPTIONS TO DISABLE SOME FUNCTIONALITY */ 5 | /*****************************************/ 6 | 7 | // define this flag if you want support for > 8 bit per channel 8 | #ifndef ONLY_8BIT 9 | #define SUPPORT_HDR 1 10 | #endif 11 | 12 | // include encoder related functionality in build. Disable when only interested in decoder 13 | #ifndef DECODER_ONLY 14 | #define HAS_ENCODER 1 15 | #endif 16 | 17 | // support animations 18 | #ifndef STILL_ONLY 19 | #define SUPPORT_ANIMATION 1 20 | #endif 21 | 22 | 23 | // during decode, check for unexpected file end and interpolate from there 24 | #define CHECK_FOR_BROKENFILES 1 25 | 26 | // maximum image buffer size to attempt to decode 27 | // (the format supports larger images/animations, but this threshold helps to avoid malicious input to grab too much memory) 28 | // this is one frame of 1000 megapixels 8-bit RGB (it's 5 bytes per pixel because YCoCg uses 2 bytes each for Co/Cg) 29 | // (or 1000 frames of 1 megapixel) 30 | #define MAX_IMAGE_BUFFER_SIZE 1000ULL*1000000ULL*5ULL 31 | 32 | // refuse to decode something which claims to have more frames than this 33 | #define MAX_FRAMES 50000 34 | 35 | /************************/ 36 | /* COMPILATION OPTIONS */ 37 | /************************/ 38 | 39 | // speed / binary size trade-off: 0, 1, 2 (higher number -> bigger and faster binary) 40 | #define LARGE_BINARY 1 41 | 42 | #ifndef __clang__ 43 | #define USE_SIMD 1 44 | #endif 45 | 46 | /**************************/ 47 | /* FIX COMPILER WARNINGS */ 48 | /**************************/ 49 | 50 | #ifdef FLIF_UNUSED 51 | #elif defined(__GNUC__) || defined(__clang__) 52 | # define FLIF_UNUSED(x) x __attribute__((unused)) 53 | #elif defined(__LCLINT__) 54 | # define FLIF_UNUSED(x) /*@unused@*/ x 55 | #else 56 | # define FLIF_UNUSED(x) x 57 | #endif 58 | 59 | /*************************************************/ 60 | /* OPTIONS TO CHANGE DEFAULT ENCODING PARAMETERS */ 61 | /*************************************************/ 62 | 63 | // more repeats makes encoding more expensive, but results in better trees (smaller files) 64 | #define TREE_LEARN_REPEATS 2 65 | 66 | #define DEFAULT_MAX_PALETTE_SIZE 512 67 | 68 | // 8 byte improvement needed before splitting a MANIAC leaf node 69 | #define CONTEXT_TREE_SPLIT_THRESHOLD 5461*8*8 70 | 71 | #define CONTEXT_TREE_COUNT_DIV 30 72 | #define CONTEXT_TREE_MIN_SUBTREE_SIZE 50 73 | 74 | 75 | 76 | /**************************************************/ 77 | /* DANGER ZONE: OPTIONS THAT CHANGE THE BITSTREAM */ 78 | /* If you modify these, the bitstream format */ 79 | /* changes, so it is no longer compatible! */ 80 | /**************************************************/ 81 | 82 | // output the first K zoomlevels without building trees (too little data anyway to learn much from it) 83 | #define NB_NOLEARN_ZOOMS 12 84 | // this is enough to get a reasonable thumbnail/icon before the tree gets built/transmitted (at most 64x64 pixels) 85 | 86 | // faster decoding, less compression (disable multi-scale bitchances, use 24-bit rac) 87 | #define FAST_BUT_WORSE_COMPRESSION 1 88 | 89 | // bounds for node counters 90 | #define CONTEXT_TREE_MIN_COUNT 1 91 | #define CONTEXT_TREE_MAX_COUNT 512 92 | 93 | 94 | 95 | // DEFAULT ENCODE/DECODE OPTIONS ARE DEFINED BELOW 96 | 97 | 98 | #include 99 | #include 100 | 101 | enum class Optional : uint8_t { 102 | undefined = 0 103 | }; 104 | 105 | enum class flifEncoding : uint8_t { 106 | nonInterlaced = 1, 107 | interlaced = 2 108 | }; 109 | 110 | union flifEncodingOptional { 111 | flifEncoding encoding; 112 | Optional o; 113 | flifEncodingOptional() : o(Optional::undefined) {} 114 | }; 115 | 116 | struct flif_options { 117 | #ifdef HAS_ENCODER 118 | int learn_repeats; 119 | int acb; 120 | std::vector frame_delay; 121 | int palette_size; 122 | int lookback; 123 | int divisor; 124 | int min_size; 125 | int split_threshold; 126 | int ycocg; 127 | int subtract_green; 128 | int plc; 129 | int frs; 130 | int alpha_zero_special; 131 | int loss; 132 | int adaptive; 133 | int predictor[5]; 134 | int chroma_subsampling; 135 | #endif 136 | flifEncodingOptional method; 137 | int invisible_predictor; 138 | int alpha; 139 | int cutoff; 140 | int crc_check; 141 | int metadata; 142 | int color_profile; 143 | int quality; 144 | int scale; 145 | int resize_width; 146 | int resize_height; 147 | int fit; 148 | int overwrite; 149 | int just_add_loss; 150 | int show_breakpoints; 151 | int no_full_decode; 152 | int keep_palette; 153 | }; 154 | 155 | const struct flif_options FLIF_DEFAULT_OPTIONS = { 156 | #ifdef HAS_ENCODER 157 | -1, // learn_repeats 158 | -1, // acb, try auto color buckets 159 | {100}, // frame_delay 160 | -1, // palette_size 161 | 1, // lookback 162 | CONTEXT_TREE_COUNT_DIV, // divisor 163 | CONTEXT_TREE_MIN_SUBTREE_SIZE, // min_size 164 | CONTEXT_TREE_SPLIT_THRESHOLD, // split_threshold 165 | 1, // ycocg 166 | 1, // subtract_green 167 | 1, // plc 168 | 1, // frs 169 | 1, // alpha_zero_special 170 | 0, // loss 171 | 0, // adaptive 172 | {-2,-2,-2,-2,-2}, // predictor, heuristically pick a fixed predictor on all planes 173 | 0, // chroma_subsampling 174 | #endif 175 | flifEncodingOptional(), // method 176 | 2, // invisible_predictor 177 | 19, // alpha 178 | 2, // cutoff 179 | -1, // crc_check 180 | 1, // metadata 181 | 1, // color_profile 182 | 100, // quality, 100 = everything, positive value: partial decode, negative value: only rough data 183 | 1, // scale 184 | 0, // resize_width 185 | 0, // resize_height 186 | 0, // fit 187 | 0, // overwrite 188 | 0, // just_add_loss 189 | 0, // show_breakpoints 190 | 0, // no_full_decode 191 | 0, // keep_palette 192 | }; 193 | -------------------------------------------------------------------------------- /src/fileio.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | class FileIO 25 | { 26 | private: 27 | FILE *file; 28 | const char *name; 29 | public: 30 | // prevent copy 31 | FileIO(const FileIO&) = delete; 32 | void operator=(const FileIO&) = delete; 33 | // prevent move, for now 34 | FileIO(FileIO&&) = delete; 35 | void operator=(FileIO&&) = delete; 36 | 37 | const int EOS = EOF; 38 | 39 | FileIO(FILE* fil, const char *aname) : file(fil), name(aname) { } 40 | ~FileIO() { 41 | if (file) fclose(file); 42 | } 43 | void flush() { 44 | fflush(file); 45 | } 46 | bool isEOF() { 47 | return feof(file); 48 | } 49 | long ftell() { 50 | return ::ftell(file); 51 | } 52 | int get_c() { 53 | return fgetc(file); 54 | } 55 | char * gets(char *buf, int n) { 56 | return fgets(buf, n, file); 57 | } 58 | int fputs(const char *s) { 59 | return ::fputs(s, file); 60 | } 61 | int fputc(int c) { 62 | return ::fputc(c, file); 63 | } 64 | void fseek(long offset, int where) { 65 | ::fseek(file, offset,where); 66 | } 67 | const char* getName() const { 68 | return name; 69 | } 70 | }; 71 | 72 | /*! 73 | * Read-only IO interface for a constant memory block 74 | */ 75 | class BlobReader 76 | { 77 | private: 78 | const uint8_t* data; 79 | size_t data_array_size; 80 | size_t seek_pos; 81 | bool readEOS; 82 | public: 83 | const int EOS = -1; 84 | 85 | BlobReader(const uint8_t* _data, size_t _data_array_size) 86 | : data(_data) 87 | , data_array_size(_data_array_size) 88 | , seek_pos(0) 89 | , readEOS(false) 90 | { 91 | } 92 | 93 | bool isEOF() const { 94 | if(readEOS) { 95 | return true; 96 | } else { 97 | return false; 98 | } 99 | } 100 | long ftell() const { 101 | return seek_pos; 102 | } 103 | int get_c() { 104 | if(seek_pos >= data_array_size) { 105 | readEOS = true; 106 | return EOS; 107 | } 108 | return data[seek_pos++]; 109 | } 110 | char * gets(char *buf, int n) { 111 | int i = 0; 112 | const int max_write = n-1; 113 | while(seek_pos < data_array_size && i < max_write) 114 | buf[i++] = data[seek_pos++]; 115 | buf[n-1] = '\0'; 116 | 117 | if(i < max_write) { 118 | readEOS = true; 119 | return 0; 120 | } else { 121 | return buf; 122 | } 123 | } 124 | int fputc(int FLIF_UNUSED(c)) { 125 | // cannot write on const memory 126 | return EOS; 127 | } 128 | void fseek(long offset, int where) { 129 | readEOS = false; 130 | switch(where) { 131 | case SEEK_SET: 132 | seek_pos = offset; 133 | break; 134 | case SEEK_CUR: 135 | seek_pos += offset; 136 | break; 137 | case SEEK_END: 138 | seek_pos = long(data_array_size) + offset; 139 | break; 140 | } 141 | } 142 | static const char* getName() { 143 | return "BlobReader"; 144 | } 145 | }; 146 | 147 | /*! 148 | * IO interface for a growable memory block 149 | */ 150 | class BlobIO 151 | { 152 | private: 153 | uint8_t* data; 154 | // keeps track how large the array really is 155 | // HINT: should only be used in the grow() function 156 | size_t data_array_size; 157 | // keeps track how many bytes were written 158 | size_t bytes_used; 159 | size_t seek_pos; 160 | bool readEOS; 161 | 162 | void grow(size_t necessary_size) { 163 | readEOS = false; 164 | if(necessary_size < data_array_size) 165 | return; 166 | 167 | size_t new_size = necessary_size; 168 | // start with reasonably large array 169 | if(new_size < 4096) 170 | new_size = 4096; 171 | 172 | if(new_size < data_array_size * 3 / 2) 173 | new_size = data_array_size * 3 / 2; 174 | uint8_t* new_data = new uint8_t[new_size]; 175 | 176 | memcpy(new_data, data, bytes_used); 177 | // if seek_pos has been moved beyond the written bytes, 178 | // fill the empty space with zeroes 179 | for(size_t i = bytes_used; i < seek_pos; ++i) 180 | new_data[i] = 0; 181 | delete [] data; 182 | data = new_data; 183 | std::swap(data_array_size, new_size); 184 | } 185 | public: 186 | const int EOS = -1; 187 | 188 | BlobIO() 189 | : data(0) 190 | , data_array_size(0) 191 | , bytes_used(0) 192 | , seek_pos(0) 193 | , readEOS(false) 194 | { 195 | } 196 | 197 | ~BlobIO() { 198 | delete [] data; 199 | } 200 | 201 | uint8_t* release(size_t* array_size) 202 | { 203 | uint8_t* ptr = data; 204 | *array_size = bytes_used; 205 | 206 | data = 0; 207 | data_array_size = 0; 208 | bytes_used = 0; 209 | seek_pos = 0; 210 | return ptr; 211 | } 212 | 213 | static void flush() { 214 | // nothing to do 215 | } 216 | bool isEOF() const { 217 | if(readEOS) { 218 | return true; 219 | } else { 220 | return false; 221 | } 222 | } 223 | long ftell() const { 224 | return seek_pos; 225 | } 226 | int get_c() { 227 | if(seek_pos >= bytes_used) { 228 | readEOS = true; 229 | return EOS; 230 | } 231 | return data[seek_pos++]; 232 | } 233 | char * gets(char *buf, int n) { 234 | int i = 0; 235 | const int max_write = n-1; 236 | while(seek_pos < bytes_used && i < max_write) 237 | buf[i++] = data[seek_pos++]; 238 | buf[n-1] = '\0'; 239 | 240 | if(i < max_write) { 241 | readEOS = true; 242 | return 0; 243 | } else { 244 | return buf; 245 | } 246 | } 247 | int fputs(const char *s) { 248 | size_t i = 0; 249 | // null-terminated string 250 | while(s[i]) 251 | { 252 | grow(seek_pos + 1); 253 | data[seek_pos++] = s[i++]; 254 | if(bytes_used < seek_pos) 255 | bytes_used = seek_pos+1; 256 | } 257 | return 0; 258 | } 259 | int fputc(int c) { 260 | grow(seek_pos + 1); 261 | 262 | data[seek_pos++] = static_cast(c); 263 | if(bytes_used < seek_pos) 264 | bytes_used = seek_pos+1; 265 | return c; 266 | } 267 | void fseek(long offset, int where) { 268 | readEOS = false; 269 | switch(where) { 270 | case SEEK_SET: 271 | seek_pos = offset; 272 | break; 273 | case SEEK_CUR: 274 | seek_pos += offset; 275 | break; 276 | case SEEK_END: 277 | seek_pos = long(bytes_used) + offset; 278 | break; 279 | } 280 | } 281 | static const char* getName() { 282 | return "BlobIO"; 283 | } 284 | }; 285 | 286 | -------------------------------------------------------------------------------- /src/flif-dec.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct FLIF_INFO 4 | { 5 | FLIF_INFO(); 6 | 7 | uint32_t width; 8 | uint32_t height; 9 | uint8_t channels; 10 | uint8_t bit_depth; 11 | size_t num_images; 12 | }; 13 | 14 | typedef uint32_t (*callback_t)(uint32_t quality, int64_t bytes_read, uint8_t decode_over, void *user_data, void *context); 15 | 16 | /*! 17 | * @param[out] info An info struct to fill. If this is not a null pointer, the decoding will exit after reading the file header. 18 | */ 19 | 20 | template 21 | bool flif_decode(IO& io, Images &images, callback_t callback, void *user_data, int, Images &partial_images, flif_options &options, metadata_options &md, FLIF_INFO* info); 22 | 23 | template 24 | bool flif_decode(IO& io, Images &images, flif_options &options, metadata_options &md) { 25 | return flif_decode(io, images, NULL, NULL, 0, images, options, md, 0); 26 | } 27 | -------------------------------------------------------------------------------- /src/flif-enc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image/color_range.hpp" 4 | #include "transform/factory.hpp" 5 | #include "common.hpp" 6 | 7 | template 8 | bool flif_encode(IO& io, Images &images, const std::vector &transDesc, flif_options &options); 9 | 10 | template 11 | bool flif_encode(IO& io, Images &images, const std::vector &transDesc = 12 | {"YCoCg","Bounds","Palette_Alpha","Palette","Color_Buckets","Duplicate_Frame","Frame_Shape","Frame_Lookback"}) { 13 | flif_options options = FLIF_DEFAULT_OPTIONS; 14 | return flif_encode(io, images, transDesc, options); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/flif-mime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FLIF image 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/flif_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "config.h" 3 | #include "maniac/rac.hpp" 4 | 5 | #include "fileio.hpp" 6 | 7 | template using RacIn = RacInput24; 8 | 9 | #ifdef HAS_ENCODER 10 | template using RacOut = RacOutput24; 11 | #endif 12 | 13 | #include "maniac/compound.hpp" 14 | #ifdef FAST_BUT_WORSE_COMPRESSION 15 | typedef SimpleBitChance FLIFBitChanceMeta; 16 | #else 17 | typedef MultiscaleBitChance<6,SimpleBitChance> FLIFBitChanceMeta; 18 | #endif 19 | -------------------------------------------------------------------------------- /src/image/color_range.cpp: -------------------------------------------------------------------------------- 1 | #include "color_range.hpp" 2 | 3 | const ColorRanges *getRanges(const Image &image) { 4 | StaticColorRangeList ranges; 5 | for (int p = 0; p < image.numPlanes(); p++) { 6 | ranges.push_back(std::make_pair(image.min(p), image.max(p))); 7 | } 8 | return new StaticColorRanges(ranges); 9 | } 10 | 11 | const ColorRanges *getRanges(const ColorRanges *ranges) { 12 | return new DupColorRanges(ranges); 13 | } 14 | -------------------------------------------------------------------------------- /src/image/color_range.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "image.hpp" 6 | 7 | typedef std::vector prevPlanes; 8 | 9 | 10 | class ColorRanges 11 | { 12 | public: 13 | virtual ~ColorRanges() {}; 14 | virtual int numPlanes() const =0; 15 | virtual ColorVal min(int p) const =0; 16 | virtual ColorVal max(int p) const =0; 17 | virtual void minmax(const int p, const prevPlanes &, ColorVal &minv, ColorVal &maxv) const { minv=min(p); maxv=max(p); } 18 | virtual void snap(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv, ColorVal &v) const { 19 | minmax(p,pp,minv,maxv); 20 | if (minv > maxv) { //e_printf("Corruption detected!\n"); 21 | // this should only happen on malicious/corrupt input files, or while adding loss 22 | maxv=minv; 23 | } 24 | assert(minv <= maxv); 25 | if(v>maxv) v=maxv; 26 | if(v= minv); 29 | } 30 | virtual bool isStatic() const { return true; } 31 | virtual const ColorRanges* previous() const { return NULL; } 32 | }; 33 | 34 | typedef std::vector > StaticColorRangeList; 35 | 36 | class StaticColorRanges : public ColorRanges 37 | { 38 | protected: 39 | const StaticColorRangeList ranges; 40 | 41 | public: 42 | explicit StaticColorRanges(StaticColorRangeList &r) : ranges(r) {} 43 | int numPlanes() const override { return ranges.size(); } 44 | ColorVal min(int p) const override { if (p >= numPlanes()) return 0; assert(p= numPlanes()) return 0; assert(pnumPlanes(); } 57 | ColorVal min(int p) const override { return ranges->min(p); } 58 | ColorVal max(int p) const override { return ranges->max(p); } 59 | void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const override { ranges->minmax(p,pp,minv,maxv); } 60 | void snap(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv, ColorVal &v) const override { ranges->snap(p,pp,minv,maxv,v); } 61 | bool isStatic() const override { return ranges->isStatic(); } 62 | const ColorRanges* previous() const override { return ranges; } 63 | }; 64 | 65 | const ColorRanges *dupRanges(const ColorRanges *ranges); 66 | -------------------------------------------------------------------------------- /src/image/crc32k.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // define endianess and some integer data types 6 | #if defined(_MSC_VER) || defined(__MINGW32__) 7 | typedef unsigned __int8 uint8_t; 8 | typedef unsigned __int16 uint16_t; 9 | typedef unsigned __int32 uint32_t; 10 | typedef signed __int32 int32_t; 11 | 12 | #define __ORDER_BIG_ENDIAN__ 4321 13 | #define __ORDER_LITTLE_ENDIAN__ 1234 14 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ 15 | 16 | #include 17 | #ifdef __MINGW32__ 18 | #define PREFETCH(location) __builtin_prefetch(location) 19 | #else 20 | #define PREFETCH(location) _mm_prefetch(location, _MM_HINT_T0) 21 | #endif 22 | #else 23 | // uint8_t, uint32_t, in32_t 24 | #include 25 | // defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN 26 | #include 27 | 28 | #ifdef __GNUC__ 29 | #define PREFETCH(location) __builtin_prefetch(location) 30 | #else 31 | #define PREFETCH(location) ; 32 | #endif 33 | #endif 34 | 35 | 36 | /// zlib's CRC32 polynomial 37 | const uint32_t Polynomial = 0xEDB88320; 38 | 39 | /// swap endianess 40 | static inline uint32_t swap(uint32_t x) 41 | { 42 | #if defined(__GNUC__) || defined(__clang__) 43 | return __builtin_bswap32(x); 44 | #else 45 | return (x >> 24) | 46 | ((x >> 8) & 0x0000FF00) | 47 | ((x << 8) & 0x00FF0000) | 48 | (x << 24); 49 | #endif 50 | } 51 | 52 | /// swap endianess 53 | inline uint16_t swap16(uint16_t x) 54 | { 55 | #if defined(__GNUC__) || defined(__clang__) 56 | return __builtin_bswap16(x); 57 | #else 58 | return (x >> 8) | 59 | (x << 8); 60 | #endif 61 | } 62 | 63 | uint32_t crc32_fast(const void* data, size_t length, uint32_t previousCrc32 = 0); 64 | -------------------------------------------------------------------------------- /src/image/image-metadata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "image.hpp" 8 | 9 | #ifdef HAS_ENCODER 10 | 11 | 12 | bool image_load_metadata(const char *filename, Image& image, const char *chunkname) { 13 | FILE *fp = fopen(filename,"rb"); 14 | if (!fp) { 15 | e_printf("Could not open file: %s\n", filename); 16 | return false; 17 | } 18 | image.init(0, 0, 0, 0, 0); 19 | 20 | fseek(fp, 0, SEEK_END); 21 | long fsize = ftell(fp); 22 | fseek(fp, 0, SEEK_SET); 23 | 24 | std::vector contents(fsize + 1); 25 | if (!fread(contents.data(), fsize, 1, fp)) { 26 | e_printf("Could not read file: %s\n", filename); 27 | fclose(fp); 28 | return false; 29 | } 30 | fclose(fp); 31 | image.set_metadata(chunkname, contents.data(), fsize); 32 | return true; 33 | } 34 | #endif 35 | 36 | bool image_save_metadata(const char *filename, const Image& image, const char *chunkname) { 37 | unsigned char * contents; 38 | size_t length; 39 | if (image.get_metadata(chunkname, &contents, &length)) { 40 | FILE *fp = fopen(filename,"wb"); 41 | if (!fp) { 42 | return false; 43 | } 44 | fwrite((void *) contents, length, 1, fp); 45 | fclose(fp); 46 | free(contents); 47 | return true; 48 | } else { 49 | e_printf("Asking to write metadata of type %s to file %s, however no such metadata is present in the input file.\n", chunkname, filename); 50 | return false; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/image/image-metadata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.hpp" 4 | 5 | #ifdef HAS_ENCODER 6 | bool image_load_metadata(const char *filename, Image& image, const char *chunkname); 7 | #endif 8 | bool image_save_metadata(const char *filename, const Image& image, const char *chunkname); 9 | 10 | -------------------------------------------------------------------------------- /src/image/image-pam.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "image.hpp" 7 | #include "image-pam.hpp" 8 | #include "image-pnm.hpp" 9 | 10 | #define PPMREADBUFLEN 256 11 | 12 | #ifdef HAS_ENCODER 13 | bool image_load_pam(const char *filename, Image& image) { 14 | FILE *fp = fopen(filename,"rb"); 15 | char buf[PPMREADBUFLEN]; 16 | 17 | if (!fp) { 18 | return false; 19 | } 20 | if (!fgets(buf, PPMREADBUFLEN, fp)) { fclose(fp); return false; } 21 | int type=0; 22 | if ( (!strncmp(buf, "P7\n", 3)) ) type=7; 23 | if (type==0) { 24 | fclose(fp); 25 | if ( (!strncmp(buf, "P4", 2)) 26 | || (!strncmp(buf, "P5", 2)) 27 | || (!strncmp(buf, "P6", 2))) { 28 | return image_load_pnm(filename, image); 29 | } 30 | e_printf("PAM file is not of type P7, cannot read other types.\n"); 31 | return false; 32 | } 33 | return image_load_pam_fp(fp, image); 34 | } 35 | bool image_load_pam_fp(FILE *fp, Image& image) { 36 | char buf[PPMREADBUFLEN], *t; 37 | int maxlines=100; 38 | unsigned int width=0,height=0; 39 | unsigned int maxval=0; 40 | unsigned int depth = 0; 41 | do { 42 | t = fgets(buf, PPMREADBUFLEN, fp); 43 | if ( t == NULL ) { 44 | fclose(fp); 45 | return true; 46 | } 47 | /* Px formats can have # comments after first line */ 48 | if (strncmp(buf, "#", 1) == 0 || strncmp(buf, "\n", 1) == 0) 49 | continue; 50 | 51 | sscanf(buf, "WIDTH %u\n", &width); 52 | sscanf(buf, "HEIGHT %u\n", &height); 53 | sscanf(buf, "DEPTH %u\n", &depth); 54 | sscanf(buf, "MAXVAL %u\n", &maxval); 55 | 56 | if (maxlines-- < 1) { 57 | e_printf("Problem while parsing PAM header.\n"); 58 | fclose(fp); 59 | return false; 60 | } 61 | } while ( strncmp(buf, "ENDHDR", 6) != 0 ); 62 | if (depth>4 || depth <1 || width <1 || height < 1 || maxval<1 || maxval > 0xffff) { 63 | e_printf("Couldn't parse PAM header, or unsupported kind of PAM file.\n"); 64 | fclose(fp); 65 | return false; 66 | } 67 | 68 | #ifndef SUPPORT_HDR 69 | if (maxval > 0xff) { 70 | e_printf("PAM file has more than 8 bit per channel, this FLIF cannot handle that.\n"); 71 | fclose(fp); 72 | return false; 73 | } 74 | #endif 75 | 76 | unsigned int nbplanes=depth; 77 | image.init(width, height, 0, maxval, nbplanes); 78 | if (maxval > 0xff) { 79 | for (unsigned int y=0; y maxval) 91 | pixel = maxval; 92 | image.set(c,y,x, pixel); 93 | } 94 | } 95 | } 96 | } else { 97 | for (unsigned int y=0; y maxval) 107 | pixel = maxval; 108 | image.set(c,y,x, pixel); 109 | } 110 | } 111 | } 112 | } 113 | 114 | if (fp!=stdin) fclose(fp); 115 | return true; 116 | } 117 | #endif 118 | 119 | bool image_save_pam(const char *filename, const Image& image) 120 | { 121 | if (image.numPlanes() < 4) return image_save_pnm(filename, image); 122 | FILE *fp = NULL; 123 | if (!strcmp(filename,"-")) fp = stdout; 124 | else fp = fopen(filename,"wb"); 125 | if (!fp) { 126 | return false; 127 | } 128 | 129 | ColorVal max = image.max(0); 130 | 131 | if (max > 0xffff) { 132 | e_printf("Cannot store as PAM. Find out why.\n"); 133 | fclose(fp); 134 | return false; 135 | } 136 | unsigned int height = image.rows(), width = image.cols(); 137 | fprintf(fp,"P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL %i\nTUPLTYPE RGB_ALPHA\nENDHDR\n", width, height, max); 138 | 139 | 140 | // experiment: output RGBA pixels in FLIF's Adam-infinity interlaced order 141 | /* 142 | fputc(image(0,0,0) & 0xFF,fp); 143 | fputc(image(1,0,0) & 0xFF,fp); 144 | fputc(image(2,0,0) & 0xFF,fp); 145 | fputc(image(3,0,0) & 0xFF,fp); 146 | 147 | for (int z = image.zooms(); z >= 0; z--) { 148 | if (z % 2 == 0) { 149 | for (uint32_t y = 1; y < image.rows(z); y += 2) { 150 | for (uint32_t x = 0; x < image.cols(z); x++) { 151 | if (max > 0xff) fputc(image(0,z,y,x) >> 8,fp); 152 | fputc(image(0,z,y,x) & 0xFF,fp); 153 | if (max > 0xff) fputc(image(1,z,y,x) >> 8,fp); 154 | fputc(image(1,z,y,x) & 0xFF,fp); 155 | if (max > 0xff) fputc(image(2,z,y,x) >> 8,fp); 156 | fputc(image(2,z,y,x) & 0xFF,fp); 157 | if (max > 0xff) fputc(image(3,z,y,x) >> 8,fp); 158 | fputc(image(3,z,y,x) & 0xFF,fp); 159 | } 160 | } 161 | } else { 162 | for (uint32_t y = 0; y < image.rows(z); y++) { 163 | for (uint32_t x = 1; x < image.cols(z); x += 2) { 164 | if (max > 0xff) fputc(image(0,z,y,x) >> 8,fp); 165 | fputc(image(0,z,y,x) & 0xFF,fp); 166 | if (max > 0xff) fputc(image(1,z,y,x) >> 8,fp); 167 | fputc(image(1,z,y,x) & 0xFF,fp); 168 | if (max > 0xff) fputc(image(2,z,y,x) >> 8,fp); 169 | fputc(image(2,z,y,x) & 0xFF,fp); 170 | if (max > 0xff) fputc(image(3,z,y,x) >> 8,fp); 171 | fputc(image(3,z,y,x) & 0xFF,fp); 172 | } 173 | } 174 | } 175 | } 176 | */ 177 | 178 | 179 | for (unsigned int y = 0; y < height; y++) { 180 | for (unsigned int x = 0; x < width; x++) { 181 | if (max > 0xff) fputc(image(0,y,x) >> 8,fp); 182 | fputc(image(0,y,x) & 0xFF,fp); 183 | if (max > 0xff) fputc(image(1,y,x) >> 8,fp); 184 | fputc(image(1,y,x) & 0xFF,fp); 185 | if (max > 0xff) fputc(image(2,y,x) >> 8,fp); 186 | fputc(image(2,y,x) & 0xFF,fp); 187 | if (max > 0xff) fputc(image(3,y,x) >> 8,fp); 188 | fputc(image(3,y,x) & 0xFF,fp); 189 | } 190 | } 191 | 192 | // if (fp != stdout) fclose(fp); 193 | if (image.get_metadata("iCCP")) { 194 | v_printf(1,"Warning: input image has color profile, which cannot be stored in output image format.\n"); 195 | } 196 | fclose(fp); 197 | return true; 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/image/image-pam.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.hpp" 4 | 5 | #ifdef HAS_ENCODER 6 | bool image_load_pam(const char *filename, Image& image); 7 | bool image_load_pam_fp(FILE *fp, Image& image); 8 | #endif 9 | bool image_save_pam(const char *filename, const Image& image); 10 | -------------------------------------------------------------------------------- /src/image/image-png-metadata.hpp: -------------------------------------------------------------------------------- 1 | // This bit of code is based from some code from libwebp 0.5.0 (specifically from examples/pngdec.c) 2 | // It is BSD-licensed 3 | 4 | 5 | // Converts the NULL terminated 'hexstring' which contains 2-byte character 6 | // representations of hex values to raw data. 7 | // 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, 8 | // e.g., 7af2..., separated by any number of newlines. 9 | // 'expected_length' is the anticipated processed size. 10 | // On success the raw buffer is returned with its length equivalent to 11 | // 'expected_length'. NULL is returned if the processed length is less than 12 | // 'expected_length' or any character aside from those above is encountered. 13 | // The returned buffer must be freed by the caller. 14 | static unsigned char* HexStringToBytes(const char* hexstring, 15 | size_t expected_length) { 16 | const char* src = hexstring; 17 | size_t actual_length = 0; 18 | unsigned char* const raw_data = (unsigned char*)malloc(expected_length); 19 | unsigned char* dst; 20 | 21 | if (raw_data == NULL) return NULL; 22 | 23 | for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) { 24 | char* end; 25 | char val[3]; 26 | if (*src == '\n') continue; 27 | val[0] = *src++; 28 | val[1] = *src; 29 | val[2] = '\0'; 30 | *dst++ = (uint8_t)strtol(val, &end, 16); 31 | if (end != val + 2) break; 32 | ++actual_length; 33 | } 34 | 35 | if (actual_length != expected_length) { 36 | free(raw_data); 37 | return NULL; 38 | } 39 | return raw_data; 40 | } 41 | 42 | static int ProcessRawProfile(const char* profile, size_t profile_len, 43 | unsigned char ** payload, size_t* payload_len) { 44 | const char* src = profile; 45 | char* end; 46 | int expected_length; 47 | 48 | if (profile == NULL || profile_len == 0) return 0; 49 | 50 | // ImageMagick formats 'raw profiles' as 51 | // '\n\n(%8lu)\n\n'. 52 | if (*src != '\n') { 53 | fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", 54 | *src); 55 | return 0; 56 | } 57 | ++src; 58 | // skip the profile name and extract the length. 59 | while (*src != '\0' && *src++ != '\n') {} 60 | expected_length = (int)strtol(src, &end, 10); 61 | if (*end != '\n') { 62 | fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", 63 | *end); 64 | return 0; 65 | } 66 | ++end; 67 | 68 | // 'end' now points to the profile payload. 69 | *payload = HexStringToBytes(end, expected_length); 70 | *payload_len = expected_length; 71 | if (*payload == NULL) return 0; 72 | return 1; 73 | } -------------------------------------------------------------------------------- /src/image/image-png.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.hpp" 4 | 5 | #ifdef HAS_ENCODER 6 | int image_load_png(const char *filename, Image &image, metadata_options &md); 7 | #endif 8 | int image_save_png(const char *filename, const Image &image); 9 | -------------------------------------------------------------------------------- /src/image/image-pnm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "image.hpp" 7 | #include "image-pnm.hpp" 8 | #include "image-pam.hpp" 9 | 10 | #define PPMREADBUFLEN 256 11 | 12 | #ifdef HAS_ENCODER 13 | 14 | // auxiliary function to read a non-zero number from a PNM header, ignoring whitespace and comments 15 | unsigned int read_pnm_int(FILE *fp, char* buf, char** t) { 16 | long result = strtol(*t,t,10); 17 | if (result == 0) { 18 | // no valid int found here, try next line 19 | do { 20 | *t = fgets(buf, PPMREADBUFLEN, fp); 21 | if ( *t == NULL ) {return false;} 22 | } while ( strncmp(buf, "#", 1) == 0 || strncmp(buf, "\n", 1) == 0); 23 | result = strtol(*t,t,10); 24 | if (result == 0) { e_printf("Invalid PNM file.\n"); fclose(fp); } 25 | } 26 | return result; 27 | } 28 | 29 | bool image_load_pnm(const char *filename, Image& image) { 30 | FILE *fp = NULL; 31 | if (!strcmp(filename,"-")) fp = stdin; 32 | else fp = fopen(filename,"rb"); 33 | 34 | char buf[PPMREADBUFLEN], *t; 35 | if (!fp) { 36 | e_printf("Could not open file: %s\n", filename); 37 | return false; 38 | } 39 | unsigned int width=0,height=0; 40 | unsigned int maxval=0; 41 | do { 42 | /* # comments before the first line */ 43 | t = fgets(buf, PPMREADBUFLEN, fp); 44 | if ( t == NULL ) return false; 45 | } while ( strncmp(buf, "#", 1) == 0 || strncmp(buf, "\n", 1) == 0); 46 | int type=0; 47 | if ( (!strncmp(buf, "P4", 2)) ) type=4; 48 | if ( (!strncmp(buf, "P5", 2)) ) type=5; 49 | if ( (!strncmp(buf, "P6", 2)) ) type=6; 50 | if ( (!strncmp(buf, "P7", 2)) ) {return image_load_pam_fp(fp, image);} 51 | if (type==0) { 52 | if (buf[0] == 'P') e_printf("PNM file is not of type P4, P5, P6 or P7, cannot read other types.\n"); 53 | else e_printf("This does not look like a PNM file.\n"); 54 | fclose(fp); 55 | return false; 56 | } 57 | t += 2; 58 | if (!(width = read_pnm_int(fp,buf,&t))) return false; 59 | if (!(height = read_pnm_int(fp,buf,&t))) return false; 60 | if (type>4) { 61 | if (!(maxval = read_pnm_int(fp,buf,&t))) return false; 62 | if ( maxval > 0xffff ) { 63 | e_printf("Invalid PNM file (more than 16-bit?)\n"); 64 | fclose(fp); 65 | return false; 66 | } 67 | } else maxval=1; 68 | #ifndef SUPPORT_HDR 69 | if (maxval > 0xff) { 70 | e_printf("PNM file has more than 8 bit per channel, this FLIF cannot handle that.\n"); 71 | return false; 72 | } 73 | #endif 74 | unsigned int nbplanes=(type==6?3:1); 75 | image.init(width, height, 0, maxval, nbplanes); 76 | if (type==4) { 77 | char byte=0; 78 | for (unsigned int y=0; y>(x%8)) ? 0 : 1)); 82 | } 83 | } 84 | } else { 85 | if (maxval > 0xff) { 86 | for (unsigned int y=0; y (int)maxval) { 92 | fclose(fp); 93 | e_printf("Invalid PNM file: value %i is larger than declared maxval %u\n", pixel, maxval); 94 | return false; 95 | } 96 | image.set(c,y,x, pixel); 97 | } 98 | } 99 | } 100 | } else { 101 | for (unsigned int y=0; y= 3) { 125 | if (image.numPlanes() == 4 && image.uses_alpha()) 126 | v_printf(1,"WARNING: image has alpha channel, saving to flat PPM! Use .png or .pam if you want to keep the alpha channel!\n"); 127 | ColorVal max = image.max(0); 128 | 129 | if (max > 0xffff) { 130 | e_printf("Cannot store as PNM. Find out why.\n"); 131 | fclose(fp); 132 | return false; 133 | } 134 | 135 | unsigned int height = image.rows(), width = image.cols(); 136 | fprintf(fp,"P6\n%u %u\n%i\n", width, height, max); 137 | for (unsigned int y = 0; y < height; y++) { 138 | for (unsigned int x = 0; x < width; x++) { 139 | if (max > 0xff) fputc(image(0,y,x) >> 8,fp); 140 | fputc(image(0,y,x) & 0xFF,fp); 141 | if (max > 0xff) fputc(image(1,y,x) >> 8,fp); 142 | fputc(image(1,y,x) & 0xFF,fp); 143 | if (max > 0xff) fputc(image(2,y,x) >> 8,fp); 144 | fputc(image(2,y,x) & 0xFF,fp); 145 | } 146 | } 147 | } else if (image.numPlanes() == 1) { 148 | ColorVal max = image.max(0); 149 | 150 | if (max > 0xffff) { 151 | e_printf("Cannot store as PNM. Find out why.\n"); 152 | fclose(fp); 153 | return false; 154 | } 155 | 156 | unsigned int height = image.rows(), width = image.cols(); 157 | fprintf(fp,"P5\n%u %u\n%i\n", width, height, max); 158 | for (unsigned int y = 0; y < height; y++) { 159 | for (unsigned int x = 0; x < width; x++) { 160 | if (max > 0xff) fputc(image(0,y,x) >> 8,fp); 161 | fputc(image(0,y,x) & 0xFF,fp); 162 | } 163 | } 164 | } else { 165 | e_printf("Cannot store as PNM. Find out why.\n"); 166 | fclose(fp); 167 | return false; 168 | } 169 | // if (fp != stdout) fclose(fp); 170 | if (image.get_metadata("iCCP")) { 171 | v_printf(1,"Warning: input image has color profile, which cannot be stored in output image format.\n"); 172 | } 173 | fclose(fp); 174 | return true; 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/image/image-pnm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.hpp" 4 | 5 | #ifdef HAS_ENCODER 6 | bool image_load_pnm(const char *filename, Image& image); 7 | #endif 8 | bool image_save_pnm(const char *filename, const Image& image); 9 | -------------------------------------------------------------------------------- /src/image/image-rggb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.hpp" 4 | 5 | #ifdef HAS_ENCODER 6 | bool image_load_rggb(const char *filename, Image& image, metadata_options &md); 7 | #endif 8 | bool image_save_rggb(const char *filename, const Image& image); 9 | -------------------------------------------------------------------------------- /src/image/image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "image.hpp" 4 | #include "image-png.hpp" 5 | #include "image-pnm.hpp" 6 | #include "image-pam.hpp" 7 | #include "image-rggb.hpp" 8 | #include "image-metadata.hpp" 9 | 10 | #ifdef _MSC_VER 11 | #define strcasecmp _stricmp 12 | #endif 13 | 14 | #ifdef HAS_ENCODER 15 | bool Image::load(const char *filename, metadata_options &options) 16 | { 17 | if (!strcmp(filename,"-")) { 18 | v_printf(2,"Reading input as PAM/PPM from standard input. "); 19 | return image_load_pnm(filename,*this); 20 | } 21 | const char *f = strrchr(filename,'/'); 22 | const char *ext = f ? strrchr(f,'.') : strrchr(filename,'.'); 23 | v_printf(2,"Loading input file: %s ",filename); 24 | if (ext && !strcasecmp(ext,".png")) { 25 | return !image_load_png(filename,*this,options); 26 | } 27 | if (ext && !strcasecmp(ext,".pnm")) { 28 | return image_load_pnm(filename,*this); 29 | } 30 | if (ext && !strcasecmp(ext,".pbm")) { 31 | return image_load_pnm(filename,*this); 32 | } 33 | if (ext && !strcasecmp(ext,".pgm")) { 34 | return image_load_pnm(filename,*this); 35 | } 36 | if (ext && !strcasecmp(ext,".ppm")) { 37 | return image_load_pnm(filename,*this); 38 | } 39 | if (ext && !strcasecmp(ext,".pam")) { 40 | return image_load_pam(filename,*this); 41 | } 42 | if (ext && !strcasecmp(ext,".rggb")) { 43 | return image_load_rggb(filename,*this, options); 44 | } 45 | if (ext && !strcasecmp(ext,".icc")) { 46 | return image_load_metadata(filename,*this,"iCCP"); 47 | } 48 | if (ext && !strcasecmp(ext,".xmp")) { 49 | return image_load_metadata(filename,*this,"eXmp"); 50 | } 51 | if (ext && !strcasecmp(ext,".exif")) { 52 | return image_load_metadata(filename,*this,"eXif"); 53 | } 54 | if (image_load_pnm(filename,*this) || !image_load_png(filename,*this,options)) return true; 55 | e_printf("ERROR: Unknown input file type to read from: %s\n",ext ? ext : "(none)"); 56 | return false; 57 | } 58 | #endif 59 | 60 | bool Image::save(const char *filename) const 61 | { 62 | if (!strcmp(filename,"-")) { 63 | v_printf(2,"Writing output as PAM to standard output. "); 64 | return image_save_pam(filename,*this); 65 | } 66 | const char *f = strrchr(filename,'/'); 67 | const char *ext = f ? strrchr(f,'.') : strrchr(filename,'.'); 68 | v_printf(2,"Saving output file: %s ",filename); 69 | if (ext && !strcasecmp(ext,".png")) { 70 | return !image_save_png(filename,*this); 71 | } 72 | if (ext && !strcasecmp(ext,".pnm")) { 73 | return image_save_pnm(filename,*this); 74 | } 75 | if (ext && !strcasecmp(ext,".pgm")) { 76 | return image_save_pnm(filename,*this); 77 | } 78 | if (ext && !strcasecmp(ext,".ppm")) { 79 | return image_save_pnm(filename,*this); 80 | } 81 | if (ext && !strcasecmp(ext,".pam")) { 82 | return image_save_pam(filename,*this); 83 | } 84 | if (ext && !strcasecmp(ext,".rggb")) { 85 | return image_save_rggb(filename,*this); 86 | } 87 | if (ext && !strcasecmp(ext,".icc")) { 88 | return image_save_metadata(filename,*this,"iCCP"); 89 | } 90 | if (ext && !strcasecmp(ext,".xmp")) { 91 | return image_save_metadata(filename,*this,"eXmp"); 92 | } 93 | if (ext && !strcasecmp(ext,".exif")) { 94 | return image_save_metadata(filename,*this,"eXif"); 95 | } 96 | e_printf("ERROR: Unknown extension to write to: %s\n",ext ? ext : "(none)"); 97 | return false; 98 | } 99 | -------------------------------------------------------------------------------- /src/io.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #ifdef _WIN32 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "io.hpp" 28 | 29 | void e_printf(const char *format, ...) { 30 | va_list args; 31 | va_start(args, format); 32 | vfprintf(stderr, format, args); 33 | fflush(stderr); 34 | va_end(args); 35 | } 36 | 37 | #ifdef DEBUG 38 | static int verbosity = 10; 39 | #else 40 | static int verbosity = 1; 41 | #endif 42 | static FILE * my_stdout = stdout; 43 | void increase_verbosity(int how_much) { 44 | verbosity += how_much; 45 | } 46 | 47 | int get_verbosity() { 48 | return verbosity; 49 | } 50 | 51 | void v_printf(const int v, const char *format, ...) { 52 | if (verbosity < v) return; 53 | va_list args; 54 | va_start(args, format); 55 | vfprintf(my_stdout, format, args); 56 | fflush(my_stdout); 57 | va_end(args); 58 | } 59 | 60 | void v_printf_tty(const int v, const char *format, ...) { 61 | if (verbosity < v) return; 62 | #ifdef _WIN32 63 | if(!_isatty(_fileno(my_stdout))) return; 64 | #else 65 | if(!isatty(fileno(my_stdout))) return; 66 | #endif 67 | va_list args; 68 | va_start(args, format); 69 | vfprintf(my_stdout, format, args); 70 | fflush(my_stdout); 71 | va_end(args); 72 | } 73 | 74 | void redirect_stdout_to_stderr() { 75 | my_stdout = stderr; 76 | } 77 | -------------------------------------------------------------------------------- /src/io.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | void e_printf(const char *format, ...); 22 | void v_printf(const int v, const char *format, ...); 23 | void v_printf_tty(const int v, const char *format, ...); 24 | void redirect_stdout_to_stderr(); 25 | 26 | void increase_verbosity(int how_much=1); 27 | int get_verbosity(); 28 | 29 | template 30 | bool ioget_int_8bit (IO& io, int* result) 31 | { 32 | int c = io.get_c(); 33 | if (c == io.EOS) { 34 | e_printf ("Unexpected EOS"); 35 | return false; 36 | } 37 | 38 | *result = c; 39 | return true; 40 | } 41 | 42 | template 43 | bool ioget_int_16bit_bigendian (IO& io, int* result) 44 | { 45 | int c1; 46 | int c2; 47 | if (!(ioget_int_8bit (io, &c1) && 48 | ioget_int_8bit (io, &c2))) 49 | return false; 50 | 51 | *result = (c1 << 8) + c2; 52 | return true; 53 | } 54 | -------------------------------------------------------------------------------- /src/library/flif-interface-private.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flif-interface-private_enc.hpp" 4 | #include "flif-interface-private_dec.hpp" 5 | -------------------------------------------------------------------------------- /src/library/flif-interface-private_common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "flif_common.h" 22 | 23 | #include "../image/image.hpp" 24 | #include "../fileio.hpp" 25 | 26 | #ifdef _WIN32 27 | #ifdef FLIF_BUILD_DLL 28 | #define FLIF_DLLEXPORT __declspec(dllexport) 29 | #else 30 | #define FLIF_DLLEXPORT 31 | #endif 32 | #else 33 | #define FLIF_DLLEXPORT __attribute__ ((visibility ("default"))) 34 | #endif 35 | 36 | struct FLIF_IMAGE 37 | { 38 | FLIF_IMAGE(); 39 | 40 | void write_row_RGBA8(uint32_t row, const void* buffer, size_t buffer_size_bytes); 41 | void read_row_RGBA8(uint32_t row, void* buffer, size_t buffer_size_bytes); 42 | 43 | void write_row_RGBA16(uint32_t row, const void* buffer, size_t buffer_size_bytes); 44 | void read_row_RGBA16(uint32_t row, void* buffer, size_t buffer_size_bytes); 45 | 46 | void write_row_RGB8(uint32_t row, const void* buffer, size_t buffer_size_bytes); 47 | void write_row_GRAY8(uint32_t row, const void* buffer, size_t buffer_size_bytes); 48 | void read_row_GRAY8(uint32_t row, void* buffer, size_t buffer_size_bytes); 49 | void write_row_GRAY16(uint32_t row, const void* buffer, size_t buffer_size_bytes); 50 | void read_row_GRAY16(uint32_t row, void* buffer, size_t buffer_size_bytes); 51 | void write_row_PALETTE8(uint32_t row, const void* buffer, size_t buffer_size_bytes); 52 | void read_row_PALETTE8(uint32_t row, void* buffer, size_t buffer_size_bytes); 53 | 54 | Image image; 55 | }; 56 | -------------------------------------------------------------------------------- /src/library/flif-interface-private_dec.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | #include "flif-interface-private_common.hpp" 24 | #include "../flif-dec.hpp" 25 | 26 | struct FLIF_DECODER 27 | { 28 | FLIF_DECODER(); 29 | 30 | int32_t decode_file(const char* filename); 31 | int32_t decode_filepointer(FILE *file, const char* filename); 32 | int32_t decode_memory(const void* buffer, size_t buffer_size_bytes); 33 | int32_t abort(); 34 | size_t num_images(); 35 | int32_t num_loops(); 36 | FLIF_IMAGE* get_image(size_t index); 37 | 38 | flif_options options; 39 | void* callback; 40 | void* user_data; 41 | int32_t first_quality; 42 | ~FLIF_DECODER() { 43 | // get rid of palettes 44 | if (internal_images.size()) internal_images[0].clear(); 45 | if (images.size()) images[0].clear(); 46 | } 47 | 48 | private: 49 | Images internal_images; 50 | Images images; 51 | std::vector> requested_images; 52 | bool working; 53 | }; 54 | -------------------------------------------------------------------------------- /src/library/flif-interface-private_enc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF encoder - Free Lossless Image Format 3 | Copyright (C) 2010-2015 Jon Sneyers & Pieter Wuille, LGPL v3+ 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "flif-interface-private_common.hpp" 22 | #include "../flif-enc.hpp" 23 | 24 | struct FLIF_ENCODER 25 | { 26 | FLIF_ENCODER(); 27 | 28 | void add_image(FLIF_IMAGE* image); 29 | void add_image_move(FLIF_IMAGE* image); 30 | void set_alpha_zero_flags(); 31 | int32_t encode_file(const char* filename); 32 | int32_t encode_memory(void** buffer, size_t* buffer_size_bytes); 33 | 34 | flif_options options; 35 | 36 | ~FLIF_ENCODER() { 37 | // get rid of palette 38 | if (images.size()) images[0].clear(); 39 | } 40 | 41 | 42 | private: 43 | void transformations(std::vector &desc); 44 | void set_options(flif_options &options); 45 | std::vector images; 46 | }; 47 | -------------------------------------------------------------------------------- /src/library/flif-interface.cpp: -------------------------------------------------------------------------------- 1 | #include "flif-interface_dec.cpp" 2 | #ifdef HAS_ENCODER 3 | #include "flif-interface_enc.cpp" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/library/flif.h: -------------------------------------------------------------------------------- 1 | #ifndef FLIF_INTERFACE_H 2 | #define FLIF_INTERFACE_H 3 | 4 | /* 5 | FLIF - Free Lossless Image Format 6 | Copyright (C) 2010-2015 Jon Sneyers & Pieter Wuille, LGPL v3+ 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU Lesser General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include "flif_dec.h" 23 | #include "flif_enc.h" 24 | 25 | // libflif version 0.2.0 26 | #define FLIF_VERSION ((0 << 16) | (0 << 8) | 2) 27 | #define FLIF_ABI_VERSION 0 28 | 29 | #endif // FLIF_INTERFACE_H 30 | -------------------------------------------------------------------------------- /src/library/flif_common.h: -------------------------------------------------------------------------------- 1 | #ifndef FLIF_INTERFACE_COMMON_H 2 | #define FLIF_INTERFACE_COMMON_H 3 | 4 | /* 5 | FLIF - Free Lossless Image Format 6 | 7 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #ifdef _WIN32 26 | #define FLIF_API __cdecl 27 | #ifdef FLIF_BUILD_DLL 28 | #define FLIF_DLLIMPORT __declspec(dllexport) 29 | #elif FLIF_USE_DLL 30 | #define FLIF_DLLIMPORT __declspec(dllimport) 31 | #endif 32 | #else 33 | #define FLIF_API 34 | #endif 35 | 36 | #ifndef FLIF_DLLIMPORT 37 | #define FLIF_DLLIMPORT 38 | #endif 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif // __cplusplus 43 | 44 | typedef struct FLIF_IMAGE FLIF_IMAGE; 45 | 46 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image(uint32_t width, uint32_t height); // RGBA 47 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image_RGB(uint32_t width, uint32_t height); 48 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image_GRAY(uint32_t width, uint32_t height); 49 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image_GRAY16(uint32_t width, uint32_t height); 50 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image_PALETTE(uint32_t width, uint32_t height); 51 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_create_image_HDR(uint32_t width, uint32_t height); 52 | 53 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_import_image_RGBA(uint32_t width, uint32_t height, const void* rgba, uint32_t rgba_stride); 54 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_import_image_RGB(uint32_t width, uint32_t height, const void* rgb, uint32_t rgb_stride); 55 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_import_image_GRAY(uint32_t width, uint32_t height, const void* gray, uint32_t gray_stride); 56 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_import_image_GRAY16(uint32_t width, uint32_t height, const void* gray, uint32_t gray_stride); 57 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_import_image_PALETTE(uint32_t width, uint32_t height, const void* gray, uint32_t gray_stride); 58 | FLIF_DLLIMPORT void FLIF_API flif_destroy_image(FLIF_IMAGE* image); 59 | 60 | FLIF_DLLIMPORT uint32_t FLIF_API flif_image_get_width(FLIF_IMAGE* image); 61 | FLIF_DLLIMPORT uint32_t FLIF_API flif_image_get_height(FLIF_IMAGE* image); 62 | FLIF_DLLIMPORT uint8_t FLIF_API flif_image_get_nb_channels(FLIF_IMAGE* image); 63 | FLIF_DLLIMPORT uint8_t FLIF_API flif_image_get_depth(FLIF_IMAGE* image); 64 | FLIF_DLLIMPORT uint32_t FLIF_API flif_image_get_palette_size(FLIF_IMAGE* image); // 0 = no palette, 1-256 = nb of colors in palette 65 | FLIF_DLLIMPORT void FLIF_API flif_image_get_palette(FLIF_IMAGE* image, void* buffer); // puts RGBA colors in buffer (4*palette_size bytes) 66 | FLIF_DLLIMPORT void FLIF_API flif_image_set_palette(FLIF_IMAGE* image, const void* buffer, uint32_t palette_size); // puts RGBA colors in buffer (4*palette_size bytes) 67 | FLIF_DLLIMPORT uint32_t FLIF_API flif_image_get_frame_delay(FLIF_IMAGE* image); 68 | FLIF_DLLIMPORT void FLIF_API flif_image_set_frame_delay(FLIF_IMAGE* image, uint32_t delay); 69 | 70 | FLIF_DLLIMPORT void FLIF_API flif_image_set_metadata(FLIF_IMAGE* image, const char* chunkname, const unsigned char* data, size_t length); 71 | FLIF_DLLIMPORT uint8_t FLIF_API flif_image_get_metadata(FLIF_IMAGE* image, const char* chunkname, unsigned char** data, size_t* length); 72 | FLIF_DLLIMPORT void FLIF_API flif_image_free_metadata(FLIF_IMAGE* image, unsigned char* data); 73 | 74 | FLIF_DLLIMPORT void FLIF_API flif_image_write_row_PALETTE8(FLIF_IMAGE* image, uint32_t row, const void* buffer, size_t buffer_size_bytes); 75 | FLIF_DLLIMPORT void FLIF_API flif_image_read_row_PALETTE8(FLIF_IMAGE* image, uint32_t row, void* buffer, size_t buffer_size_bytes); 76 | 77 | FLIF_DLLIMPORT void FLIF_API flif_image_write_row_GRAY8(FLIF_IMAGE* image, uint32_t row, const void* buffer, size_t buffer_size_bytes); 78 | FLIF_DLLIMPORT void FLIF_API flif_image_read_row_GRAY8(FLIF_IMAGE* image, uint32_t row, void* buffer, size_t buffer_size_bytes); 79 | 80 | FLIF_DLLIMPORT void FLIF_API flif_image_write_row_GRAY16(FLIF_IMAGE* image, uint32_t row, const void* buffer, size_t buffer_size_bytes); 81 | FLIF_DLLIMPORT void FLIF_API flif_image_read_row_GRAY16(FLIF_IMAGE* image, uint32_t row, void* buffer, size_t buffer_size_bytes); 82 | 83 | FLIF_DLLIMPORT void FLIF_API flif_image_write_row_RGBA8(FLIF_IMAGE* image, uint32_t row, const void* buffer, size_t buffer_size_bytes); 84 | FLIF_DLLIMPORT void FLIF_API flif_image_read_row_RGBA8(FLIF_IMAGE* image, uint32_t row, void* buffer, size_t buffer_size_bytes); 85 | 86 | FLIF_DLLIMPORT void FLIF_API flif_image_write_row_RGBA16(FLIF_IMAGE* image, uint32_t row, const void* buffer, size_t buffer_size_bytes); 87 | FLIF_DLLIMPORT void FLIF_API flif_image_read_row_RGBA16(FLIF_IMAGE* image, uint32_t row, void* buffer, size_t buffer_size_bytes); 88 | 89 | FLIF_DLLIMPORT void FLIF_API flif_free_memory(void* buffer); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif // __cplusplus 94 | 95 | #endif // FLIF_INTERFACE_COMMON_H 96 | -------------------------------------------------------------------------------- /src/library/flif_dec.h: -------------------------------------------------------------------------------- 1 | #ifndef FLIF_INTERFACE_DEC_H 2 | #define FLIF_INTERFACE_DEC_H 3 | 4 | /* 5 | FLIF - Free Lossless Image Format 6 | 7 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | */ 21 | 22 | #include 23 | 24 | #include "flif_common.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif // __cplusplus 29 | 30 | typedef uint32_t (*callback_t)(uint32_t quality, int64_t bytes_read, uint8_t decode_over, void *user_data, void *context); 31 | 32 | typedef struct FLIF_DECODER FLIF_DECODER; 33 | typedef struct FLIF_INFO FLIF_INFO; 34 | 35 | // initialize a FLIF decoder 36 | FLIF_DLLIMPORT FLIF_DECODER* FLIF_API flif_create_decoder(); 37 | 38 | // decode a given FLIF file 39 | FLIF_DLLIMPORT int32_t FLIF_API flif_decoder_decode_file(FLIF_DECODER* decoder, const char* filename); 40 | // decode a FLIF blob in memory: buffer should point to the blob and buffer_size_bytes should be its size 41 | FLIF_DLLIMPORT int32_t FLIF_API flif_decoder_decode_memory(FLIF_DECODER* decoder, const void* buffer, size_t buffer_size_bytes); 42 | 43 | /* 44 | * Decode a given FLIF from a file pointer 45 | * The filename here is used for error messages. 46 | * It would be helpful to pass an actual filename here, but a non-NULL dummy one can be used instead. 47 | */ 48 | FLIF_DLLIMPORT int32_t FLIF_API flif_decoder_decode_filepointer(FLIF_DECODER* decoder, FILE *filepointer, const char *filename); 49 | 50 | // returns the number of frames (1 if it is not an animation) 51 | FLIF_DLLIMPORT size_t FLIF_API flif_decoder_num_images(FLIF_DECODER* decoder); 52 | // only relevant for animations: returns the loop count (0 = loop forever) 53 | FLIF_DLLIMPORT int32_t FLIF_API flif_decoder_num_loops(FLIF_DECODER* decoder); 54 | // returns a pointer to a given frame, counting from 0 (use index=0 for still images) 55 | FLIF_DLLIMPORT FLIF_IMAGE* FLIF_API flif_decoder_get_image(FLIF_DECODER* decoder, size_t index); 56 | 57 | FLIF_DLLIMPORT void FLIF_API flif_decoder_generate_preview(void *context); 58 | 59 | // release an decoder (has to be called after decoding is done, to avoid memory leaks) 60 | FLIF_DLLIMPORT void FLIF_API flif_destroy_decoder(FLIF_DECODER* decoder); 61 | // abort a decoder (can be used before decoding is completed) 62 | FLIF_DLLIMPORT int32_t FLIF_API flif_abort_decoder(FLIF_DECODER* decoder); 63 | 64 | // decode options, all optional, can be set after decoder initialization and before actual decoding 65 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_crc_check(FLIF_DECODER* decoder, int32_t crc_check); // default: no (0) 66 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_quality(FLIF_DECODER* decoder, int32_t quality); // valid quality: 0-100 67 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_scale(FLIF_DECODER* decoder, uint32_t scale); // valid scales: 1,2,4,8,16,... 68 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_resize(FLIF_DECODER* decoder, uint32_t width, uint32_t height); 69 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_fit(FLIF_DECODER* decoder, uint32_t width, uint32_t height); 70 | 71 | // Progressive decoding: set a callback function. The callback will be called after a certain quality is reached, 72 | // and it should return the desired next quality that should be reached before it will be called again. 73 | // The qualities are expressed on a scale from 0 to 10000 (not 0 to 100!) for fine-grained control. 74 | // `user_data` can be NULL or a pointer to any user-defined context. The decoder doesn't care about its contents; 75 | // it just passes the pointer value back to the callback. 76 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_callback(FLIF_DECODER* decoder, callback_t callback, void *user_data); 77 | FLIF_DLLIMPORT void FLIF_API flif_decoder_set_first_callback_quality(FLIF_DECODER* decoder, int32_t quality); // valid quality: 0-10000 78 | 79 | // Reads the header of a FLIF file and packages it as a FLIF_INFO struct. 80 | // May return a null pointer if the file is not in the right format. 81 | // The caller takes ownership of the return value and must call flif_destroy_info(). 82 | FLIF_DLLIMPORT FLIF_INFO* FLIF_API flif_read_info_from_memory(const void* buffer, size_t buffer_size_bytes); 83 | // deallocator function for FLIF_INFO 84 | FLIF_DLLIMPORT void FLIF_API flif_destroy_info(FLIF_INFO* info); 85 | 86 | // get the image width 87 | FLIF_DLLIMPORT uint32_t FLIF_API flif_info_get_width(FLIF_INFO* info); 88 | // get the image height 89 | FLIF_DLLIMPORT uint32_t FLIF_API flif_info_get_height(FLIF_INFO* info); 90 | // get the number of color channels 91 | FLIF_DLLIMPORT uint8_t FLIF_API flif_info_get_nb_channels(FLIF_INFO* info); 92 | // get the number of bits per channel 93 | FLIF_DLLIMPORT uint8_t FLIF_API flif_info_get_depth(FLIF_INFO* info); 94 | // get the number of animation frames 95 | FLIF_DLLIMPORT size_t FLIF_API flif_info_num_images(FLIF_INFO* info); 96 | 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif // __cplusplus 101 | 102 | #endif // FLIF_INTERFACE_DEC_H 103 | -------------------------------------------------------------------------------- /src/library/flif_enc.h: -------------------------------------------------------------------------------- 1 | #ifndef FLIF_INTERFACE_ENC_H 2 | #define FLIF_INTERFACE_ENC_H 3 | 4 | /* 5 | FLIF encoder - Free Lossless Image Format 6 | Copyright (C) 2010-2015 Jon Sneyers & Pieter Wuille, LGPL v3+ 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU Lesser General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include "flif_common.h" 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif // __cplusplus 27 | 28 | typedef struct FLIF_ENCODER FLIF_ENCODER; 29 | 30 | // initialize a FLIF encoder 31 | FLIF_DLLIMPORT FLIF_ENCODER* FLIF_API flif_create_encoder(); 32 | 33 | // give it an image to encode; add more than one image to encode an animation; it will CLONE the image 34 | // (so the input image is not touched and you have to call flif_destroy_image on it yourself to free that memory) 35 | FLIF_DLLIMPORT void FLIF_API flif_encoder_add_image(FLIF_ENCODER* encoder, FLIF_IMAGE* image); 36 | 37 | // give it an image to encode; add more than one image to encode an animation; it will MOVE the input image 38 | // (input image becomes invalid during encode and flif_destroy_encoder will free it) 39 | FLIF_DLLIMPORT void FLIF_API flif_encoder_add_image_move(FLIF_ENCODER* encoder, FLIF_IMAGE* image); 40 | 41 | // encode to a file 42 | FLIF_DLLIMPORT int32_t FLIF_API flif_encoder_encode_file(FLIF_ENCODER* encoder, const char* filename); 43 | 44 | // encode to memory (afterwards, buffer will point to the blob and buffer_size_bytes contains its size) 45 | FLIF_DLLIMPORT int32_t FLIF_API flif_encoder_encode_memory(FLIF_ENCODER* encoder, void** buffer, size_t* buffer_size_bytes); 46 | 47 | // release an encoder (has to be called to avoid memory leaks) 48 | FLIF_DLLIMPORT void FLIF_API flif_destroy_encoder(FLIF_ENCODER* encoder); 49 | 50 | // encoder options (these are all optional, the defaults should be fine) 51 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_interlaced(FLIF_ENCODER* encoder, uint32_t interlaced); // 0 = -N, 1 = -I (default: -I) 52 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_learn_repeat(FLIF_ENCODER* encoder, uint32_t learn_repeats); // default: 2 (-R) 53 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_auto_color_buckets(FLIF_ENCODER* encoder, uint32_t acb); // 0 = -B, 1 = default 54 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_palette_size(FLIF_ENCODER* encoder, int32_t palette_size); // default: 512 (max palette size) 55 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_lookback(FLIF_ENCODER* encoder, int32_t lookback); // default: 1 (-L) 56 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_divisor(FLIF_ENCODER* encoder, int32_t divisor); // default: 30 (-D) 57 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_min_size(FLIF_ENCODER* encoder, int32_t min_size); // default: 50 (-M) 58 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_split_threshold(FLIF_ENCODER* encoder, int32_t threshold); // default: 64 (-T) 59 | // The default is to not store RGB values of fully transparent pixels. If you want to avoid that, you have to change it with this function! 60 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_alpha_zero(FLIF_ENCODER* encoder, int32_t lossless); // 0 = default (RGB undefined when A=0), 1 = keep RGB at A=0 (-K) 61 | //error: dllimport cannot be applied to non-inline function definition 62 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_alpha_zero_lossless(FLIF_ENCODER* encoder); 63 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_chance_cutoff(FLIF_ENCODER* encoder, int32_t cutoff); // default: 2 (-X) 64 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_chance_alpha(FLIF_ENCODER* encoder, int32_t alpha); // default: 19 (-Z) 65 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_crc_check(FLIF_ENCODER* encoder, uint32_t crc_check); // 0 = no CRC, 1 = add CRC 66 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_channel_compact(FLIF_ENCODER* encoder, uint32_t plc); // 0 = -C, 1 = default 67 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_ycocg(FLIF_ENCODER* encoder, uint32_t ycocg); // 0 = -Y, 1 = default 68 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_frame_shape(FLIF_ENCODER* encoder, uint32_t frs); // 0 = -S, 1 = default 69 | 70 | //set amount of quality loss, 0 for no loss, 100 for maximum loss, negative values indicate adaptive lossy (second image should be the saliency map) 71 | FLIF_DLLIMPORT void FLIF_API flif_encoder_set_lossy(FLIF_ENCODER* encoder, int32_t loss); // default: 0 (lossless) 72 | 73 | 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif // __cplusplus 78 | 79 | #endif // FLIF_INTERFACE_ENC_H 80 | -------------------------------------------------------------------------------- /src/maniac/bit.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | 3 | #include 4 | int __builtin_clz(unsigned int value) 5 | { 6 | unsigned long r; 7 | _BitScanReverse(&r, value); 8 | return (31 - r); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/maniac/bit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef _MSC_VER 3 | 4 | int __builtin_clz(unsigned int value); 5 | 6 | #endif -------------------------------------------------------------------------------- /src/maniac/chance.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include "chance.hpp" 20 | #include "bit.hpp" 21 | #include 22 | 23 | void build_table(uint16_t *zero_state, uint16_t *one_state, size_t size, uint32_t factor, unsigned int max_p) 24 | { 25 | const int64_t one = 1LL << 32; 26 | int64_t p; 27 | unsigned int last_p8, p8; 28 | unsigned int i; 29 | 30 | memset(zero_state,0,sizeof(uint16_t) * size); 31 | memset(one_state,0,sizeof(uint16_t) * size); 32 | 33 | last_p8 = 0; 34 | p = one / 2; 35 | for (i = 0; i < size / 2; i++) { 36 | p8 = (size * p + one / 2) >> 32; //FIXME try without the one 37 | if (p8 <= last_p8) p8 = last_p8 + 1; 38 | if (last_p8 && last_p8 < size && p8 <= max_p) one_state[last_p8] = p8; 39 | 40 | p += ((one - p) * factor + one / 2) >> 32; 41 | last_p8 = p8; 42 | } 43 | 44 | for (i = size - max_p; i <= max_p; i++) { 45 | if (one_state[i]) continue; 46 | 47 | p = (i * one + size / 2) / size; 48 | p += ((one - p) * factor + one / 2) >> 32; 49 | p8 = (size * p + one / 2) >> 32; //FIXME try without the one 50 | if (p8 <= i) p8 = i + 1; 51 | if (p8 > max_p) p8 = max_p; 52 | one_state[i] = p8; 53 | } 54 | 55 | for (i = 1; i < size; i++) 56 | zero_state[i] = size - one_state[size - i]; 57 | } 58 | 59 | /** Computes an approximation of log(4096 / x) / log(2) * base */ 60 | static uint32_t log4kf(int x, uint32_t base) { 61 | int bits = 8 * sizeof(int) - __builtin_clz(x); 62 | uint64_t y = ((uint64_t)x) << (32 - bits); 63 | uint32_t res = base * (13 - bits); 64 | uint32_t add = base; 65 | while ((add > 1) && ((y & 0x7FFFFFFF) != 0)) { 66 | y = (((uint64_t)y) * y + 0x40000000) >> 31; 67 | add >>= 1; 68 | if ((y >> 32) != 0) { 69 | res -= add; 70 | y >>= 1; 71 | } 72 | } 73 | return res; 74 | } 75 | 76 | Log4kTable::Log4kTable() { 77 | data[0] = 0; 78 | for (int i = 1; i <= 4096; i++) { 79 | data[i] = (log4kf(i, (65535UL << 16) / 12) + (1 << 15)) >> 16; 80 | } 81 | scale = 65535 / 12; 82 | } 83 | 84 | const Log4kTable log4k; 85 | -------------------------------------------------------------------------------- /src/maniac/chance.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct Log4kTable { 28 | uint16_t data[4097]; 29 | int scale; 30 | 31 | Log4kTable(); 32 | }; 33 | 34 | extern const Log4kTable log4k; 35 | 36 | void extern build_table(uint16_t *zero_state, uint16_t *one_state, size_t size, uint32_t factor, unsigned int max_p); 37 | 38 | class SimpleBitChanceTable 39 | { 40 | public: 41 | uint16_t next[2][4096]; // stored as 12-bit numbers 42 | uint32_t alpha; 43 | 44 | void init(int cut, int alpha_) { 45 | alpha = alpha_; 46 | build_table(next[0], next[1], 4096, alpha_, 4096-cut); 47 | } 48 | 49 | SimpleBitChanceTable(int cut = 2, int alpha = 0xFFFFFFFF / 19) { 50 | init(cut, alpha); 51 | } 52 | }; 53 | 54 | #ifdef STATS 55 | struct BitChanceStats 56 | { 57 | double weight; 58 | double sum; 59 | double factor; 60 | 61 | BitChanceStats() : weight(0), sum(0), factor(1.0) {} 62 | 63 | void add(bool bit, unsigned int alpha) { 64 | weight += factor; 65 | if (bit) { 66 | sum += factor; 67 | } 68 | factor *= (1.0 - alpha / 4294967296.0); 69 | } 70 | 71 | BitChanceStats& operator+=(const BitChanceStats& stats) { 72 | weight += stats.weight; 73 | sum += stats.sum; 74 | return *this; 75 | } 76 | 77 | std::string format() const { 78 | std::stringstream ss; 79 | ss << sum << ',' << weight; 80 | return ss.str(); 81 | } 82 | }; 83 | #endif 84 | 85 | class SimpleBitChance 86 | { 87 | protected: 88 | uint16_t chance; // stored as a 12-bit number 89 | #ifdef STATS 90 | BitChanceStats stats_; 91 | #endif 92 | 93 | public: 94 | typedef SimpleBitChanceTable Table; 95 | 96 | SimpleBitChance() { 97 | chance = 0x800; 98 | } 99 | 100 | uint16_t inline get_12bit() const { 101 | return chance; 102 | } 103 | void set_12bit(uint16_t chance) { 104 | this->chance = chance; 105 | } 106 | void inline put(bool bit, const Table &table) { 107 | #ifdef STATS 108 | stats_.add(bit, table.alpha); 109 | #endif 110 | chance = table.next[bit][chance]; 111 | } 112 | 113 | void estim(bool bit, uint64_t &total) const { 114 | total += log4k.data[bit ? chance : 4096-chance]; 115 | } 116 | 117 | static int scale() { 118 | return log4k.scale; 119 | } 120 | 121 | #ifdef STATS 122 | const BitChanceStats& stats() const { 123 | return stats_; 124 | } 125 | #endif 126 | }; 127 | 128 | 129 | #ifndef FAST_BUT_WORSE_COMPRESSION 130 | 131 | static const uint32_t MULTISCALE_ALPHAS[] = { 132 | 21590903, 66728412, 214748365, 7413105, 106514140, 10478104, 133 | //41729744, 5081644, 154536134, 53610361, 14808157, 83024800, 134 | //31468986, 3483142, 8675949, 6333940,128332124,12654046,75606698,47300557,203951463,58885392,35675766,94047111,3071053,4623799,17881424,26067561,9534590,5584795,8146883,6960985,11514860,116922432,71030141,50357314,180327910,62685268,88366071,3950501,245135590,33506680,140836325,4924204,15769017,23724167,37984644,5244115,5947593,44428377,19649020,100089021,9239337,29554783,80475310,8407260,57072137,13475351,7183492,3169265,2794299,164387337,7650051,4341711,109877739,48805148,285518438,22990693,120609957,223623543,3709472,136540575,64675496,4771639,16792101,26898887,25261851,10153668,34574286,40442237,6536419,91162830,20923221,6137730,78003381,55314351,191784837,68845961,73283013,32471914,103252233,60755844,149830100,45842100,51958541,85654236,36812186,43058031,19041256,2623791,332276342,97021591,113346113,10812893,30496923,5411776,174853162,260577854,14349874,132373756,2975884,4480536,124412038,28641651,3594527,11882728,3375207,185970177,216869333,6745365,4207184,39194272,7894563,230582101,145264850,5763342,22279836,2707704,3828091,159387120,410190395,9839267,197776890,8953217,2883663,13905751,11158365,3270616,169541181,12262333,303407934,276959225,210313815,24480974,4076824,27756639,585189062,13058253,363764189,15281050,2542478,18452249,237750805,20276138,16272536,294332358,252742534,2130583863,462185550,268647915,17328222,386315419,352964365,312752266,2313344,874357947,505177649,342471031,435457062,374878495,322372603,2463684,1348207122,696492758,535880669,2172176,398083245,476120461,1061088123,638637072,1903342123,759025196,2039621,422645434,2241650,551873246,2387331,448634113,977298116,490448053,1690401179,1181956121,2038126651,716804021,620344619,803443341,520318678,676701158,568306117,924600596,1493527858,1816328538,1120194691,1004588004,2104856,850135566,1279659514,1947720708,602531930,657419257,737644875,1976407,899176673,1649701506,1090312381,1383509600,780954783,826500455,950638308,1032515596,1992655788,1246411823,1570275450,1419498079,2084110791,1150740857,1859538985,1213845117,1915153,1773726365,1456171521,1313590710,1609656898,1531563934,1731746439 135 | }; 136 | 137 | 138 | template class MultiscaleBitChanceTable { 139 | public: 140 | typedef typename BitChance::Table SubTable; 141 | SubTable subTable[N]; 142 | 143 | explicit MultiscaleBitChanceTable(int cut = 8) { 144 | for (int i= 0; i class MultiscaleBitChance 151 | { 152 | protected: 153 | BitChance chances[N]; 154 | uint32_t quality[N]; 155 | uint8_t best; 156 | #ifdef STATS 157 | BitChanceStats stats_; 158 | #endif 159 | 160 | public: 161 | typedef MultiscaleBitChanceTable Table; 162 | 163 | MultiscaleBitChance() { 164 | set_12bit(0x800); 165 | } 166 | 167 | void set_12bit(uint16_t chanceIn) { 168 | for (int i = 0; i>9; 191 | quality[i] = (oqual*255 + sbits*4097 + 128)>>8; 192 | // quality[i] = (oqual*127 + sbits*2049 + 64)>>7; 193 | // if (quality[i] < quality[best]) best=i; 194 | chances[i].put(bit, table.subTable[i]); 195 | } 196 | 197 | for (int i=0; i 23 | #endif 24 | 25 | #include 26 | #include 27 | #include "../config.h" 28 | #include "../compiler-specific.hpp" 29 | 30 | /* RAC configuration for 24-bit RAC */ 31 | class RacConfig24 { 32 | public: 33 | typedef uint_fast32_t data_t; 34 | static const data_t MAX_RANGE_BITS = 24; 35 | static const data_t MIN_RANGE_BITS = 16; 36 | static const data_t MIN_RANGE = (1UL << MIN_RANGE_BITS); 37 | static const data_t BASE_RANGE = (1UL << MAX_RANGE_BITS); 38 | 39 | static inline data_t chance_12bit_chance(int b12, data_t range) { 40 | assert(b12 > 0); 41 | assert((b12 >> 12) == 0); 42 | // We want to compute (range * b12 + 0x800) >> 12. On 64-bit architectures this is no problem 43 | if (sizeof(data_t) > 4) return (range * b12 + 0x800) >> 12; 44 | // Unfortunately, this can overflow the 32-bit data type on 32-bit architectures, so split range 45 | // in its lower and upper 12 bits, and compute separately. 46 | else return ((((range & 0xFFF) * b12 + 0x800) >> 12) + ((range >> 12) * b12)); 47 | // (no worries, the compiler eliminates this branching) 48 | } 49 | }; 50 | 51 | template class RacInput { 52 | public: 53 | typedef typename Config::data_t rac_t; 54 | protected: 55 | IO& io; 56 | private: 57 | #ifdef STATS 58 | uint64_t samples; 59 | #endif 60 | rac_t range; 61 | rac_t low; 62 | private: 63 | rac_t read_catch_eof() { 64 | rac_t c = io.get_c(); 65 | // no reason to branch here to catch end-of-stream, just return garbage (0xFF I guess) if a premature EOS happens 66 | //if(c == io.EOS) return 0; 67 | return c; 68 | } 69 | void inline input() { 70 | if (range <= Config::MIN_RANGE) { 71 | low <<= 8; 72 | range <<= 8; 73 | low |= read_catch_eof(); 74 | } 75 | if (range <= Config::MIN_RANGE) { 76 | low <<= 8; 77 | range <<= 8; 78 | low |= read_catch_eof(); 79 | } 80 | } 81 | bool inline get(rac_t chance) { 82 | #ifdef STATS 83 | samples++; 84 | #endif 85 | assert(chance > 0); 86 | assert(chance < range); 87 | if (low >= range-chance) { 88 | low -= range-chance; 89 | range = chance; 90 | input(); 91 | return true; 92 | } else { 93 | range -= chance; 94 | input(); 95 | return false; 96 | } 97 | } 98 | public: 99 | explicit RacInput(IO& ioin) : io(ioin), range(Config::BASE_RANGE), low(0) { 100 | #ifdef STATS 101 | samples = 0; 102 | #endif 103 | rac_t r = Config::BASE_RANGE; 104 | while (r > 1) { 105 | low <<= 8; 106 | low |= read_catch_eof(); 107 | r >>= 8; 108 | } 109 | } 110 | 111 | #ifdef STATS 112 | ~RacInput() { 113 | fprintf(stdout, "Total samples read from range coder: %llu\n", (unsigned long long)samples); 114 | } 115 | #endif 116 | 117 | bool inline read_12bit_chance(uint16_t b12) ATTRIBUTE_HOT { 118 | return get(Config::chance_12bit_chance(b12, range)); 119 | } 120 | 121 | bool inline read_bit() { 122 | return get(range >> 1); 123 | } 124 | }; 125 | 126 | 127 | template class RacInput24 : public RacInput { 128 | public: 129 | explicit RacInput24(IO& io) : RacInput(io) { } 130 | }; 131 | 132 | #ifdef HAS_ENCODER 133 | #include "rac_enc.hpp" 134 | #endif 135 | -------------------------------------------------------------------------------- /src/maniac/rac_enc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF encoder - Free Lossless Image Format 3 | Copyright (C) 2010-2015 Jon Sneyers & Pieter Wuille, LGPL v3+ 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | template class RacOutput { 22 | public: 23 | typedef typename Config::data_t rac_t; 24 | protected: 25 | IO& io; 26 | private: 27 | rac_t range; 28 | rac_t low; 29 | int delayed_byte; 30 | int delayed_count; 31 | 32 | void inline output() { 33 | while (range <= Config::MIN_RANGE) { 34 | int byte = low >> Config::MIN_RANGE_BITS; 35 | if (delayed_byte < 0) { // first generated byte 36 | delayed_byte = byte; 37 | } else if (((low + range) >> 8) < Config::MIN_RANGE) { // definitely no overflow 38 | io.fputc(delayed_byte); 39 | while (delayed_count) { 40 | io.fputc(0xFF); 41 | delayed_count--; 42 | } 43 | delayed_byte = byte; 44 | } else if ((low >> 8) >= Config::MIN_RANGE) { // definitely overflow 45 | io.fputc(delayed_byte + 1); 46 | while (delayed_count) { 47 | io.fputc(0); 48 | delayed_count--; 49 | } 50 | delayed_byte = byte & 0xFF; 51 | } else { 52 | delayed_count++; 53 | } 54 | low = (low & (Config::MIN_RANGE - 1)) << 8; 55 | range <<= 8; 56 | } 57 | } 58 | void inline put(rac_t chance, bool bit) { 59 | assert(chance > 0); 60 | assert(chance < range); 61 | if (bit) { 62 | low += range - chance; 63 | range = chance; 64 | } else { 65 | range -= chance; 66 | } 67 | output(); 68 | } 69 | public: 70 | RacOutput(IO& ioin) : io(ioin), range(Config::BASE_RANGE), low(0), delayed_byte(-1), delayed_count(0) { } 71 | 72 | void inline write_12bit_chance(uint16_t b12, bool bit) { 73 | put(Config::chance_12bit_chance(b12, range), bit); 74 | } 75 | 76 | void inline write_bit(bool bit) { 77 | put(range >> 1, bit); 78 | } 79 | 80 | void inline flush() { 81 | low += (Config::MIN_RANGE - 1); 82 | // is this the correct way to reliably flush? 83 | range = Config::MIN_RANGE - 1; 84 | output(); 85 | range = Config::MIN_RANGE - 1; 86 | output(); 87 | range = Config::MIN_RANGE - 1; 88 | output(); 89 | range = Config::MIN_RANGE - 1; 90 | output(); 91 | io.flush(); 92 | } 93 | }; 94 | 95 | 96 | class RacDummy { 97 | public: 98 | static void inline write_12bit_chance(FLIF_UNUSED(uint16_t b12), bool) { } 99 | static void inline write_bit(bool) { } 100 | static void inline flush() { } 101 | }; 102 | 103 | 104 | template class RacOutput24 : public RacOutput { 105 | public: 106 | RacOutput24(IO& io) : RacOutput(io) { } 107 | }; 108 | -------------------------------------------------------------------------------- /src/maniac/symbol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "symbol.hpp" 4 | 5 | #ifdef STATS 6 | std::string SymbolChanceStats::format() const { 7 | std::stringstream ss; 8 | ss << "zero," << stats_zero.format() << ", "; 9 | ss << "sign," << stats_sign.format() << ", "; 10 | for (int i = 0; i < 17; i++) { 11 | ss << "e" << i << "," << stats_exp[i].format() << ", "; 12 | } 13 | for (int i = 0; i < 18; i++) { 14 | ss << "m" << i << "," << stats_mant[i].format() << ", "; 15 | } 16 | return ss.str(); 17 | } 18 | 19 | SymbolChanceStats::~SymbolChanceStats() { 20 | fprintf(stderr, "STATS: %s\n", format().c_str()); 21 | } 22 | 23 | SymbolChanceStats global_symbol_stats; 24 | #endif 25 | -------------------------------------------------------------------------------- /src/maniac/symbol_enc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF encoder - Free Lossless Image Format 3 | Copyright (C) 2010-2015 Jon Sneyers & Pieter Wuille, LGPL v3+ 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | template 22 | void UniformSymbolCoder::write_int(int min, int max, int val) { 23 | assert(max >= min); 24 | if (min != 0) { 25 | max -= min; 26 | val -= min; 27 | } 28 | if (max == 0) return; 29 | 30 | // split in [0..med] [med+1..max] 31 | int med = max/2; 32 | if (val > med) { 33 | rac.write_bit(true); 34 | write_int(med+1, max, val); 35 | } else { 36 | rac.write_bit(false); 37 | write_int(0, med, val); 38 | } 39 | return; 40 | } 41 | 42 | 43 | template void writer(SymbolCoder& coder, int bits, int value) { 44 | int pos=0; 45 | while (pos++ < bits) { 46 | coder.write(value&1, BIT_MANT, pos); 47 | value >>= 1; 48 | } 49 | } 50 | 51 | template void writer(SymbolCoder& coder, int min, int max, int value) { 52 | assert(min<=max); 53 | assert(value>=min); 54 | assert(value<=max); 55 | 56 | // avoid doing anything if the value is already known 57 | if (min == max) return; 58 | 59 | if (value == 0) { // value is zero 60 | coder.write(true, BIT_ZERO); 61 | return; 62 | } 63 | 64 | assert(min <= 0 && max >= 0); // should always be the case, because guess should always be in valid range 65 | 66 | // only output zero bit if value could also have been zero 67 | //if (max >= 0 && min <= 0) 68 | coder.write(false,BIT_ZERO); 69 | int sign = (value > 0 ? 1 : 0); 70 | if (max > 0 && min < 0) { 71 | // only output sign bit if value can be both pos and neg 72 | coder.write(sign,BIT_SIGN); 73 | } 74 | if (sign) min = 1; 75 | if (!sign) max = -1; 76 | const int a = abs(value); 77 | const int e = maniac::util::ilog2(a); 78 | int amin = sign ? abs(min) : abs(max); 79 | int amax = sign ? abs(max) : abs(min); 80 | 81 | int emax = maniac::util::ilog2(amax); 82 | int i = maniac::util::ilog2(amin); 83 | 84 | while (i < emax) { 85 | // if exponent >i is impossible, we are done 86 | if ((1 << (i+1)) > amax) break; 87 | // if exponent i is possible, output the exponent bit 88 | coder.write(i==e, BIT_EXP, (i<<1) + sign); 89 | if (i==e) break; 90 | i++; 91 | } 92 | // e_printf("exp=%i\n",e); 93 | int have = (1 << e); 94 | int left = have-1; 95 | for (int pos = e; pos>0;) { 96 | int bit = 1; 97 | left ^= (1 << (--pos)); 98 | int minabs1 = have | (1< amax) { // 1-bit is impossible 103 | bit = 0; 104 | } else if (maxabs0 >= amin) { // 0-bit and 1-bit are both possible 105 | bit = (a >> pos) & 1; 106 | coder.write(bit, BIT_MANT, pos); 107 | } 108 | have |= (bit << pos); 109 | } 110 | } 111 | 112 | 113 | template 114 | void SimpleSymbolBitCoder::write(bool bit, SymbolChanceBitType typ, int i) { 115 | BitChance& bch = ctx.bit(typ, i); 116 | rac.write_12bit_chance(bch.get_12bit(), bit); 117 | bch.put(bit, table); 118 | } 119 | 120 | 121 | template 122 | void SimpleSymbolCoder::write_int(int min, int max, int value) { 123 | SimpleSymbolBitCoder bitCoder(table, ctx, rac); 124 | writer >(bitCoder, min, max, value); 125 | } 126 | template 127 | void SimpleSymbolCoder::write_int(int nbits, int value) { 128 | assert (nbits <= bits); 129 | SimpleSymbolBitCoder bitCoder(table, ctx, rac); 130 | writer(bitCoder, nbits, value); 131 | } 132 | -------------------------------------------------------------------------------- /src/maniac/util.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include "bit.hpp" 23 | 24 | namespace maniac { 25 | namespace util { 26 | 27 | static inline int ilog2(uint32_t l) { 28 | if (l == 0) { return 0; } 29 | // return sizeof(unsigned int) * 8 - __builtin_clz(l) - 1; 30 | return sizeof(unsigned int) * 8 - 1 - __builtin_clz(l); 31 | } 32 | 33 | void indent(int n); 34 | 35 | 36 | } // namespace util 37 | } // namespace maniac 38 | -------------------------------------------------------------------------------- /src/transform/bounds.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include "transform.hpp" 25 | #include "../maniac/symbol.hpp" 26 | 27 | class ColorRangesBounds final : public ColorRanges { 28 | protected: 29 | const std::vector > bounds; 30 | const ColorRanges *ranges; 31 | public: 32 | ColorRangesBounds(const std::vector > &boundsIn, const ColorRanges *rangesIn) : bounds(boundsIn), ranges(rangesIn) {} 33 | bool isStatic() const override { return false; } 34 | int numPlanes() const override { return bounds.size(); } 35 | ColorVal min(int p) const override { assert(pmin(p), bounds[p].first); } 36 | ColorVal max(int p) const override { assert(pmax(p), bounds[p].second); } 37 | void snap(const int p, const prevPlanes &pp, ColorVal &min, ColorVal &max, ColorVal &v) const override { 38 | if (p==0 || p==3) { min=bounds[p].first; max=bounds[p].second; } // optimization for special case 39 | else { 40 | ranges->snap(p,pp,min,max,v); 41 | if (min < bounds[p].first) min=bounds[p].first; 42 | if (max > bounds[p].second) max=bounds[p].second; 43 | if (min>max) { 44 | // should happen only if alpha=0 interpolation produces YI combination for which Q range from ColorRangesYIQ is outside bounds 45 | min=bounds[p].first; 46 | max=bounds[p].second; 47 | } 48 | } 49 | if(v>max) v=max; 50 | if(vminmax(p, pp, min, max); 56 | if (min < bounds[p].first) min=bounds[p].first; 57 | if (max > bounds[p].second) max=bounds[p].second; 58 | if (min>max) { 59 | // should happen only if alpha=0 interpolation produces YI combination for which Q range from ColorRangesYIQ is outside bounds 60 | min=bounds[p].first; 61 | max=bounds[p].second; 62 | } 63 | assert(min <= max); 64 | } 65 | }; 66 | 67 | 68 | template 69 | class TransformBounds : public Transform { 70 | protected: 71 | std::vector > bounds; 72 | 73 | bool undo_redo_during_decode() override { return false; } 74 | 75 | const ColorRanges *meta(Images&, const ColorRanges *srcRanges) override { 76 | if (srcRanges->isStatic()) { 77 | return new StaticColorRanges(bounds); 78 | } else { 79 | return new ColorRangesBounds(bounds, srcRanges); 80 | } 81 | } 82 | 83 | bool load(const ColorRanges *srcRanges, RacIn &rac) override { 84 | if (srcRanges->numPlanes() > 4) return false; // something wrong if Bounds is done on FRA 85 | SimpleSymbolCoder, 18> coder(rac); 86 | bounds.clear(); 87 | for (int p=0; pnumPlanes(); p++) { 88 | // ColorVal min = coder.read_int(0, srcRanges->max(p) - srcRanges->min(p)) + srcRanges->min(p); 89 | // ColorVal max = coder.read_int(0, srcRanges->max(p) - min) + min; 90 | ColorVal min = coder.read_int2(srcRanges->min(p), srcRanges->max(p)); 91 | ColorVal max = coder.read_int2(min, srcRanges->max(p)); 92 | if (min > max) return false; 93 | if (min < srcRanges->min(p)) return false; 94 | if (max > srcRanges->max(p)) return false; 95 | bounds.push_back(std::make_pair(min,max)); 96 | v_printf(5,"[%i:%i..%i]",p,min,max); 97 | } 98 | return true; 99 | } 100 | 101 | #ifdef HAS_ENCODER 102 | void save(const ColorRanges *srcRanges, RacOut &rac) const override { 103 | SimpleSymbolCoder, 18> coder(rac); 104 | for (int p=0; pnumPlanes(); p++) { 105 | ColorVal min = bounds[p].first; 106 | ColorVal max = bounds[p].second; 107 | // coder.write_int(0, srcRanges->max(p) - srcRanges->min(p), min - srcRanges->min(p)); 108 | // coder.write_int(0, srcRanges->max(p) - min, max - min); 109 | coder.write_int2(srcRanges->min(p), srcRanges->max(p), min); 110 | coder.write_int2(min, srcRanges->max(p), max); 111 | v_printf(5,"[%i:%i..%i]",p,min,max); 112 | } 113 | } 114 | 115 | bool process(const ColorRanges *srcRanges, const Images &images) override { 116 | if (images[0].palette) return false; // skip if the image is already a palette image 117 | bounds.clear(); 118 | bool trivialbounds=true; 119 | int nump=srcRanges->numPlanes(); 120 | for (int p=0; pmax(p); 122 | ColorVal max = srcRanges->min(p); 123 | for (const Image& image : images) 124 | for (uint32_t r=0; r3 && p<3 && image(3,r,c)==0) continue; // don't take fully transparent pixels into account 127 | ColorVal v = image(p,r,c); 128 | if (v < min) min = v; 129 | if (v > max) max = v; 130 | assert(v <= srcRanges->max(p)); 131 | assert(v >= srcRanges->min(p)); 132 | } 133 | } 134 | if (min > max) min = max = (min+max)/2; // this can happen if the image is fully transparent 135 | bounds.push_back(std::make_pair(min,max)); 136 | if (min > srcRanges->min(p)) trivialbounds=false; 137 | if (max < srcRanges->max(p)) trivialbounds=false; 138 | } 139 | return !trivialbounds; 140 | } 141 | #endif 142 | }; 143 | -------------------------------------------------------------------------------- /src/transform/factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "transform.hpp" 4 | 5 | #include "ycocg.hpp" 6 | //#include "yc1c2.hpp" 7 | #include "permute.hpp" 8 | #include "bounds.hpp" 9 | #include "colorbuckets.hpp" 10 | #include "palette.hpp" 11 | #include "palette_A.hpp" 12 | #include "palette_C.hpp" 13 | //#include "palette_CoCg.hpp" 14 | #ifdef SUPPORT_ANIMATION 15 | #include "frameshape.hpp" 16 | #include "framedup.hpp" 17 | #include "framecombine.hpp" 18 | #endif 19 | //#include "dct.hpp" 20 | 21 | template 22 | std::unique_ptr> create_transform(const std::string &desc) { 23 | if (desc == "YCoCg") 24 | return make_unique>(); 25 | // use this if you just want to quickly try YC1C2 26 | // return new TransformYCC(); 27 | if (desc == "Bounds") 28 | return make_unique>(); 29 | if (desc == "PermutePlanes") 30 | return make_unique>(); 31 | if (desc == "Color_Buckets") 32 | return make_unique>(); 33 | if (desc == "Palette") 34 | return make_unique>(); 35 | if (desc == "Palette_Alpha") 36 | return make_unique>(); 37 | // if (desc == "Palette_Chroma") // turned out to be useless 38 | // return make_unique>(); 39 | if (desc == "Channel_Compact") 40 | return make_unique>(); 41 | #ifdef SUPPORT_ANIMATION 42 | if (desc == "Frame_Shape") 43 | return make_unique>(); 44 | if (desc == "Duplicate_Frame") 45 | return make_unique>(); 46 | if (desc == "Frame_Lookback") 47 | return make_unique>(); 48 | #endif 49 | // if (desc == "DCT") 50 | // return make_unique>(); 51 | return NULL; 52 | } 53 | 54 | template std::unique_ptr> create_transform(const std::string &desc); 55 | template std::unique_ptr> create_transform(const std::string &desc); 56 | template std::unique_ptr> create_transform(const std::string &desc); 57 | -------------------------------------------------------------------------------- /src/transform/factory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "transform.hpp" 4 | #include 5 | 6 | template 7 | std::unique_ptr> create_transform(const std::string &desc); 8 | -------------------------------------------------------------------------------- /src/transform/framedup.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "transform.hpp" 25 | #include "../maniac/symbol.hpp" 26 | 27 | 28 | 29 | template 30 | class TransformFrameDup final : public Transform { 31 | protected: 32 | std::vector seen_before; 33 | uint32_t nb; 34 | 35 | bool undo_redo_during_decode() override { return false; } 36 | const ColorRanges *meta(Images& images, const ColorRanges *srcRanges) override { 37 | for (unsigned int fr=0; fr &rac) override { 47 | SimpleSymbolCoder, 18> coder(rac); 48 | seen_before.clear(); 49 | seen_before.push_back(-1); 50 | for (unsigned int i=1; i=0) count++; } v_printf(5,"[%i]",count); 52 | return true; 53 | } 54 | 55 | #ifdef HAS_ENCODER 56 | void save(const ColorRanges *, RacOut &rac) const override { 57 | SimpleSymbolCoder, 18> coder(rac); 58 | assert(nb == seen_before.size()); 59 | for (unsigned int i=1; i=0) count++; } v_printf(5,"[%i]",count); 61 | } 62 | 63 | bool process(const ColorRanges *srcRanges, const Images &images) override { 64 | int np=srcRanges->numPlanes(); 65 | nb = images.size(); 66 | seen_before.clear(); 67 | seen_before.resize(nb,-1); 68 | bool dupes_found=false; 69 | for (unsigned int fr=1; fr 22 | 23 | #include "transform.hpp" 24 | #include "../maniac/symbol.hpp" 25 | 26 | 27 | 28 | template 29 | class TransformFrameShape final : public Transform { 30 | protected: 31 | std::vector b; 32 | std::vector e; 33 | uint32_t cols; 34 | uint32_t nb; 35 | 36 | bool undo_redo_during_decode() override { return false; } 37 | 38 | const ColorRanges *meta(Images& images, const ColorRanges *srcRanges) override { 39 | uint32_t pos=0; 40 | for (unsigned int fr=1; fr= 0) continue; 43 | for (uint32_t r=0; r &rac) override { 56 | SimpleSymbolCoder, 18> coder(rac); 57 | for (unsigned int i=0; i cols || e[i] < b[i] || e[i] <= 0) { 61 | e_printf("\nError: FRS transform: invalid end column\n"); 62 | return false; 63 | } 64 | } 65 | return true; 66 | } 67 | 68 | #if HAS_ENCODER 69 | void save(const ColorRanges *, RacOut &rac) const override { 70 | SimpleSymbolCoder, 18> coder(rac); 71 | assert(nb == b.size()); 72 | assert(nb == e.size()); 73 | for (unsigned int i=0; inumPlanes(); 80 | nb = 0; 81 | cols = images[0].cols(); 82 | for (unsigned int fr=1; fr= 0) continue; 85 | nb += image.rows(); 86 | for (uint32_t r=0; r3 && image(3,r,c) == 0 && images[fr-1](3,r,c)==0) continue; 90 | for (int p=0; p= b.back(); c--) { 98 | if (image.alpha_zero_special && np>3 && image(3,r,c) == 0 && images[fr-1](3,r,c)==0) continue; 99 | for (int p=0; p 25 | #include 26 | 27 | 28 | class ColorRangesPaletteC final : public ColorRanges { 29 | protected: 30 | const ColorRanges *ranges; 31 | int nb_colors[4]; 32 | public: 33 | ColorRangesPaletteC(const ColorRanges *rangesIn, const int nb[4]) : ranges(rangesIn) { for (int i=0; i<4; i++) nb_colors[i] = nb[i]; } 34 | bool isStatic() const override { return true; } 35 | int numPlanes() const override { return ranges->numPlanes(); } 36 | 37 | ColorVal min(FLIF_UNUSED(int p)) const override { return 0; } 38 | ColorVal max(int p) const override { return nb_colors[p]; } 39 | void minmax(const int p, FLIF_UNUSED(const prevPlanes &pp), ColorVal &minv, ColorVal &maxv) const override { 40 | minv=0; maxv=nb_colors[p]; 41 | } 42 | 43 | }; 44 | 45 | 46 | template 47 | class TransformPaletteC : public Transform { 48 | protected: 49 | std::vector CPalette_vector[4]; 50 | std::vector CPalette_inv_vector[4]; 51 | 52 | public: 53 | bool init(const ColorRanges *srcRanges) override { 54 | if (srcRanges->numPlanes()>4) return false; // FRA should always be done after CC, this is just to catch bad input 55 | return true; 56 | } 57 | 58 | const ColorRanges *meta(FLIF_UNUSED(Images& images), const ColorRanges *srcRanges) override { 59 | int nb[4] = {}; 60 | v_printf(4,"["); 61 | for (int i=0; inumPlanes(); i++) { 62 | nb[i] = CPalette_vector[i].size()-1; 63 | if (i>0) v_printf(4,","); 64 | v_printf(4,"%i",nb[i]); 65 | // if (nb[i] < 64) nb[i] <<= 2; 66 | } 67 | v_printf(4,"]"); 68 | return new ColorRangesPaletteC(srcRanges, nb); 69 | } 70 | 71 | void invData(Images& images, FLIF_UNUSED(uint32_t strideCol), FLIF_UNUSED(uint32_t strideRow)) const override { 72 | for (Image& image : images) { 73 | 74 | const uint32_t scaledRows = image.scaledRows(); 75 | const uint32_t scaledCols = image.scaledCols(); 76 | 77 | for (int p=0; p 64 ? 0 : 2); 81 | image.undo_make_constant_plane(p); 82 | GeneralPlane &plane = image.getPlane(p); 83 | for (uint32_t r=0; r> stretch]); 87 | if (P < 0 || P >= (int) palette_size) P = 0; // might happen on invisible pixels with predictor -H1 88 | assert(P < (int) palette_size); 89 | plane.set(r,c, palette[P]); 90 | } 91 | } 92 | } 93 | } 94 | } 95 | 96 | #if HAS_ENCODER 97 | bool process(const ColorRanges *srcRanges, const Images &images) override { 98 | 99 | if (images[0].palette) return false; // skip if the image is already a palette image 100 | 101 | std::set CPalette; 102 | bool nontrivial=false; 103 | for (int p=0; pnumPlanes(); p++) { 104 | if (p==3) CPalette.insert(0); // ensure that A=0 is still A=0 even if image does not contain zero-alpha pixels 105 | for (const Image& image : images) { 106 | for (uint32_t r=0; rmax(p)-srcRanges->min(p)) nontrivial = true; 113 | // if on all channels, less than 10% of the range can be compacted away, it's probably a bad idea to do the compaction 114 | // since the gain from a smaller RGB range will probably not compensate for the disturbing of the YIQ transform 115 | if ((int)CPalette.size() * 10 <= 9 * (srcRanges->max(p)-srcRanges->min(p))) nontrivial = true; 116 | if (CPalette.size() < 10) { 117 | // add up to 10 shades of gray 118 | ColorVal prev=0; 119 | for (ColorVal c : CPalette) { 120 | if (c > prev+1) CPalette_vector[p].push_back((c+prev)/2); 121 | CPalette_vector[p].push_back(c); 122 | prev=c; 123 | nontrivial=true; 124 | } 125 | } else { 126 | for (ColorVal c : CPalette) CPalette_vector[p].push_back(c); 127 | } 128 | CPalette.clear(); 129 | CPalette_inv_vector[p].resize(srcRanges->max(p)+1); 130 | for (unsigned int i=0; i64 ? 0 : 2); 138 | for (uint32_t r=0; r &rac) const override { 150 | SimpleSymbolCoder, 18> coder(rac); 151 | for (int p=0; pnumPlanes(); p++) { 152 | coder.write_int(0, srcRanges->max(p)-srcRanges->min(p), CPalette_vector[p].size()-1); 153 | ColorVal min=srcRanges->min(p); 154 | int remaining=CPalette_vector[p].size()-1; 155 | for (unsigned int i=0; imax(p)-min-remaining, CPalette_vector[p][i]-min); 157 | min = CPalette_vector[p][i]+1; 158 | remaining--; 159 | } 160 | } 161 | } 162 | #endif 163 | bool load(const ColorRanges *srcRanges, RacIn &rac) override { 164 | SimpleSymbolCoder, 18> coder(rac); 165 | for (int p=0; pnumPlanes(); p++) { 166 | unsigned int nb = coder.read_int(0, srcRanges->max(p)-srcRanges->min(p)) + 1; 167 | ColorVal min=srcRanges->min(p); 168 | int remaining = nb-1; 169 | for (unsigned int i=0; imax(p)-min-remaining)); 171 | min = CPalette_vector[p][i]+1; 172 | remaining--; 173 | } 174 | } 175 | return true; 176 | } 177 | }; 178 | -------------------------------------------------------------------------------- /src/transform/permute.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | 20 | #pragma once 21 | 22 | #include "../image/image.hpp" 23 | #include "../image/color_range.hpp" 24 | #include "transform.hpp" 25 | 26 | class ColorRangesPermute final : public ColorRanges { 27 | protected: 28 | const std::vector permutation; 29 | const ColorRanges *ranges; 30 | public: 31 | ColorRangesPermute(const std::vector &perm, const ColorRanges *rangesIn) 32 | : permutation(perm), ranges(rangesIn) { } 33 | bool isStatic() const override { return false; } 34 | int numPlanes() const override { return ranges->numPlanes(); } 35 | 36 | ColorVal min(int p) const override { return ranges->min(permutation[p]); } 37 | ColorVal max(int p) const override { return ranges->max(permutation[p]); } 38 | 39 | }; 40 | 41 | class ColorRangesPermuteSubtract final : public ColorRanges { 42 | protected: 43 | const std::vector permutation; 44 | const ColorRanges *ranges; 45 | public: 46 | ColorRangesPermuteSubtract(const std::vector &perm, const ColorRanges *rangesIn) 47 | : permutation(perm), ranges(rangesIn) { } 48 | bool isStatic() const override { return false; } 49 | int numPlanes() const override { return ranges->numPlanes(); } 50 | 51 | ColorVal min(int p) const override { if (p==0 || p>2) return ranges->min(permutation[p]); else return ranges->min(permutation[p])-ranges->max(permutation[0]); } 52 | ColorVal max(int p) const override { if (p==0 || p>2) return ranges->max(permutation[p]); else return ranges->max(permutation[p])-ranges->min(permutation[0]); } 53 | void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const override { 54 | if (p==0 || p>2) { minv = min(p); maxv = max(p); } 55 | else { minv = ranges->min(permutation[p])-pp[0]; maxv = ranges->max(permutation[p])-pp[0]; } 56 | } 57 | 58 | }; 59 | 60 | 61 | template 62 | class TransformPermute : public Transform { 63 | protected: 64 | std::vector permutation; 65 | const ColorRanges *ranges; 66 | bool subtract; 67 | 68 | public: 69 | bool virtual init(const ColorRanges *srcRanges) override { 70 | if (srcRanges->numPlanes() < 3) return false; 71 | if (srcRanges->min(0) < 0 || srcRanges->min(1) < 0 || srcRanges->min(2) < 0) return false; // already did YCoCg 72 | permutation.resize(srcRanges->numPlanes()); 73 | ranges = srcRanges; 74 | return true; 75 | } 76 | 77 | const ColorRanges *meta(Images&, const ColorRanges *srcRanges) override { 78 | if (subtract) return new ColorRangesPermuteSubtract(permutation, srcRanges); 79 | else return new ColorRangesPermute(permutation, srcRanges); 80 | } 81 | 82 | #ifdef HAS_ENCODER 83 | void configure(const int setting) override { 84 | subtract = setting; 85 | } 86 | bool process(const ColorRanges *srcRanges, const Images &images) override { 87 | if (images[0].palette) return false; // skip if the image is already a palette image 88 | const int perm[5] = {1,0,2,3,4}; // just always transform RGB to GRB, we can do something more complicated later 89 | for (int p=0; pnumPlanes(); p++) { 90 | permutation[p] = perm[p]; 91 | } 92 | return true; 93 | } 94 | void data(Images& images) const override { 95 | ColorVal pixel[5]; 96 | for (Image& image : images) 97 | for (uint32_t r=0; rnumPlanes(); p++) pixel[p] = image(p,r,c); 100 | image.set(0,r,c, pixel[permutation[0]]); 101 | if (!subtract) { for (int p=1; pnumPlanes(); p++) image.set(p,r,c, pixel[permutation[p]]); } 102 | else { for (int p=1; p<3 && pnumPlanes(); p++) image.set(p,r,c, pixel[permutation[p]] - pixel[permutation[0]]); 103 | for (int p=3; pnumPlanes(); p++) image.set(p,r,c, pixel[permutation[p]]); } 104 | } 105 | } 106 | } 107 | void save(const ColorRanges *srcRanges, RacOut &rac) const override { 108 | SimpleSymbolCoder, 18> coder(rac); 109 | coder.write_int2(0, 1, subtract); 110 | if (subtract) v_printf(4,"Subtract"); 111 | for (int p=0; pnumPlanes(); p++) { 112 | coder.write_int2(0, srcRanges->numPlanes()-1, permutation[p]); 113 | v_printf(5,"[%i->%i]",p,permutation[p]); 114 | } 115 | } 116 | #endif 117 | bool load(const ColorRanges *srcRanges, RacIn &rac) override { 118 | SimpleSymbolCoder, 18> coder(rac); 119 | subtract = coder.read_int2(0, 1); 120 | if (subtract) v_printf(4,"Subtract"); 121 | bool from[4] = {false, false, false, false}, to[4] = {false, false, false, false}; 122 | for (int p=0; pnumPlanes(); p++) { 123 | permutation[p] = coder.read_int2(0, srcRanges->numPlanes()-1); 124 | v_printf(5,"[%i->%i]",p,permutation[p]); 125 | from[p] = true; 126 | to[permutation[p]] = true; 127 | } 128 | for (int p=0; pnumPlanes(); p++) { 129 | if (!from[p] || !to[p]) { 130 | e_printf("\nNot a valid permutation!\n"); 131 | return false; 132 | } 133 | } 134 | return true; 135 | } 136 | #define CLAMP(x,l,u) (x>u?u:(xnumPlanes(); p++) image.undo_make_constant_plane(p); 145 | for (uint32_t r=0; rnumPlanes(); p++) pixel[p] = image(p,r,c); 148 | for (int p=0; pnumPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); 149 | image.set(permutation[0],r,c, pixel[0]); 150 | if (!subtract) { for (int p=1; pnumPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); } 151 | else { for (int p=1; p<3 && pnumPlanes(); p++) image.set(permutation[p],r,c, CLAMP(pixel[p] + pixel[0], ranges->min(permutation[p]), ranges->max(permutation[p]))); 152 | for (int p=3; pnumPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); } 153 | } 154 | } 155 | } 156 | } 157 | }; 158 | 159 | -------------------------------------------------------------------------------- /src/transform/transform.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #pragma once 20 | 21 | #include "../image/image.hpp" 22 | #include "../image/color_range.hpp" 23 | #include "../maniac/rac.hpp" 24 | #include "../flif_config.h" 25 | 26 | 27 | template 28 | class Transform { 29 | protected: 30 | 31 | public: 32 | virtual ~Transform() {}; 33 | 34 | // On encode: init, process, save, meta, data, 35 | // On decode: init, load, meta, , invData ( + optional configure anywhere) 36 | // Progressive decode: init, load, meta, , invData, , data, 37 | // , invData, , data, 38 | // ... 39 | // , invData 40 | 41 | 42 | bool virtual init(const ColorRanges *) { return true; } 43 | bool virtual undo_redo_during_decode() { return true; } 44 | void virtual configure(const int) { } 45 | bool virtual load(const ColorRanges *, RacIn &) { return true; }; 46 | #ifdef HAS_ENCODER 47 | bool virtual process(const ColorRanges *, const Images &) { return true; }; 48 | void virtual save(const ColorRanges *, RacOut &) const {}; 49 | void virtual data(Images&) const {} 50 | #endif 51 | const ColorRanges virtual *meta(Images&, const ColorRanges *srcRanges) { return new DupColorRanges(srcRanges); } 52 | void virtual invData(Images&, FLIF_UNUSED(uint32_t strideCol)=1, FLIF_UNUSED(uint32_t strideRow)=1) const {} 53 | bool virtual is_palette_transform() const { return false; } 54 | }; 55 | -------------------------------------------------------------------------------- /src/transform/yc1c2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | FLIF - Free Lossless Image Format 3 | 4 | Copyright 2010-2016, Jon Sneyers & Pieter Wuille 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | 20 | #pragma once 21 | 22 | #include "../image/image.hpp" 23 | #include "../image/color_range.hpp" 24 | #include "transform.hpp" 25 | #include 26 | 27 | #define clip(x,l,u) if ((x) < (l)) {(x)=(l);} else if ((x) > (u)) {(x)=(u);} 28 | 29 | 30 | class ColorRangesYCC final : public ColorRanges { 31 | protected: 32 | const int maximum; 33 | const ColorRanges *ranges; 34 | public: 35 | ColorRangesYCC(int m, const ColorRanges *rangesIn) 36 | : maximum(m), ranges(rangesIn) { 37 | } 38 | bool isStatic() const { return false; } 39 | int numPlanes() const { return ranges->numPlanes(); } 40 | 41 | ColorVal min(int p) const { 42 | switch(p) { 43 | case 0: return 0; 44 | case 1: return -maximum; 45 | case 2: return -maximum; 46 | default: return ranges->min(p); 47 | }; 48 | } 49 | ColorVal max(int p) const { 50 | switch(p) { 51 | case 0: return maximum; 52 | case 1: return maximum; 53 | case 2: return maximum; 54 | default: return ranges->max(p); 55 | }; 56 | } 57 | 58 | void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const { 59 | if (p<3) { minv=min(p); maxv=max(p); return; } 60 | else ranges->minmax(p,pp,minv,maxv); 61 | } 62 | }; 63 | 64 | 65 | template 66 | class TransformYCC : public Transform { 67 | protected: 68 | int maximum; 69 | const ColorRanges *ranges; 70 | 71 | public: 72 | bool virtual init(const ColorRanges *srcRanges) override { 73 | if (srcRanges->numPlanes() < 3) return false; 74 | if (srcRanges->min(0) < 0 || srcRanges->min(1) < 0 || srcRanges->min(2) < 0) return false; 75 | if (srcRanges->min(0) == srcRanges->max(0) || srcRanges->min(1) == srcRanges->max(1) || srcRanges->min(2) == srcRanges->max(2)) return false; 76 | maximum = std::max(std::max(srcRanges->max(0), srcRanges->max(1)), srcRanges->max(2)); 77 | ranges = srcRanges; 78 | return true; 79 | } 80 | 81 | const ColorRanges *meta(Images&, const ColorRanges *srcRanges) override { 82 | return new ColorRangesYCC(maximum, srcRanges); 83 | } 84 | 85 | #ifdef HAS_ENCODER 86 | void data(Images& images) const override { 87 | ColorVal R,G,B,Y,C1,C2; 88 | for (Image& image : images) 89 | for (uint32_t r=0; rmax(0), ranges->max(1), ranges->max(2)}; 109 | for (Image& image : images) { 110 | image.undo_make_constant_plane(0); 111 | image.undo_make_constant_plane(1); 112 | image.undo_make_constant_plane(2); 113 | 114 | const uint32_t scaledRows = image.scaledRows(); 115 | const uint32_t scaledCols = image.scaledCols(); 116 | 117 | for (uint32_t r=0; r/dev/null >/dev/null 9 | then 10 | echo "FLIF not found, please install FLIF first!" 11 | exit 1 12 | fi 13 | if ! $APNGDIS 2>/dev/null |grep -q APNG 14 | then 15 | echo "APNG Disassembler not found, please install it first!" 16 | echo "sudo apt-get install apngdis" 17 | exit 1 18 | fi 19 | 20 | if [ $# -lt 1 ] 21 | then 22 | echo "Usage: apng2flif input.png [output.flif [flif-options]]" 23 | exit 24 | fi 25 | 26 | IN="$1" 27 | shift 28 | 29 | if [ $# -lt 1 ] 30 | then 31 | OUT="$(dirname "$IN")/$(basename "$IN" .png).flif" 32 | else 33 | OUT="$1" 34 | shift 35 | fi 36 | 37 | echo "Decoding $IN ..." 38 | $APNGDIS "$IN" $TMP_PREFIX >/dev/null 39 | FRAME_DELAY="" 40 | for d in $TMP_PREFIX*.txt 41 | do 42 | . ./$d 43 | FRAME_DELAY="$FRAME_DELAY$((1000 * $delay))," 44 | done 45 | echo "Encoding $OUT ..." 46 | $FLIF -F$FRAME_DELAY $@ $TMP_PREFIX*.$TMP_FORMAT "$OUT" 47 | rm $TMP_PREFIX*.$TMP_FORMAT 48 | rm $TMP_PREFIX*.txt 49 | -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame01.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame02.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame03.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame04.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame05.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame06.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame07.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame08.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame09.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame10.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame11.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame12.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame13.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame14.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame15.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame16.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame17.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame18.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame19.png -------------------------------------------------------------------------------- /tools/bouncing_ball_frames/bouncing-ball-frame20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/bouncing_ball_frames/bouncing-ball-frame20.png -------------------------------------------------------------------------------- /tools/build-libpng.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | mkdir ~/build-libpng 4 | cd ~/build-libpng 5 | wget "http://prdownloads.sourceforge.net/libpng/libpng-1.6.28.tar.xz" 6 | tar xf libpng-1.6.28.tar.xz 7 | cd libpng-1.6.28/ 8 | ./configure || cat config.log 9 | make install 10 | -------------------------------------------------------------------------------- /tools/endless_war.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/endless_war.gif -------------------------------------------------------------------------------- /tools/gif2flif: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FLIF="flif" 4 | CONVERT="convert" 5 | TMP_PREFIX="gif2flif_tmp_frame" 6 | TMP_FORMAT="png" 7 | 8 | if ! $FLIF 2>/dev/null >/dev/null 9 | then 10 | echo "FLIF not found, please install FLIF first!" 11 | exit 1 12 | fi 13 | if ! $CONVERT -version 2>/dev/null >/dev/null 14 | then 15 | echo "ImageMagick not found, please install it first!" 16 | echo "sudo apt-get install imagemagick" 17 | exit 1 18 | fi 19 | 20 | if [ $# -lt 1 ] 21 | then 22 | echo "Usage: gif2flif input.gif [output.flif [flif-options]]" 23 | exit 24 | fi 25 | 26 | IN="$1" 27 | shift 28 | 29 | if [ $# -lt 1 ] 30 | then 31 | OUT="$(dirname "$IN")/$(basename "$IN" .gif).flif" 32 | else 33 | OUT="$1" 34 | shift 35 | fi 36 | 37 | echo "Decoding $IN ..." 38 | FRAME_DELAY="$($CONVERT -identify -format "%T0," -coalesce "$IN" $TMP_PREFIX%04d.$TMP_FORMAT)" 39 | echo "Encoding $OUT ..." 40 | $FLIF -F "$FRAME_DELAY" $@ $TMP_PREFIX*.$TMP_FORMAT "$OUT" 41 | rm $TMP_PREFIX*.$TMP_FORMAT 42 | -------------------------------------------------------------------------------- /tools/kodim01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FLIF-hub/FLIF/0074d6fd095d27ce81346aa3fbe9bab59105053e/tools/kodim01.png -------------------------------------------------------------------------------- /tools/sizes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FLIF_FLAGS="" 4 | 5 | make clean 6 | 7 | git reset --hard HEAD > times.log 8 | if [ ! -d "./test_images" ] ; then 9 | echo "Need directory named 'test_images' to contain sample images." 10 | exit 1 11 | fi 12 | 13 | # if "old" already exists for some reason, do NOT work on current branch but bail out 14 | git checkout -b old || exit 2 15 | 16 | 17 | 18 | for i in `seq 1 50`; do 19 | git_head=`git log -1 --format=%h` 20 | # if build fails, make clean and try again 21 | make flif CXXFLAGS="-O3" -j4 || make clean ; make flif CXXFLAGS="-O3" -j4 || (git reset --hard HEAD^1 ; continue) 22 | echo "Run number $i" 23 | mkdir -p test_images/run_${i} 24 | cd test_images 25 | for image in `find . | grep '\.png$'` ; do 26 | ../flif ${FLIF_FLAGS} ${image} run_${i}/${image//png/flif} 27 | done 28 | cd .. 29 | echo "run $i `du -sb test_images/run_${i} | cut -d' ' -f1` $git_head " | tee -a sizes.log 30 | git reset --hard HEAD^1 31 | done 32 | -------------------------------------------------------------------------------- /tools/test-lossy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | FLIF=$1 6 | IN=$2 7 | OUTF=$3 8 | OUTP=$4 9 | 10 | runtest() { 11 | local lossyArg=$1 12 | local orderArg=$2 13 | 14 | rm -f ${OUTF} ${OUTP} 15 | ${FLIF} $lossyArg $orderArg "${IN}" "${OUTF}" 16 | ${FLIF} -d ${OUTF} ${OUTP} 17 | test "`compare -metric AE ${IN} ${OUTP} null: 2>&1`" -lt 500000 18 | } 19 | 20 | runtest -I -Q40 21 | 22 | runtest -I -Q0 23 | 24 | runtest -N -Q40 25 | 26 | runtest -N -Q0 27 | 28 | -------------------------------------------------------------------------------- /tools/test-metadata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | FLIF=$1 6 | IN=$2 7 | OUTF=$3 8 | OUTP=$4 9 | 10 | EXIFIN=../tmp-test/in-exif.xmp 11 | EXIFOUT=../tmp-test/out-exif.xmp 12 | EXIFTOOL_OPTIONS="-XMP:*" 13 | 14 | rm -f ${OUTF} ${OUTP} ${EXIFIN} ${EXIFOUT} 15 | ${FLIF} "${IN}" "${OUTF}" 16 | ${FLIF} -d ${OUTF} ${OUTP} 17 | exiftool ${EXIFTOOL_OPTIONS} ${IN} -o ${EXIFIN} 18 | exiftool ${EXIFTOOL_OPTIONS} ${OUTP} -o ${EXIFOUT} 19 | diff ${EXIFIN} ${EXIFOUT} 20 | 21 | -------------------------------------------------------------------------------- /tools/test-roundtrip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | FLIF=$1 6 | IN=$2 7 | OUTF=$3 8 | OUTP=$4 9 | 10 | runtest() { 11 | local encArgs=$1 12 | local decArgs=$2 13 | 14 | rm -f ${OUTF} ${OUTP} 15 | $FLIF $encArgs "${IN}" "${OUTF}" 16 | $FLIF -d $decArgs ${OUTF} ${OUTP} 17 | test "`compare -metric AE ${IN} ${OUTP} null: 2>&1`" = "0" 18 | } 19 | 20 | runtest -I 21 | 22 | runtest -N 23 | -------------------------------------------------------------------------------- /tools/test-roundtrip_anim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # compare $1 (base name without .png extension, could be multiple frames) one by one to the rest of the arguments 4 | function check { 5 | one=$1*.png 6 | for c in $one 7 | do 8 | if [[ $(compare -metric mepp $c $2 null: 2>&1) == "0 (0, 0)" ]] 9 | then 10 | #echo "OK-compare (identical decoded images)" 11 | shift 12 | continue 13 | else 14 | echo "BUG DETECTED!!!" 15 | echo "PROBLEM IN FILE $1 : $c is not the same image as $2" 16 | exit 1 17 | fi 18 | done 19 | } 20 | 21 | 22 | set -ex 23 | 24 | FLIF=$1 25 | IN=$2 26 | OUTF=$3 27 | 28 | runtest() { 29 | local encArgs=$1 30 | local decArgs=$2 31 | 32 | rm -f ${OUTF} decoded-test-frame*.pam 33 | $FLIF $encArgs test-frame*.png "${OUTF}" 34 | $FLIF -d $decArgs ${OUTF} decoded-test-frame.pam 35 | check test-frame decoded-test-frame*.pam 36 | rm decoded-test-frame*.pam 37 | } 38 | 39 | 40 | convert -coalesce "${IN}" test-frame%04d.png 41 | 42 | # test a few combinations of encode parameters 43 | runtest -I 44 | runtest -NL0 45 | runtest -SP0 46 | runtest -L50 47 | 48 | rm test-frame*.png 49 | -------------------------------------------------------------------------------- /tools/test-roundtrip_anim_framedir.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # compare $1 (base name without .png extension, could be multiple frames) one by one to the rest of the arguments 4 | function check { 5 | one=$1*.png 6 | for c in $one 7 | do 8 | if [[ $(compare -metric mepp $c $2 null: 2>&1) == "0 (0, 0)" ]] 9 | then 10 | #echo "OK-compare (identical decoded images)" 11 | shift 12 | continue 13 | else 14 | echo "BUG DETECTED!!!" 15 | echo "PROBLEM IN FILE $1 : $c is not the same image as $2" 16 | exit 1 17 | fi 18 | done 19 | } 20 | 21 | 22 | set -ex 23 | 24 | FLIF=$1 25 | IN=$2 26 | OUTF=$3 27 | 28 | runtest() { 29 | local encArgs=$1 30 | local decArgs=$2 31 | 32 | rm -f ${OUTF} decoded-test-frame*.pam 33 | $FLIF -vv $encArgs ${IN}/*.png "${OUTF}" 34 | $FLIF -vv -d $decArgs ${OUTF} decoded-test-frame.pam 35 | check ${IN}/ decoded-test-frame*.pam 36 | rm decoded-test-frame*.pam 37 | } 38 | 39 | 40 | 41 | # test a few combinations of encode parameters 42 | runtest -I 43 | runtest -NL0 44 | runtest -SP0 45 | runtest -L50 46 | 47 | --------------------------------------------------------------------------------