- SAIL Frequently Asked Questions (FAQ)
- How old is SAIL?
- Is SAIL cross-platform?
- What's the preferred way of installation?
- Does SAIL support static linking?
- What are the competitors of SAIL?
- Describe the high-level APIs
- Does SAIL provide simple one-line APIs?
- What pixel formats SAIL is able to read?
- In what pixel format SAIL reading functions output images?
- What pixel formats SAIL is able to write?
- Does SAIL support animated and multi-paged images?
- Does SAIL support reading from memory?
- How does SAIL support image formats?
- Does SAIL preload codecs in the initialization routine?
- How does SAIL look for codecs?
- How can I point SAIL to my custom codecs?
- I'd like to reorganize the standard SAIL folder layout on Windows (for standalone build or bundle)
- Describe the memory management techniques implemented in SAIL
- Can I implement an image codec in C++?
- Describe codec info file format
- Are there any C/C++ examples?
- Are there any bindings to other programming languages?
- How many image formats do you plan to implement?
- I have questions, issues, or proposals
SAIL is rebranded ksquirrel-libs rewritten in C, improved and with high-level APIs. Ksquirrel-libs was a set of C++ image codecs for the KSquirrel image viewer. See http://ksquirrel.sourceforge.net.
Technically, SAIL (ksquirrel-libs) was founded in 2003 making it one of the oldest image decoding libraries.
Yes. It's written in pure C11 and is highly portable. However, only the Windows, macOS, and Linux platforms are currently supported. Pull requests to support more platforms are highly welcomed.
- Windows:
vcpkg - macOS:
brew - Linux: native packages if available
See BUILDING.
Yes. Compile with -DBUILD_SHARED_LIBS=OFF. This automatically enables SAIL_COMBINE_CODECS.
SAIL provides four levels of high-level APIs:
Junior: I just want to load this JPEG from a file or memoryAdvanced: I want to load this animated GIF from a file or memoryDeep diver: I want to load this animated GIF from a file or memory and have control over selected codecs and meta dataTechnical diver: I want everything above and my custom I/O source
See EXAMPLES for more.
Yes. SAIL provides four levels of APIs, depending on your needs: junior, advanced, deep diver, and technical diver.
junior is your choice. See EXAMPLES for more.
SAIL codecs always try to support as many input pixel formats as possible. The list of pixel formats that can be read by SAIL is codec-specific and is not publicly available.
For example, some codecs may be able to read just 3 input pixel formats. Other may be able to read 10.
SAIL always tries to output pixel format close to the source pixel format as much as possible. Ideally (but not always), it outputs the same pixel format as stored in the image.
For example, SAIL outputs BPP24-BGR images from full-color BMP files without transparency.
You can also consider conversion functions from libsail-manip.
SAIL codecs always try to support as much output pixel formats as possible. SAIL doesn't convert one pixel format to another in writing operations. Images are always written as is.
The list of pixel formats that can be written by SAIL is codec-specific and is publicly available in every
.codec.info file. It can be accessed through sail_codec_info_from_extension() -> codec_info -> write_features -> output_pixel_formats.
Yes. Just continue reading the image file until the reading functions return SAIL_OK.
If no more frames are available, the reading functions return SAIL_ERROR_NO_MORE_FRAMES.
Yes. SAIL supports reading/writing from/to files and memory. For technical divers, it's also possible to use custom I/O sources.
See sail_start_reading_file(), sail_start_reading_mem(), and sail_start_reading_io().
SAIL supports image formats through dynamically loaded SAIL codecs. End-users never work with the codecs directly. They always work with the abstract high-level APIs.
SAIL doesn't preload codecs in the initialization routine (sail_init()). It loads them on demand.
However, you can preload them explicitly with sail_init_with_flags(SAIL_FLAG_PRELOAD_CODECS).
All codecs get loaded on application startup.
Codecs path search algorithm (first found path wins):
Codecs are combined into a dynamically linked library, so no need to search them.
Same to VCPKG port.
SAIL_CODECS_PATHenvironment variable<SAIL DEPLOYMENT FOLDER>\lib\sail\codecs- Hardcoded
SAIL_CODECS_PATHin config.h
SAIL_CODECS_PATHenvironment variable- Hardcoded
SAIL_CODECS_PATHin config.h
<FOUND PATH>/lib is added to LD_LIBRARY_PATH.
Additionally, SAIL_THIRD_PARTY_CODECS_PATH environment variable with a list of ';'-separated paths
is searched if SAIL_THIRD_PARTY_CODECS_PATH is enabled in CMake, (the default) so you can load your own codecs
from there.
If SAIL_THIRD_PARTY_CODECS_PATH is enabled in CMake (the default), you can set the SAIL_THIRD_PARTY_CODECS_PATH environment variable
to a list of ';'-separated paths containing your custom SAIL codecs.
On Windows, sail.dll location and SAIL_THIRD_PARTY_CODECS_PATH/lib are the only places where codecs DLL dependencies are searched.
No other paths are searched. Use WIN32 API AddDllDirectory to add your own DLL dependencies search path.
On other platforms, SAIL_THIRD_PARTY_CODECS_PATH/lib is added to LD_LIBRARY_PATH.
If SAIL_THIRD_PARTY_CODECS_PATH is OFF, loading custom codecs is disabled.
You can surely do that. However, with the standard layout SAIL detects the codecs' location automatically.
If you reorganize the standard SAIL folder layout, you'll need to specify the new codecs' location by
setting the SAIL_CODECS_PATH environment variable.
Internally, SAIL always cleans up on errors. If you encounter a memory leak on error, please report it.
C only: However, if an engineer encounters an error in the middle of reading or writing an image with the advanced
or a deeper API, it's always a responsibility of the engineer to stop reading or writing with
sail_stop_reading() or sail_stop_writing(). These functions execute a proper cleanup in the underlying codec.
If you don't call sail_stop_reading() or sail_stop_writing() in this situation, be prepared for memory leaks.
C++ only: C++ engineers are more lucky. The C++ binding executes the necessary cleanup automatically in this
situation in ~image_input() or ~image_output().
It's always recommended (but not required) to use the SAIL_TRY() macro to call SAIL functions. It's also always recommended
to clean up in your code with the SAIL_TRY_OR_CLEANUP() macro if you need to.
External pointers that are allocated or modified by SAIL functions stay untouched on error. For example:
struct sail_image *image = NULL;
SAIL_TRY(sail_alloc_image(&image));
/*
* If sail_alloc_palette_for_data() fails, the palette pointer stays untouched (NULL).
* This code prints NULL value on error.
*/
SAIL_TRY_OR_CLEANUP(sail_alloc_palette_for_data(SAIL_PIXEL_FORMAT_BPP24_RGB, color_count, &image->palette));
/* cleanup */ printf("%p\n", image->palette),
sail_destroy_image(image));Or:
void *state = NULL;
struct sail_image *image = NULL;
SAIL_TRY(sail_start_reading_file(..., &state));
/*
* If sail_read_next_frame() fails, the image pointer stays untouched (NULL).
* This code prints NULL value on error.
*/
SAIL_TRY_OR_CLEANUP(sail_read_next_frame(state, &image),
/* cleanup */ printf("%p\n", image),
sail_stop_reading(state));C reading and writing functions require a local void pointer to state. Always set it to NULL before reading or writing. For example:
void *state = NULL;
SAIL_TRY(sail_start_reading_file(..., &state));
SAIL_TRY_OR_CLEANUP(sail_read_next_frame(state, ...),
/* cleanup */ sail_stop_reading(state));Yes. Your codec just needs to export a set of public functions so SAIL can recognize and use it. Theoretically, you can implement your codec in any programming language.
Let's take a hypothetical codec info:
# This section describes the codec per se.
#
[codec]
# Codec layout is a set of functions it exports. Different layouts generations are not compatible.
# libsail supports just a single (current) layout. Cannot be empty.
#
layout=6
# Semantic codec version. Cannot be empty.
#
version=1.0.0
# Codec priority. SAIL uses this property to sort the enumerated codecs by priority
# to speed up search of popular image formats by functions like sail_codec_info_from_path().
#
# HIGHEST = one of the most popular image formats like JPEG
# HIGH = pretty popular and common image format like SVG
# MEDIUM = moderate popularity
# LOW = rare image format
# LOWEST = very rare and/or too specific and/or ancient image format
#
priority=MEDIUM
# Short codec name. Must be uppercase. Cannot be empty.
#
name=ABC
# Codec description. Any human-readable string. Cannot be empty.
#
description=Some ABC Format
# ';'-separated list of hex-encoded magic numbers indentifying this image format.
# Can be empty only if the list of file extensions below is not empty.
#
magic-numbers=34 AB
# ';'-separated list of file extensions indentifying this image format.
# Can be empty only if the list of magic numbers above is not empty.
#
extensions=abc;bca
# ';'-separated list of MIME types indentifying this image format. Can be empty.
#
mime-types=image/abc
# Section of various features describing what the image codec can actually read.
#
[read-features]
# ';'-separated list of what the image codec can actually read.
# Can be empty if the image codec cannot read images.
#
# Possible values:
# STATIC - Can read static images.
# ANIMATED - Can read animated images.
# MULTI-PAGED - Can read multi-paged (but not animated) images.
# META-DATA - Can read image meta data like JPEG comments or EXIF.
# INTERLACED - Can read interlaced images.
# ICCP - Can read embedded ICC profiles.
#
features=STATIC;META-DATA;INTERLACED;ICCP
# Section of various features describing what the image codec can actually write.
#
[write-features]
# ';'-separated list of what the image codec can actually write.
# Can be empty if the image codec cannot write images.
#
# Possible values:
# STATIC - Can write static images.
# ANIMATED - Can write animated images.
# MULTI-PAGED - Can write multi-paged (but not animated) images.
# META-DATA - Can write image meta data like JPEG comments or EXIF.
# INTERLACED - Can write interlaced images.
# ICCP - Can write embedded ICC profiles.
#
features=STATIC;META-DATA;INTERLACED;ICCP
# ';'-separated list of pixel formats the image codec can write.
# Can be empty if the image codec cannot write images.
#
# Note: SAIL doesn't convert images while saving. It writes them 1:1. The image codec
# can take as input and save 8-bit indexed, 24-bit RGB, and 32-bit RGBA images.
#
output-pixel-formats=BPP8-INDEXED;BPP24-RGB;BPP32-BGRA
# ';'-separated list of required properties input images must have. Can be empty.
#
properties=
# ';'-separated list of compressions the image codec can write. Cannot be empty if the image codec
# can write images. If the image codec cannot select compressions, specify UNSUPPORTED.
#
compression-types=DEFLATE;RLE
# Default compression from the list above to use when no explicit compression was selected
# by a client application. Can be empty if the image codec cannot write images.
#
default-compression=DEFLATE
# Minimum compression level. This parameter is not used and must be 0 if the list
# of supported compressions has more than one compression or if the list is empty.
#
# The data type is double. C function atof() is used to convert the value to double.
# Decimal-point character is determined by the current C locale.
#
compression-level-min=1
# Maximum compression level. This parameter is not used and must be 0 if the list
# of supported compressions has more than one compression or if the list is empty.
#
# The data type is double. C function atof() is used to convert the value to double.
# Decimal-point character is determined by the current C locale.
#
compression-level-max=9
# Default compression level to use when no explicit compression level was selected
# by a client application. This parameter is not used and must be 0 if the list
# of supported compressions has more than one compression or if the list is empty.
# Must be in the range of the min/max limits above.
#
# The data type is double. C function atof() is used to convert the value to double.
# Decimal-point character is determined by the current C locale.
#
compression-level-default=6
# Step to increment or decrement compression level. This parameter is not used
# and must be 0 if the list of supported compressions has more than one compression
# or if the list is empty.
#
# The data type is double. C function atof() is used to convert the value to double.
# Decimal-point character is determined by the current C locale.
#
compression-level-step=1
Yes. See EXAMPLES for more.
Yes. Currently SAIL supports the following bindings:
- C++
Pull requests to support more programming languages are highly welcomed.
Ksquirrel-libs supported around 60 image formats. I don't plan to port all of them. However, the most popular image formats will be definitely ported from ksquirrel-libs.
Opening a GitHub issue is the preferred way of communicating and solving problems.
Pull requests are always welcomed.