Commit e99a7e67 authored by Andreas Tille's avatar Andreas Tille

Imported Upstream version 2.0.1

parents
version 2.0
-----------
- refactored codebase into pngquant and standalone libimagequant
- reduced memory usage by further 30% (and more for very large images)
- less precise remapping improving speed by 25% in higher speed settings
- --output option for writing converted file under the given path
- light dithering with --floyd=0.5
- fixed regression in dithering of alpha channel
version 1.8
-----------
- min/max quality option (number of colors is automatically adjusted for desired quality level)
- switched option parsing to getopt_long (syntax such as -s1 and --ext=ext is supported)
- significantly improved performance thanks to custom partial sorting
- optional Cocoa (Mac OS X) image reader for color profile support
- reduced memory usage by 20%
- remapping improved for very low number of colors
version 1.7
-----------
- new, accurate RGBA color similarity algorithm
- change of optional SSE3 code to SSE2 that is always enabled on x86-64
- optional OpenMP-based parallelisation of remapping
- changed long options to use double hyphen (-force to --force) [thanks to Jari Aalto]
version 1.6
-----------
- novel dithering algorithm that doesn't add noise unless necessary
- perceptual weighting of colors taking into account edges and noise
- much faster remapping
- improved portability, makefiles and man page
version 1.5
-----------
- palettes postprocessed with Voronoi iteration
- better RGBA color similarity algorithm and Floyd-Steinberg remapping
- SSE optimisations
version 1.4
-----------
- median cut is applied many times in a feedback loop
- speed/quality trade-off option
- faster remap of transparent areas
version 1.3
-----------
- significant changes to the algorithm: use of variance
to find largest dimensioin and to split most varying boxes
- use of premultiplied alpha for color blending
- conversion of output to gamma 2.2
version 1.2
-----------
- color computation done in floating point
- gamma correction applied
- dropped support for very old systems & compilers
version 1.1
-----------
- alpha-sensitive color reduction and dithering
- support -- and - arguments in command line
- number of colors optional (defaults to 256)
- increased maximum number of colors in histogram
version 1.0
-----------
- cleaned up Makefile.unx (better gcc optimizations, "clean" target)
- recompiled binaries with zlib 1.1.4
version 0.95
------------
- fixed Win32 filter bug (binary mode for stdin/stdout)
- fixed cosmetic "choosing colors" verbosity buglet
- fixed palette-size bug when number of colors in image < number requested
- fixed sample-depth bug (png_set_packing() not retroactively smart)
version 0.91
------------
- fixed some verbose/non-verbose oopers
- fixed Win32 (MSVC) portability issues (getpid(), random(), srandom())
- added Makefile.w32 for MSVC (tested with 5.0)
version 0.90
------------
- added support for multiple files on command line
- changed stdin support to write PNG stream to stdout (not "stdin-fs8.png")
version 0.75
------------
- added support for any type of input file [Glenn Randers-Pehrson]
- fixed palette-(re)scaling bug
- added -verbose and -quiet options (default now is -quiet)
- added palette-remapping to minimize size of tRNS chunk
- made Floyd-Steinberg dithering default
- changed output naming scheme to -fs8.png and -or8.png (FS or ordered dither)
version 0.70
------------
- first public release
The quantization and dithering code in pngquant is lifted from Jef Poskanzer's
'ppmquant', part of his wonderful PBMPLUS tool suite.
Greg Roelofs hacked it into a (in his words) "slightly cheesy" 'pamquant' back
in 1997 (see http://pobox.com/~newt/greg_rgba.html) and finally he ripped out
the cheesy file-I/O parts and replaced them with nice PNG code in December
2000. The PNG reading and writing code is a merged and slightly simplified
version of readpng, readpng2, and writepng from his book:
"PNG: The Definitive Guide."
Pngquant therefore inherits both licenses, one for each source file.
Note that both licenses are basically BSD-like; that is, use the code however
you like, as long as you acknowledge its origins.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant.c:
Copyright (C) 1989, 1991 by Jef Poskanzer.
Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by
Stefan Schneider.
Copyright 2009-2013 by Kornel Lesinski.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
rwpng.c (and rwpng.h):
Copyright (c) 1998-2002 Greg Roelofs. All rights reserved.
This software is provided "as is," without warranty of any kind,
express or implied. In no event shall the author or contributors
be held liable for any damages arising in any way from the use of
this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright
notice, disclaimer, and this list of conditions.
2. Redistributions in binary form must reproduce the above copyright
notice, disclaimer, and this list of conditions in the documenta-
tion and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this
software must display the following acknowledgment:
This product includes software developed by Greg Roelofs
and contributors for the book, "PNG: The Definitive Guide,"
published by O'Reilly and Associates.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
To build pngquant from source on Mac OS X and most Linux distributions,
simply run:
$ make
It will create pngquant executable in the current directory. If you'd like
to install it system-wide:
$ sudo make install
By default it will be installed in /usr/local/bin. To install it in another
directory set PREFIX or DESTDIR environmental variables.
pngquant uses GNU Makefile. To compile on FreeBSD you will need to use gmake,
and on Windows the MinGW compiler (MSVC does not support C99).
##Compilation with OpenMP
$ make openmp
This makes pngquant faster in wall-clock time on multicore machines when one
image at a time is processed.
However, it significantly increases total CPU time used, and thus it's not
recommended for server-side and parallelized batch jobs which run many pngquant
instances at a time.
##Compilation with Cocoa image reader
$ USE_COCOA=1 make
On Mac OS X pngquant can use Cocoa framework to load images. This enables
support for color profiles and other input file formats.
##Compilation of `libimagequant.a` only
If you want to use pngquant's conversion algorithm without loading/saving PNG
files, then you can run make in the `lib/` directory.
The library doesn't need libpng or zlib.
# Makefile for pngquant
VERSION = $(shell grep 'define PNGQUANT_VERSION' pngquant.c | egrep -Eo '[12]\.[0-9.]*')
# This changes default "cc" to "gcc", but still allows customization of the CC variable
# if this line causes problems with non-GNU make, just remove it:
CC := $(patsubst cc,gcc,$(CC))
BIN ?= pngquant
PREFIX ?= /usr/local
BINPREFIX = $(PREFIX)/bin
# Alternatively, build libpng and zlib in these directories:
CUSTOMLIBPNG ?= ../libpng
CUSTOMZLIB ?= ../zlib
CFLAGSOPT ?= -DNDEBUG -O3 -fstrict-aliasing -ffast-math -funroll-loops -fomit-frame-pointer -ffinite-math-only
CFLAGS ?= -Wall -Wno-unknown-pragmas -I. -I$(CUSTOMLIBPNG) -I$(CUSTOMZLIB) -I/usr/local/include/ -I/usr/include/ -I/usr/X11/include/ $(CFLAGSOPT)
CFLAGS += -std=c99 $(CFLAGSADD)
LDFLAGS ?= -L$(CUSTOMLIBPNG) -L$(CUSTOMZLIB) -L/usr/local/lib/ -L/usr/lib/ -L/usr/X11/lib/
LDFLAGS += -lpng -lz -lm lib/libimagequant.a -lm $(LDFLAGSADD)
OBJS = pngquant.o rwpng.o
COCOA_OBJS = rwpng_cocoa.o
DISTLIBFILES = lib/*.[ch] lib/Makefile lib/COPYRIGHT lib/MANUAL.md
DISTFILES = $(OBJS:.o=.c) *.[hm] pngquant.1 Makefile README.md INSTALL CHANGELOG COPYRIGHT
TARNAME = pngquant-$(VERSION)
TARFILE = $(TARNAME)-src.tar.bz2
ifdef USE_COCOA
CFLAGS += -mmacosx-version-min=10.6 -DUSE_COCOA=1
LDLAGS += -mmacosx-version-min=10.6
OBJS += $(COCOA_OBJS)
FRAMEWORKS += -framework Cocoa
endif
BUILD_CONFIGURATION="$(CC) $(CFLAGS) $(LDFLAGS)"
all: $(BIN)
lib/libimagequant.a::
$(MAKE) -C lib -$(MAKEFLAGS) static
openmp::
$(MAKE) CFLAGSADD="$(CFLAGSADD) -fopenmp" OPENMPFLAGS="-Bstatic -lgomp" -j8 $(MKFLAGS)
$(BIN): $(OBJS) lib/libimagequant.a
$(CC) $(OBJS) $(LDFLAGS) $(OPENMPFLAGS) $(FRAMEWORKS) -o $@
rwpng_cocoa.o: rwpng_cocoa.m
clang -c $(CFLAGS) -o $@ $<
$(OBJS): rwpng.h build_configuration
install: $(BIN)
install -m 0755 -p $(BIN) $(DESTDIR)$(BINPREFIX)/$(BIN)
uninstall:
rm -f $(DESTDIR)$(BINPREFIX)/$(BIN)
dist: $(TARFILE)
$(TARFILE): $(DISTFILES)
rm -rf $(TARFILE) $(TARNAME)
mkdir -p $(TARNAME)/lib
cp $(DISTFILES) $(TARNAME)
cp $(DISTLIBFILES) $(TARNAME)/lib
tar -cjf $(TARFILE) --numeric-owner --exclude='._*' $(TARNAME)
rm -rf $(TARNAME)
shasum $(TARFILE)
clean:
rm -f $(BIN) $(OBJS) $(COCOA_OBJS) $(TARFILE) build_configuration
$(MAKE) -C lib -$(MAKEFLAGS) clean
build_configuration::
@test -f build_configuration && test $(BUILD_CONFIGURATION) = "`cat build_configuration`" || echo > build_configuration $(BUILD_CONFIGURATION)
.PHONY: all openmp install uninstall dist clean
.DELETE_ON_ERROR:
#pngquant 2
This is the official `pngquant` and `libimagequant`.
[pngquant](http://pngquant.org) converts 24/32-bit RGBA PNGs to 8-bit palette with *alpha channel preserved*.
Such images are compatible with all modern browsers, and a special compatibility setting exists which helps transparency degrade well in Internet Explorer 6.
Quantized files are often 40-70% smaller than their 24/32-bit version.
This utility works on Linux, Mac OS X and Windows.
##Usage
- batch conversion of multiple files: `pngquant *.png`
- Unix-style stdin/stdout chaining: `… | pngquant - | …`
To further reduce file size, try [optipng](http://optipng.sourceforge.net) or [ImageOptim](http://imageoptim.pornel.net).
##Improvements since 1.0
Generated files are both smaller and look much better.
* Significantly better quality of quantisation
- more accurate remapping of semitransparent colors
- special dithering algorithm that does not add noise in well-quantized areas of the image
- uses variance instead of popularity for box selection (improvement suggested in the original median cut paper)
- feedback loop that repeats median cut for poorly quantized colors
- additional colormap improvement using Voronoi iteration
- supports much larger number of colors in input images without degradation of quality
- gamma correction (output is always generated with gamma 2.2 for web compatibility)
* More flexible commandline usage
- number of colors defaults to 256
- long options and standard switches like `--` and `-` are allowed
* Refactored and modernised code
- C99 with no workarounds for old systems
- floating-point math used throughout
- Intel SSE optimisations
- multicore support via OpenMP
- quantization moved to standalone libimagequant
##Options
See `pngquant -h` for full list.
###`--quality min-max`
`min` and `max` are numbers in range 0 (worst) to 100 (perfect), similar to JPEG. pngquant will use the least amount of colors required to meet or exceed the `max` quality. If conversion results in quality below the `min` quality the image won't be saved (if outputting to stdin, 24-bit original will be output) and pngquant will exit with status code 99.
pngquant --quality=65-80 image.png
###`--ext new.png`
Set custom extension (suffix) for output filename. By default `-or8.png` or `-fs8.png` is used. If you use `--ext=.png --force` options pngquant will overwrite input files in place (use with caution).
###`--speed N`
Speed/quality trade-off from 1 (brute-force) to 11 (fastest). The default is 3. Speed 10 has 5% lower quality, but is 8 times faster than the default. Speed 11 disables dithering and lowers compression level.
###`--nofs`
Disables Floyd-Steinberg dithering.
###`--iebug`
Workaround for IE6, which only displays fully opaque pixels. pngquant will make almost-opaque pixels fully opaque and will avoid creating new transparent colors.
###`--version`
Print version information to stdout.
###`-`
Read image from stdin and send result to stdout.
###`--`
Stops processing of arguments. This allows use of file names that start with `-`. If you're using pngquant in a script, it's advisable to put this before file names:
pngquant $OPTIONS -- "$FILE"
© 2009-2013 by Kornel Lesiński.
Copyright (C) 1989, 1991 by Jef Poskanzer.
Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by Stefan Schneider.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
This diff is collapsed.
VERSION=2.0.0
# This changes default "cc" to "gcc", but still allows customization of the CC variable
# if this line causes problems with non-GNU make, just remove it:
CC := $(patsubst cc,gcc,$(CC))
STATICLIB=libimagequant.a
DLL=libimagequant.dll
DLLIMP=libimagequant_dll.a
DLLDEF=libimagequant_dll.def
CFLAGSOPT ?= -DNDEBUG -O3 -fstrict-aliasing -ffast-math -funroll-loops -fomit-frame-pointer -ffinite-math-only
CFLAGS ?= -Wall -Wno-unknown-pragmas -I. $(CFLAGSOPT)
CFLAGS += -std=c99 $(CFLAGSADD)
OBJS = pam.o mediancut.o blur.o mempool.o viter.o nearest.o libimagequant.o
BUILD_CONFIGURATION="$(CC) $(CFLAGS) $(LDFLAGS)"
DISTFILES = $(OBJS:.o=.c) *.h MANUAL.md COPYRIGHT Makefile
TARNAME = libimagequant-$(VERSION)
TARFILE = $(TARNAME)-src.tar.bz2
all: static
static: $(STATICLIB)
dll:
$(MAKE) CFLAGSADD="-DLIQ_EXPORT='__declspec(dllexport)'" $(DLL)
openmp::
$(MAKE) CFLAGSADD=-fopenmp OPENMPFLAGS="-Bstatic -lgomp" -j8 -$(MAKEFLAGS)
$(DLL) $(DLLIMP): $(OBJS)
$(CC) -shared -o $(DLL) $(OBJS) $(LDFLAGS) -Wl,--out-implib,$(DLLIMP),--output-def,$(DLLDEF)
$(STATICLIB): $(OBJS)
$(AR) $(ARFLAGS) $@ $^
$(OBJS): pam.h build_configuration
dist: $(TARFILE)
$(TARFILE): $(DISTFILES)
rm -rf $(TARFILE) $(TARNAME)
mkdir $(TARNAME)
cp $(DISTFILES) $(TARNAME)
tar -cjf $(TARFILE) --numeric-owner --exclude='._*' $(TARNAME)
rm -rf $(TARNAME)
-shasum $(TARFILE)
clean:
rm -f $(OBJS) $(STATICLIB) $(TARFILE) build_configuration
build_configuration::
@test -f build_configuration && test $(BUILD_CONFIGURATION) = "`cat build_configuration`" || echo > build_configuration $(BUILD_CONFIGURATION)
.PHONY: all openmp static clean dist dll
.DELETE_ON_ERROR:
#include "libimagequant.h"
#include "pam.h"
#include "blur.h"
/*
Blurs image horizontally (width 2*size+1) and writes it transposed to dst (called twice gives 2d blur)
*/
static void transposing_1d_blur(unsigned char *restrict src, unsigned char *restrict dst, unsigned int width, unsigned int height, const unsigned int size)
{
for(unsigned int j=0; j < height; j++) {
unsigned char *restrict row = src + j*width;
// accumulate sum for pixels outside line
unsigned int sum;
sum = row[0]*size;
for(unsigned int i=0; i < size; i++) {
sum += row[i];
}
// blur with left side outside line
for(unsigned int i=0; i < size; i++) {
sum -= row[0];
sum += row[i+size];
dst[i*height + j] = sum / (size*2);
}
for(unsigned int i=size; i < width-size; i++) {
sum -= row[i-size];
sum += row[i+size];
dst[i*height + j] = sum / (size*2);
}
// blur with right side outside line
for(unsigned int i=width-size; i < width; i++) {
sum -= row[i-size];
sum += row[width-1];
dst[i*height + j] = sum / (size*2);
}
}
}
/**
* Picks maximum of neighboring pixels (blur + lighten)
*/
LIQ_PRIVATE void max3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height)
{
for(unsigned int j=0; j < height; j++) {
const unsigned char *row = src + j*width,
*prevrow = src + (j > 1 ? j-1 : 0)*width,
*nextrow = src + MIN(height-1,j+1)*width;
unsigned char prev,curr=row[0],next=row[0];
for(unsigned int i=0; i < width-1; i++) {
prev=curr;
curr=next;
next=row[i+1];
unsigned char t1 = MAX(prev,next);
unsigned char t2 = MAX(nextrow[i],prevrow[i]);
*dst++ = MAX(curr,MAX(t1,t2));
}
unsigned char t1 = MAX(curr,next);
unsigned char t2 = MAX(nextrow[width-1],prevrow[width-1]);
*dst++ = MAX(t1,t2);
}
}
/**
* Picks minimum of neighboring pixels (blur + darken)
*/
LIQ_PRIVATE void min3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height)
{
for(unsigned int j=0; j < height; j++) {
const unsigned char *row = src + j*width,
*prevrow = src + (j > 1 ? j-1 : 0)*width,
*nextrow = src + MIN(height-1,j+1)*width;
unsigned char prev,curr=row[0],next=row[0];
for(unsigned int i=0; i < width-1; i++) {
prev=curr;
curr=next;
next=row[i+1];
unsigned char t1 = MIN(prev,next);
unsigned char t2 = MIN(nextrow[i],prevrow[i]);
*dst++ = MIN(curr,MIN(t1,t2));
}
unsigned char t1 = MIN(curr,next);
unsigned char t2 = MIN(nextrow[width-1],prevrow[width-1]);
*dst++ = MIN(t1,t2);
}
}
/*
Filters src image and saves it to dst, overwriting tmp in the process.
Image must be width*height pixels high. Size controls radius of box blur.
*/
LIQ_PRIVATE void blur(unsigned char *src, unsigned char *tmp, unsigned char *dst, unsigned int width, unsigned int height, unsigned int size)
{
assert(size > 0);
if (width < 2*size+1 || height < 2*size+1) return;
transposing_1d_blur(src, tmp, width, height, size);
transposing_1d_blur(tmp, dst, height, width, size);
}
LIQ_PRIVATE void blur(unsigned char *src, unsigned char *tmp, unsigned char *dst, unsigned int width, unsigned int height, unsigned int size);
LIQ_PRIVATE void max3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height);
LIQ_PRIVATE void min3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height);
This diff is collapsed.
//
// http://pngquant.org
//
#ifndef LIBIMAGEQUANT_H
#define LIBIMAGEQUANT_H
#ifndef LIQ_EXPORT
#define LIQ_EXPORT extern
#endif
#ifndef LIQ_PRIVATE
#if defined(__GNUC__) || defined (__llvm__)
#define LIQ_PRIVATE __attribute__((visibility("hidden")))
#else
#define LIQ_PRIVATE
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
typedef struct liq_attr liq_attr;
typedef struct liq_image liq_image;
typedef struct liq_result liq_result;
typedef struct liq_color {
unsigned char r, g, b, a;
} liq_color;
typedef struct liq_palette {
unsigned int count;
liq_color entries[256];
} liq_palette;
typedef enum liq_error {
LIQ_OK = 0,
LIQ_VALUE_OUT_OF_RANGE = 100,
LIQ_OUT_OF_MEMORY,
LIQ_NOT_READY,
LIQ_BITMAP_NOT_AVAILABLE,
LIQ_BUFFER_TOO_SMALL,
LIQ_INVALID_POINTER,
} liq_error;
enum liq_ownership {LIQ_OWN_ROWS=4, LIQ_OWN_PIXELS=8};
LIQ_EXPORT liq_attr* liq_attr_create(void);
LIQ_EXPORT liq_attr* liq_attr_create_with_allocator(void* (*malloc)(size_t), void (*free)(void*));
LIQ_EXPORT liq_attr* liq_attr_copy(liq_attr *orig);
LIQ_EXPORT void liq_attr_destroy(liq_attr *attr);
LIQ_EXPORT liq_error liq_set_max_colors(liq_attr* attr, int colors);
LIQ_EXPORT liq_error liq_set_speed(liq_attr* attr, int speed);
LIQ_EXPORT liq_error liq_set_min_opacity(liq_attr* attr, int min);
LIQ_EXPORT liq_error liq_set_min_posterization(liq_attr* attr, int bits);
LIQ_EXPORT liq_error liq_set_quality(liq_attr* attr, int minimum, int maximum);
LIQ_EXPORT void liq_set_last_index_transparent(liq_attr* attr, int is_last);
typedef void liq_log_callback_function(const liq_attr*, const char *message, void* user_info);
typedef void liq_log_flush_callback_function(const liq_attr*, void* user_info);
LIQ_EXPORT void liq_set_log_callback(liq_attr*, liq_log_callback_function*, void* user_info);
LIQ_EXPORT void liq_set_log_flush_callback(liq_attr*, liq_log_flush_callback_function*, void* user_info);
LIQ_EXPORT liq_image *liq_image_create_rgba_rows(liq_attr *attr, void* rows[], int width, int height, double gamma);
LIQ_EXPORT liq_image *liq_image_create_rgba(liq_attr *attr, void* bitmap, int width, int height, double gamma);
typedef void liq_image_get_rgba_row_callback(liq_color row_out[], int row, int width, void* user_info);
LIQ_EXPORT liq_image *liq_image_create_custom(liq_attr *attr, liq_image_get_rgba_row_callback *row_callback, void* user_info, int width, int height, double gamma);
LIQ_EXPORT liq_error liq_image_set_memory_ownership(liq_image *image, int ownership_flags);
LIQ_EXPORT int liq_image_get_width(const liq_image *img);
LIQ_EXPORT int liq_image_get_height(const liq_image *img);
LIQ_EXPORT void liq_image_destroy(liq_image *img);
LIQ_EXPORT liq_result *liq_quantize_image(liq_attr *options, liq_image *input_image);
LIQ_EXPORT liq_error liq_set_dithering_level(liq_result *res, float dither_level);
LIQ_EXPORT liq_error liq_set_output_gamma(liq_result* res, double gamma);
LIQ_EXPORT double liq_get_output_gamma(const liq_result *result);
LIQ_EXPORT const liq_palette *liq_get_palette(liq_result *result);
LIQ_EXPORT liq_error liq_write_remapped_image(liq_result *result, liq_image *input_image, void *buffer, size_t buffer_size);
LIQ_EXPORT liq_error liq_write_remapped_image_rows(liq_result *result, liq_image *input_image, unsigned char **row_pointers);
LIQ_EXPORT double liq_get_quantization_error(liq_result *result);
LIQ_EXPORT int liq_get_quantization_quality(liq_result *result);
LIQ_EXPORT void liq_result_destroy(liq_result *);
#ifdef __cplusplus
}
#endif
#endif
This diff is collapsed.
LIQ_PRIVATE colormap *mediancut(histogram *hist, const float min_opaque_val, unsigned int newcolors, const double target_mse, const double max_mse);
#include "libimagequant.h"
#include "mempool.h"
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#define ALIGN_MASK 15UL
#define MEMPOOL_RESERVED ((sizeof(struct mempool)+ALIGN_MASK) & ~ALIGN_MASK)
struct mempool {
unsigned int used, size;
void* (*malloc)(size_t);
void (*free)(void*);
struct mempool *next;
};
LIQ_PRIVATE void* mempool_create(mempool *mptr, const unsigned int size, unsigned int max_size, void* (*malloc)(size_t), void (*free)(void*))
{
if (*mptr && ((*mptr)->used+size) <= (*mptr)->size) {
unsigned int prevused = (*mptr)->used;
(*mptr)->used += (size+15UL) & ~0xFUL;
return ((char*)(*mptr)) + prevused;
}
mempool old = *mptr;
if (!max_size) max_size = (1<<17);
max_size = size+ALIGN_MASK > max_size ? size+ALIGN_MASK : max_size;
*mptr = malloc(MEMPOOL_RESERVED + max_size);
if (!*mptr) return NULL;
**mptr = (struct mempool){
.malloc = malloc,
.free = free,
.size = MEMPOOL_RESERVED + max_size,
.used = sizeof(struct mempool),
.next = old,
};
uintptr_t mptr_used_start = (uintptr_t)(*mptr + (*mptr)->used);
(*mptr)->used += (ALIGN_MASK + 1 - (mptr_used_start & ALIGN_MASK)) & ALIGN_MASK; // reserve bytes required to make subsequent allocations aligned
assert(!((uintptr_t)(*mptr + (*mptr)->used) & ALIGN_MASK));
return mempool_alloc(mptr, size, size);
}
LIQ_PRIVATE void* mempool_alloc(mempool *mptr, unsigned int size, unsigned int max_size)
{
if (((*mptr)->used+size) <= (*mptr)->size) {
unsigned int prevused = (*mptr)->used;
(*mptr)->used += (size + ALIGN_MASK) & ~ALIGN_MASK;
return ((char*)(*mptr)) + prevused;
}
return mempool_create(mptr, size, max_size, (*mptr)->malloc, (*mptr)->free);
}
LIQ_PRIVATE void mempool_destroy(mempool m)
{
while (m) {
mempool next = m->next;
m->free(m);
m = next;
}
}
#ifndef MEMPOOL_H
#define MEMPOOL_H
#include <stddef.h>
struct mempool;
typedef struct mempool *mempool;
LIQ_PRIVATE void* mempool_create(mempool *mptr, unsigned int size, unsigned int capacity, void* (*malloc)(size_t), void (*free)(void*));
LIQ_PRIVATE void* mempool_alloc(mempool *mptr, unsigned int size, unsigned int capacity);
LIQ_PRIVATE void mempool_destroy(mempool m);
#endif
#include "libimagequant.h"