1 //! Small, portable C library for high-quality conversion of RGBA images to 8-bit indexed-color (palette) images.
2 //! It's powering [pngquant2](https://pngquant.org).
3 //!
4 //! This is a low-level crate exposing a C API. If you're looking for a Rust library, see [imagequant](https://crates.io/crates/imagequant).
5 //!
6 //! ## License
7 //!
8 //! Libimagequant is dual-licensed:
9 //!
10 //! * For Free/Libre Open Source Software it's available under [GPL v3 or later](https://raw.github.com/ImageOptim/libimagequant/master/COPYRIGHT) with additional copyright notices for older parts of the code.
11 //!
12 //! * For use in non-GPL software (e.g. closed-source or App Store distribution) please ask kornel@pngquant.org for a commercial license.
13 //!
14 //! ## Overview
15 //!
16 //! The basic flow is:
17 //!
18 //! 1. Create attributes object and configure the library.
19 //! 2. Create image object from RGBA pixels or data source.
20 //! 3. Perform quantization (generate palette).
21 //! 4. Store remapped image and final palette.
22 //! 5. Free memory.
23 //!
24 //! Please note that libimagequant only handles raw uncompressed arrays of pixels in memory and is completely independent of any file format.
25 //!
26 //! There are 3 ways to create image object for quantization:
27 //!
28 //!   * `liq_image_create_rgba()` for simple, contiguous RGBA pixel arrays (width×height×4 bytes large bitmap).
29 //!   * `liq_image_create_rgba_rows()` for non-contiguous RGBA pixel arrays (that have padding between rows or reverse order, e.g. BMP).
30 //!   * `liq_image_create_custom()` for RGB, ABGR, YUV and all other formats that can be converted on-the-fly to RGBA (you have to supply the conversion function).
31 //!
32 //! Note that "image" here means raw uncompressed pixels. If you have a compressed image file, such as PNG, you must use another library (e.g. lodepng) to decode it first.
33 
34 #![allow(non_camel_case_types)]
35 
36 #[cfg(feature = "openmp")]
37 extern crate openmp_sys;
38 
39 use std::os::raw::{c_int, c_uint, c_char, c_void};
40 use std::error;
41 use std::fmt;
42 use std::error::Error;
43 
44 pub enum liq_attr {}
45 pub enum liq_image {}
46 pub enum liq_result {}
47 pub enum liq_histogram {}
48 pub type liq_color = rgb::RGBA8;
49 
50 #[repr(C)]
51 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
52 pub enum liq_error {
53     LIQ_OK = 0,
54     LIQ_QUALITY_TOO_LOW = 99,
55     LIQ_VALUE_OUT_OF_RANGE = 100,
56     LIQ_OUT_OF_MEMORY,
57     LIQ_ABORTED,
58     LIQ_BITMAP_NOT_AVAILABLE,
59     LIQ_BUFFER_TOO_SMALL,
60     LIQ_INVALID_POINTER,
61     LIQ_UNSUPPORTED,
62 }
63 
64 #[repr(C)]
65 #[derive(Copy, Clone)]
66 pub enum liq_ownership {
67     LIQ_OWN_ROWS = 4,
68     LIQ_OWN_PIXELS = 8,
69     LIQ_COPY_PIXELS = 16,
70 }
71 
72 #[repr(C)]
73 pub struct liq_palette {
74     pub count: c_int,
75     pub entries: [liq_color; 256],
76 }
77 
78 #[repr(C)]
79 #[derive(Debug, Copy, Clone)]
80 pub struct liq_histogram_entry {
81     pub color: liq_color,
82     pub count: c_uint,
83 }
84 
85 impl error::Error for liq_error {
description(&self) -> &str86     fn description(&self) -> &str {
87         match *self {
88             liq_error::LIQ_OK => "OK",
89             liq_error::LIQ_QUALITY_TOO_LOW => "LIQ_QUALITY_TOO_LOW",
90             liq_error::LIQ_VALUE_OUT_OF_RANGE => "VALUE_OUT_OF_RANGE",
91             liq_error::LIQ_OUT_OF_MEMORY => "OUT_OF_MEMORY",
92             liq_error::LIQ_ABORTED => "LIQ_ABORTED",
93             liq_error::LIQ_BITMAP_NOT_AVAILABLE => "BITMAP_NOT_AVAILABLE",
94             liq_error::LIQ_BUFFER_TOO_SMALL => "BUFFER_TOO_SMALL",
95             liq_error::LIQ_INVALID_POINTER => "INVALID_POINTER",
96             liq_error::LIQ_UNSUPPORTED => "LIQ_UNSUPPORTED",
97         }
98     }
99 }
100 
101 impl fmt::Display for liq_error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result102     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103         write!(f, "{}", self.description())
104     }
105 }
106 
107 impl liq_error {
108     #[inline]
is_ok(&self) -> bool109     pub fn is_ok(&self) -> bool {
110         *self == liq_error::LIQ_OK
111     }
112 
is_err(&self) -> bool113     pub fn is_err(&self) -> bool {
114         !self.is_ok()
115     }
116 
117     #[inline]
ok(&self) -> Result<(), liq_error>118     pub fn ok(&self) -> Result<(), liq_error> {
119         match *self {
120             liq_error::LIQ_OK => Ok(()),
121             e => Err(e),
122         }
123     }
124 
125     #[inline]
ok_or<E>(self, err: E) -> Result<(), E>126     pub fn ok_or<E>(self, err: E) -> Result<(), E> {
127         if self.is_ok() {
128             Ok(())
129         } else {
130             Err(err)
131         }
132     }
133 
unwrap(&self)134     pub fn unwrap(&self) {
135         assert!(self.is_ok(), "{}", self);
136     }
137 
expect(&self, msg: &str)138     pub fn expect(&self, msg: &str) {
139         assert!(self.is_ok(), "{}", msg);
140     }
141 }
142 
143 pub type liq_log_callback_function = Option<unsafe extern "C" fn(arg1: &liq_attr, message: *const c_char, user_info: *mut c_void)>;
144 pub type liq_log_flush_callback_function = Option<unsafe extern "C" fn(arg1: &liq_attr, user_info: *mut c_void)>;
145 pub type liq_progress_callback_function = Option<unsafe extern "C" fn(progress_percent: f32, user_info: *mut c_void) -> c_int>;
146 pub type liq_image_get_rgba_row_callback = unsafe extern "C" fn(row_out: *mut liq_color, row: c_int, width: c_int, user_info: *mut c_void);
147 
148 #[link(name="imagequant", kind="static")]
149 extern "C" {
150 
151     /// Returns object that will hold initial settings (attributes) for the library.
152     ///
153     /// The object should be freed using `liq_attr_destroy()` after it's no longer needed.
154     /// Returns `NULL` in the unlikely case that the library cannot run on the current machine (e.g. the library has been compiled for SSE-capable x86 CPU and run on VIA C3 CPU).
liq_attr_create() -> *mut liq_attr155     pub fn liq_attr_create() -> *mut liq_attr;
liq_attr_copy(orig: &liq_attr) -> *mut liq_attr156     pub fn liq_attr_copy(orig: &liq_attr) -> *mut liq_attr;
liq_attr_destroy(attr: &mut liq_attr)157     pub fn liq_attr_destroy(attr: &mut liq_attr);
158 
159     /// Specifies maximum number of colors to use.
160     ///
161     /// The default is 256. Instead of setting a fixed limit it's better to use `liq_set_quality()`.
162     /// The first argument is attributes object from `liq_attr_create()`.
163     /// Returns `LIQ_VALUE_OUT_OF_RANGE` if number of colors is outside the range 2-256.
liq_set_max_colors(attr: &mut liq_attr, colors: c_int) -> liq_error164     pub fn liq_set_max_colors(attr: &mut liq_attr, colors: c_int) -> liq_error;
liq_get_max_colors(attr: &liq_attr) -> c_int165     pub fn liq_get_max_colors(attr: &liq_attr) -> c_int;
liq_set_speed(attr: &mut liq_attr, speed: c_int) -> liq_error166     pub fn liq_set_speed(attr: &mut liq_attr, speed: c_int) -> liq_error;
liq_get_speed(attr: &liq_attr) -> c_int167     pub fn liq_get_speed(attr: &liq_attr) -> c_int;
liq_set_min_posterization(attr: &mut liq_attr, bits: c_int) -> liq_error168     pub fn liq_set_min_posterization(attr: &mut liq_attr, bits: c_int) -> liq_error;
liq_get_min_posterization(attr: &liq_attr) -> c_int169     pub fn liq_get_min_posterization(attr: &liq_attr) -> c_int;
170     /// Quality is in range `0` (worst) to `100` (best) and values are analoguous to JPEG quality (i.e. `80` is usually good enough).
171     ///
172     /// Quantization will attempt to use the lowest number of colors needed to achieve `maximum` quality. `maximum` value of `100` is the default and means conversion as good as possible.
173     /// If it's not possible to convert the image with at least `minimum` quality (i.e. 256 colors is not enough to meet the minimum quality), then `liq_image_quantize()` will fail. The default minumum is `0` (proceeds regardless of quality).
174     /// Quality measures how well the generated palette fits image given to `liq_image_quantize()`. If a different image is remapped with `liq_write_remapped_image()` then actual quality may be different.
175     /// Regardless of the quality settings the number of colors won't exceed the maximum (see `liq_set_max_colors()`).
176     /// The first argument is attributes object from `liq_attr_create()`.
177     ///
178     /// Returns `LIQ_VALUE_OUT_OF_RANGE` if target is lower than minimum or any of them is outside the 0-100 range.
179     /// Returns `LIQ_INVALID_POINTER` if `attr` appears to be invalid.
liq_set_quality(attr: &mut liq_attr, minimum: c_int, maximum: c_int) -> liq_error180     pub fn liq_set_quality(attr: &mut liq_attr, minimum: c_int, maximum: c_int) -> liq_error;
liq_get_min_quality(attr: &liq_attr) -> c_int181     pub fn liq_get_min_quality(attr: &liq_attr) -> c_int;
liq_get_max_quality(attr: &liq_attr) -> c_int182     pub fn liq_get_max_quality(attr: &liq_attr) -> c_int;
liq_set_last_index_transparent(attr: &mut liq_attr, is_last: c_int)183     pub fn liq_set_last_index_transparent(attr: &mut liq_attr, is_last: c_int);
184 
liq_image_create_rgba_rows(attr: &liq_attr, rows: *const *const u8, width: c_int, height: c_int, gamma: f64) -> *mut liq_image185     pub fn liq_image_create_rgba_rows(attr: &liq_attr, rows: *const *const u8, width: c_int, height: c_int, gamma: f64) -> *mut liq_image;
186     /// Creates an object that represents the image pixels to be used for quantization and remapping.
187     ///
188     /// The pixel array must be contiguous run of RGBA pixels (alpha is the last component, 0 = transparent, 255 = opaque).
189     ///
190     /// The first argument is attributes object from `liq_attr_create()`. The same `attr` object should be used for the entire process, from creation of images to quantization.
191     ///
192     /// The `pixels` array must not be modified or freed until this object is freed with `liq_image_destroy()`. See also `liq_image_set_memory_ownership()`.
193     ///
194     /// `width` and `height` are dimensions in pixels. An image 10x10 pixel large will need a 400-byte array.
195     ///
196     /// `gamma` can be `0` for images with the typical 1/2.2 [gamma](https://en.wikipedia.org/wiki/Gamma_correction).
197     /// Otherwise `gamma` must be > 0 and < 1, e.g. `0.45455` (1/2.2) or `0.55555` (1/1.8). Generated palette will use the same gamma unless `liq_set_output_gamma()` is used. If `liq_set_output_gamma` is not used, then it only affects whether brighter or darker areas of the image will get more palette colors allocated.
198     ///
199     /// Returns `NULL` on failure, e.g. if `pixels` is `NULL` or `width`/`height` is <= 0.
liq_image_create_rgba(attr: &liq_attr, bitmap: *const u8, width: c_int, height: c_int, gamma: f64) -> *mut liq_image200     pub fn liq_image_create_rgba(attr: &liq_attr, bitmap: *const u8, width: c_int, height: c_int, gamma: f64) -> *mut liq_image;
201     /// unsafe: It will crash if the owned memory wasn't allocated using `libc::malloc()` (or whatever allocator C side is using)
liq_image_set_memory_ownership(image: &liq_image, own: liq_ownership) -> liq_error202     pub fn liq_image_set_memory_ownership(image: &liq_image, own: liq_ownership) -> liq_error;
203 
liq_set_log_callback(arg1: &mut liq_attr, arg2: liq_log_callback_function, user_info: *mut c_void)204     pub fn liq_set_log_callback(arg1: &mut liq_attr, arg2: liq_log_callback_function, user_info: *mut c_void);
liq_set_log_flush_callback(arg1: &mut liq_attr, arg2: liq_log_flush_callback_function, user_info: *mut c_void)205     pub fn liq_set_log_flush_callback(arg1: &mut liq_attr, arg2: liq_log_flush_callback_function, user_info: *mut c_void);
liq_attr_set_progress_callback(arg1: &mut liq_attr, arg2: liq_progress_callback_function, user_info: *mut c_void)206     pub fn liq_attr_set_progress_callback(arg1: &mut liq_attr, arg2: liq_progress_callback_function, user_info: *mut c_void);
liq_result_set_progress_callback(arg1: &mut liq_result, arg2: liq_progress_callback_function, user_info: *mut c_void)207     pub fn liq_result_set_progress_callback(arg1: &mut liq_result, arg2: liq_progress_callback_function, user_info: *mut c_void);
liq_image_create_custom(attr: &liq_attr, row_callback: liq_image_get_rgba_row_callback, user_info: *mut c_void, width: c_int, height: c_int, gamma: f64) -> *mut liq_image208     pub fn liq_image_create_custom(attr: &liq_attr, row_callback: liq_image_get_rgba_row_callback, user_info: *mut c_void, width: c_int, height: c_int, gamma: f64) -> *mut liq_image;
209     /// Remap assuming the image will be always presented exactly on top of this background.
210     ///
211     /// Takes ownership of the background image (i.e. do NOT use it afterwards, do NOT call liq_image_destroy on it).
212     ///
213     /// The background must have the same size. The foreground image must have a transparent color.
liq_image_set_background(img: &mut liq_image, background: *mut liq_image) -> liq_error214     pub fn liq_image_set_background(img: &mut liq_image, background: *mut liq_image) -> liq_error;
liq_image_set_importance_map(img: &mut liq_image, buffer: *mut u8, buffer_size: usize, own: liq_ownership) -> liq_error215     pub fn liq_image_set_importance_map(img: &mut liq_image, buffer: *mut u8, buffer_size: usize, own: liq_ownership) -> liq_error;
liq_image_add_fixed_color(img: &mut liq_image, color: liq_color) -> liq_error216     pub fn liq_image_add_fixed_color(img: &mut liq_image, color: liq_color) -> liq_error;
liq_image_get_width(img: &liq_image) -> c_int217     pub fn liq_image_get_width(img: &liq_image) -> c_int;
liq_image_get_height(img: &liq_image) -> c_int218     pub fn liq_image_get_height(img: &liq_image) -> c_int;
liq_image_destroy(img: &mut liq_image)219     pub fn liq_image_destroy(img: &mut liq_image);
220 
liq_histogram_create(attr: &liq_attr) -> *mut liq_histogram221     pub fn liq_histogram_create(attr: &liq_attr) -> *mut liq_histogram;
liq_histogram_add_image(hist: &mut liq_histogram, attr: &liq_attr, image: &mut liq_image) -> liq_error222     pub fn liq_histogram_add_image(hist: &mut liq_histogram, attr: &liq_attr, image: &mut liq_image) -> liq_error;
liq_histogram_add_colors(hist: &mut liq_histogram, attr: &liq_attr, entries: *const liq_histogram_entry, num_entries: c_int, gamma: f64) -> liq_error223     pub fn liq_histogram_add_colors(hist: &mut liq_histogram, attr: &liq_attr, entries: *const liq_histogram_entry, num_entries: c_int, gamma: f64) -> liq_error;
liq_histogram_add_fixed_color(hist: &mut liq_histogram, color: liq_color) -> liq_error224     pub fn liq_histogram_add_fixed_color(hist: &mut liq_histogram, color: liq_color) -> liq_error;
liq_histogram_destroy(hist: &mut liq_histogram)225     pub fn liq_histogram_destroy(hist: &mut liq_histogram);
226 
227     /// Performs quantization (palette generation) based on settings in `attr` (from `liq_attr_create()`) and pixels of the image.
228     ///
229     /// Returns `LIQ_OK` if quantization succeeds and sets `liq_result` pointer in `out_result`. The last argument is used for receiving the `result` object:
230     ///
231     ///     liq_result *result;
232     ///     if (LIQ_OK == liq_image_quantize(img, attr, &result)) { // Note &result
233     ///         // result pointer is valid here
234     ///     }
235     ///
236     /// Returns `LIQ_QUALITY_TOO_LOW` if quantization fails due to limit set in `liq_set_quality()`.
237     ///
238     /// See `liq_write_remapped_image()`.
239     ///
240     /// If you want to generate one palette for multiple images at once, see `liq_histogram_create()`.
liq_quantize_image(options: &liq_attr, input_image: &liq_image) -> *mut liq_result241     pub fn liq_quantize_image(options: &liq_attr, input_image: &liq_image) -> *mut liq_result;
liq_histogram_quantize(input_hist: &liq_histogram, options: &liq_attr, result_output: &mut *mut liq_result) -> liq_error242     pub fn liq_histogram_quantize(input_hist: &liq_histogram, options: &liq_attr, result_output: &mut *mut liq_result) -> liq_error;
liq_image_quantize(input_image: &liq_image, options: &liq_attr, result_output: &mut *mut liq_result) -> liq_error243     pub fn liq_image_quantize(input_image: &liq_image, options: &liq_attr, result_output: &mut *mut liq_result) -> liq_error;
244     /// Enables/disables dithering in `liq_write_remapped_image()`.
245     ///
246     /// Dithering level must be between `0` and `1` (inclusive). Dithering level `0` enables fast non-dithered remapping. Otherwise a variation of Floyd-Steinberg error diffusion is used.
247     ///
248     /// Precision of the dithering algorithm depends on the speed setting, see `liq_set_speed()`.
249     ///
250     /// Returns `LIQ_VALUE_OUT_OF_RANGE` if the dithering level is outside the 0-1 range.
liq_set_dithering_level(res: &mut liq_result, dither_level: f32) -> liq_error251     pub fn liq_set_dithering_level(res: &mut liq_result, dither_level: f32) -> liq_error;
liq_set_output_gamma(res: &mut liq_result, gamma: f64) -> liq_error252     pub fn liq_set_output_gamma(res: &mut liq_result, gamma: f64) -> liq_error;
liq_get_output_gamma(result: &liq_result) -> f64253     pub fn liq_get_output_gamma(result: &liq_result) -> f64;
254     /// Returns pointer to palette optimized for image that has been quantized or remapped
255     /// (final refinements are applied to the palette during remapping).
256     ///
257     /// It's valid to call this method before remapping, if you don't plan to remap any images or want to use same palette for multiple images.
258     ///
259     /// `liq_palette->count` contains number of colors (up to 256), `liq_palette->entries[n]` contains RGBA value for nth palette color.
liq_get_palette<'a>(result: &'a mut liq_result) -> &'a liq_palette260     pub fn liq_get_palette<'a>(result: &'a mut liq_result) -> &'a liq_palette;
261     /// Remaps the image to palette and writes its pixels to the given buffer, 1 pixel per byte.
262     ///
263     /// The buffer must be large enough to fit the entire image, i.e. width×height bytes large. For safety, pass the size of the buffer as `buffer_size`.
264     ///
265     /// For best performance call `liq_get_palette()` *after* this function, as palette is improved during remapping (except when `liq_histogram_quantize()` is used).
266     ///
267     /// Returns `LIQ_BUFFER_TOO_SMALL` if given size of the buffer is not enough to fit the entire image.
268     ///
269     ///     int buffer_size = width*height;
270     ///     char *buffer = malloc(buffer_size);
271     ///     if (LIQ_OK == liq_write_remapped_image(result, input_image, buffer, buffer_size)) {
272     ///         liq_palette *pal = liq_get_palette(result);
273     ///         // save image
274     ///     }
275     ///
276     /// See `liq_get_palette()`.
277     ///
278     /// The buffer is assumed to be contiguous, with rows ordered from top to bottom, and no gaps between rows. If you need to write rows with padding or upside-down order, then use `liq_write_remapped_image_rows()`.
279     ///
280     /// Please note that it only writes raw uncompressed pixels to memory. It does not perform any PNG compression. If you'd like to create a PNG file then you need to pass the raw pixel data to another library, e.g. libpng or lodepng. See `rwpng.c` in `pngquant` project for an example how to do that.
liq_write_remapped_image(result: &mut liq_result, input_image: &mut liq_image, buffer: *mut u8, buffer_size: usize) -> liq_error281     pub fn liq_write_remapped_image(result: &mut liq_result, input_image: &mut liq_image, buffer: *mut u8, buffer_size: usize) -> liq_error;
liq_write_remapped_image_rows(result: &mut liq_result, input_image: &mut liq_image, row_pointers: *const *mut u8) -> liq_error282     pub fn liq_write_remapped_image_rows(result: &mut liq_result, input_image: &mut liq_image, row_pointers: *const *mut u8) -> liq_error;
liq_get_quantization_error(result: &liq_result) -> f64283     pub fn liq_get_quantization_error(result: &liq_result) -> f64;
liq_get_quantization_quality(result: &liq_result) -> c_int284     pub fn liq_get_quantization_quality(result: &liq_result) -> c_int;
285 
liq_result_destroy(res: &mut liq_result)286     pub fn liq_result_destroy(res: &mut liq_result);
liq_get_remapping_error(result: &liq_result) -> f64287     pub fn liq_get_remapping_error(result: &liq_result) -> f64;
liq_get_remapping_quality(result: &liq_result) -> c_int288     pub fn liq_get_remapping_quality(result: &liq_result) -> c_int;
liq_version() -> c_int289     pub fn liq_version() -> c_int;
290 }
291 
292 #[test]
links_and_runs()293 fn links_and_runs() {
294     use std::ptr;
295     unsafe {
296         assert!(liq_version() >= 20901);
297         let attr = liq_attr_create();
298         assert!(!attr.is_null());
299         let hist = liq_histogram_create(&*attr);
300         assert!(!hist.is_null());
301         let mut res = ptr::null_mut();
302         liq_histogram_quantize(&*hist, &*attr, &mut res);
303         assert!(res.is_null());
304         liq_histogram_destroy(&mut *hist);
305         liq_attr_destroy(&mut *attr);
306     }
307 }
308