mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
Merge branch 'master' of https://github.com/python-imaging/Pillow into namespaced
This commit is contained in:
commit
b0fffd24a4
10
PIL/Image.py
10
PIL/Image.py
|
@ -721,6 +721,16 @@ class Image:
|
||||||
if dither is None:
|
if dither is None:
|
||||||
dither = FLOYDSTEINBERG
|
dither = FLOYDSTEINBERG
|
||||||
|
|
||||||
|
# fake a P-mode image, otherwise the transparency will get lost as there is
|
||||||
|
# currently no other way to convert transparency into an RGBA image
|
||||||
|
if self.mode == "L" and mode == "RGBA" and "transparency" in self.info:
|
||||||
|
from PIL import ImagePalette
|
||||||
|
self.mode = "P"
|
||||||
|
bytePalette = bytes([i//3 for i in range(768)])
|
||||||
|
self.palette = ImagePalette.raw("RGB", bytePalette)
|
||||||
|
self.palette.dirty = 1
|
||||||
|
self.load()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
im = self.im.convert(mode, dither)
|
im = self.im.convert(mode, dither)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -10,8 +10,8 @@ def test_toarray():
|
||||||
return ai["shape"], ai["typestr"], len(ai["data"])
|
return ai["shape"], ai["typestr"], len(ai["data"])
|
||||||
# assert_equal(test("1"), ((100, 128), '|b1', 1600))
|
# assert_equal(test("1"), ((100, 128), '|b1', 1600))
|
||||||
assert_equal(test("L"), ((100, 128), '|u1', 12800))
|
assert_equal(test("L"), ((100, 128), '|u1', 12800))
|
||||||
assert_equal(test("I"), ((100, 128), '<i4', 51200)) # FIXME: wrong?
|
assert_equal(test("I"), ((100, 128), Image._ENDIAN + 'i4', 51200)) # FIXME: wrong?
|
||||||
assert_equal(test("F"), ((100, 128), '<f4', 51200)) # FIXME: wrong?
|
assert_equal(test("F"), ((100, 128), Image._ENDIAN + 'f4', 51200)) # FIXME: wrong?
|
||||||
assert_equal(test("RGB"), ((100, 128, 3), '|u1', 38400))
|
assert_equal(test("RGB"), ((100, 128, 3), '|u1', 38400))
|
||||||
assert_equal(test("RGBA"), ((100, 128, 4), '|u1', 51200))
|
assert_equal(test("RGBA"), ((100, 128, 4), '|u1', 51200))
|
||||||
assert_equal(test("RGBX"), ((100, 128, 4), '|u1', 51200))
|
assert_equal(test("RGBX"), ((100, 128, 4), '|u1', 51200))
|
||||||
|
|
|
@ -18,6 +18,8 @@ def test_pack():
|
||||||
else:
|
else:
|
||||||
return [ord(c) for c in im.tobytes("raw", rawmode)]
|
return [ord(c) for c in im.tobytes("raw", rawmode)]
|
||||||
|
|
||||||
|
order = 1 if Image._ENDIAN == '<' else -1
|
||||||
|
|
||||||
assert_equal(pack("1", "1"), [128])
|
assert_equal(pack("1", "1"), [128])
|
||||||
assert_equal(pack("1", "1;I"), [0])
|
assert_equal(pack("1", "1;I"), [0])
|
||||||
assert_equal(pack("1", "1;R"), [1])
|
assert_equal(pack("1", "1;R"), [1])
|
||||||
|
@ -25,9 +27,9 @@ def test_pack():
|
||||||
|
|
||||||
assert_equal(pack("L", "L"), [1])
|
assert_equal(pack("L", "L"), [1])
|
||||||
|
|
||||||
assert_equal(pack("I", "I"), [1, 0, 0, 0])
|
assert_equal(pack("I", "I"), [1, 0, 0, 0][::order])
|
||||||
|
|
||||||
assert_equal(pack("F", "F"), [0, 0, 128, 63])
|
assert_equal(pack("F", "F"), [0, 0, 128, 63][::order])
|
||||||
|
|
||||||
assert_equal(pack("LA", "LA"), [1, 2])
|
assert_equal(pack("LA", "LA"), [1, 2])
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,12 @@ def test_tobytes():
|
||||||
def tobytes(mode):
|
def tobytes(mode):
|
||||||
return Image.new(mode, (1, 1), 1).tobytes()
|
return Image.new(mode, (1, 1), 1).tobytes()
|
||||||
|
|
||||||
|
order = 1 if Image._ENDIAN == '<' else -1
|
||||||
|
|
||||||
assert_equal(tobytes("L"), b"\x01")
|
assert_equal(tobytes("L"), b"\x01")
|
||||||
assert_equal(tobytes("I;16"), b"\x01\x00")
|
assert_equal(tobytes("I;16"), b"\x01\x00")
|
||||||
assert_equal(tobytes("I;16B"), b"\x00\x01")
|
assert_equal(tobytes("I;16B"), b"\x00\x01")
|
||||||
assert_equal(tobytes("I"), b"\x01\x00\x00\x00")
|
assert_equal(tobytes("I"), b"\x01\x00\x00\x00"[::order])
|
||||||
|
|
||||||
|
|
||||||
def test_convert():
|
def test_convert():
|
||||||
|
|
|
@ -1370,7 +1370,6 @@ _putdata(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
#ifdef WITH_QUANTIZE
|
#ifdef WITH_QUANTIZE
|
||||||
|
|
||||||
#include "Quant.h"
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_quantize(ImagingObject* self, PyObject* args)
|
_quantize(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -282,7 +282,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int i, x, y;
|
int i, x, y;
|
||||||
Imaging im;
|
Imaging im;
|
||||||
int index, error, ascender;
|
int index, error, ascender, descender;
|
||||||
int load_flags;
|
int load_flags;
|
||||||
unsigned char *source;
|
unsigned char *source;
|
||||||
FT_ULong ch;
|
FT_ULong ch;
|
||||||
|
@ -332,6 +332,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
int xx, x0, x1;
|
int xx, x0, x1;
|
||||||
source = (unsigned char*) glyph->bitmap.buffer;
|
source = (unsigned char*) glyph->bitmap.buffer;
|
||||||
ascender = PIXEL(self->face->size->metrics.ascender);
|
ascender = PIXEL(self->face->size->metrics.ascender);
|
||||||
|
descender = PIXEL(self->face->size->metrics.descender);
|
||||||
xx = x + glyph->bitmap_left;
|
xx = x + glyph->bitmap_left;
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
x1 = glyph->bitmap.width;
|
x1 = glyph->bitmap.width;
|
||||||
|
@ -340,7 +341,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
if (xx + x1 > im->xsize)
|
if (xx + x1 > im->xsize)
|
||||||
x1 = im->xsize - xx;
|
x1 = im->xsize - xx;
|
||||||
for (y = 0; y < glyph->bitmap.rows; y++) {
|
for (y = 0; y < glyph->bitmap.rows; y++) {
|
||||||
int yy = y + ascender - glyph->bitmap_top;
|
int yy = y + ascender + descender - glyph->bitmap_top;
|
||||||
if (yy >= 0 && yy < im->ysize) {
|
if (yy >= 0 && yy < im->ysize) {
|
||||||
/* blend this glyph into the buffer */
|
/* blend this glyph into the buffer */
|
||||||
unsigned char *target = im->image8[yy] + xx;
|
unsigned char *target = im->image8[yy] + xx;
|
||||||
|
@ -361,6 +362,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
int xx, x0, x1;
|
int xx, x0, x1;
|
||||||
source = (unsigned char*) glyph->bitmap.buffer;
|
source = (unsigned char*) glyph->bitmap.buffer;
|
||||||
ascender = PIXEL(self->face->size->metrics.ascender);
|
ascender = PIXEL(self->face->size->metrics.ascender);
|
||||||
|
descender = PIXEL(self->face->size->metrics.descender);
|
||||||
xx = x + glyph->bitmap_left;
|
xx = x + glyph->bitmap_left;
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
x1 = glyph->bitmap.width;
|
x1 = glyph->bitmap.width;
|
||||||
|
@ -369,7 +371,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
if (xx + x1 > im->xsize)
|
if (xx + x1 > im->xsize)
|
||||||
x1 = im->xsize - xx;
|
x1 = im->xsize - xx;
|
||||||
for (y = 0; y < glyph->bitmap.rows; y++) {
|
for (y = 0; y < glyph->bitmap.rows; y++) {
|
||||||
int yy = y + ascender - glyph->bitmap_top;
|
int yy = y + ascender + descender - glyph->bitmap_top;
|
||||||
if (yy >= 0 && yy < im->ysize) {
|
if (yy >= 0 && yy < im->ysize) {
|
||||||
/* blend this glyph into the buffer */
|
/* blend this glyph into the buffer */
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -25,17 +25,15 @@
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "Quant.h"
|
#include "QuantTypes.h"
|
||||||
#include "QuantOctree.h"
|
#include "QuantOctree.h"
|
||||||
|
|
||||||
#include "QuantDefines.h"
|
|
||||||
#include "QuantHash.h"
|
#include "QuantHash.h"
|
||||||
#include "QuantHeap.h"
|
#include "QuantHeap.h"
|
||||||
|
|
||||||
#define NO_OUTPUT
|
#define NO_OUTPUT
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned long scale;
|
uint32_t scale;
|
||||||
} PixelHashData;
|
} PixelHashData;
|
||||||
|
|
||||||
typedef struct _PixelList {
|
typedef struct _PixelList {
|
||||||
|
@ -50,7 +48,7 @@ typedef struct _BoxNode {
|
||||||
PixelList *head[3],*tail[3];
|
PixelList *head[3],*tail[3];
|
||||||
int axis;
|
int axis;
|
||||||
int volume;
|
int volume;
|
||||||
unsigned long pixelCount;
|
uint32_t pixelCount;
|
||||||
} BoxNode;
|
} BoxNode;
|
||||||
|
|
||||||
#define _SQR(x) ((x)*(x))
|
#define _SQR(x) ((x)*(x))
|
||||||
|
@ -76,104 +74,92 @@ typedef struct _BoxNode {
|
||||||
((q)->c.g=(p)->c.g>>(s)), \
|
((q)->c.g=(p)->c.g>>(s)), \
|
||||||
((q)->c.b=(p)->c.b>>(s))
|
((q)->c.b=(p)->c.b>>(s))
|
||||||
|
|
||||||
static unsigned long
|
static uint32_t
|
||||||
unshifted_pixel_hash(const HashTable h, const void *p)
|
unshifted_pixel_hash(const HashTable *h, const Pixel pixel)
|
||||||
{
|
{
|
||||||
Pixel *pixel=(Pixel *)&p;
|
return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b);
|
||||||
unsigned long hash=PIXEL_HASH(pixel->c.r,
|
|
||||||
pixel->c.g,
|
|
||||||
pixel->c.b);
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
unshifted_pixel_cmp(const HashTable h, const void *a, const void *b)
|
unshifted_pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2)
|
||||||
{
|
{
|
||||||
Pixel *pixel1=(Pixel *)&a;
|
if (pixel1.c.r==pixel2.c.r) {
|
||||||
Pixel *pixel2=(Pixel *)&b;
|
if (pixel1.c.g==pixel2.c.g) {
|
||||||
if (pixel1->c.r==pixel2->c.r) {
|
if (pixel1.c.b==pixel2.c.b) {
|
||||||
if (pixel1->c.g==pixel2->c.g) {
|
|
||||||
if (pixel1->c.b==pixel2->c.b) {
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return (int)(pixel1->c.b)-(int)(pixel2->c.b);
|
return (int)(pixel1.c.b)-(int)(pixel2.c.b);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return (int)(pixel1->c.g)-(int)(pixel2->c.g);
|
return (int)(pixel1.c.g)-(int)(pixel2.c.g);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return (int)(pixel1->c.r)-(int)(pixel2->c.r);
|
return (int)(pixel1.c.r)-(int)(pixel2.c.r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long
|
static uint32_t
|
||||||
pixel_hash(const HashTable h,const void *p)
|
pixel_hash(const HashTable *h,const Pixel pixel)
|
||||||
{
|
{
|
||||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
||||||
Pixel *pixel=(Pixel *)&p;
|
return PIXEL_HASH(pixel.c.r>>d->scale, pixel.c.g>>d->scale, pixel.c.b>>d->scale);
|
||||||
unsigned long hash=PIXEL_HASH(pixel->c.r>>d->scale,
|
|
||||||
pixel->c.g>>d->scale,
|
|
||||||
pixel->c.b>>d->scale);
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pixel_cmp(const HashTable h,const void *a,const void *b)
|
pixel_cmp(const HashTable *h,const Pixel pixel1, const Pixel pixel2)
|
||||||
{
|
{
|
||||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
||||||
Pixel *pixel1=(Pixel *)&a;
|
uint32_t A,B;
|
||||||
Pixel *pixel2=(Pixel *)&b;
|
A=PIXEL_HASH(pixel1.c.r>>d->scale, pixel1.c.g>>d->scale, pixel1.c.b>>d->scale);
|
||||||
unsigned long A,B;
|
B=PIXEL_HASH(pixel2.c.r>>d->scale, pixel2.c.g>>d->scale, pixel2.c.b>>d->scale);
|
||||||
A=PIXEL_HASH(pixel1->c.r>>d->scale,
|
|
||||||
pixel1->c.g>>d->scale,
|
|
||||||
pixel1->c.b>>d->scale);
|
|
||||||
B=PIXEL_HASH(pixel2->c.r>>d->scale,
|
|
||||||
pixel2->c.g>>d->scale,
|
|
||||||
pixel2->c.b>>d->scale);
|
|
||||||
return (A==B)?0:((A<B)?-1:1);
|
return (A==B)?0:((A<B)?-1:1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
exists_count_func(const HashTable h, const void *key, void **val)
|
exists_count_func(const HashTable *h, const Pixel key, uint32_t *val)
|
||||||
{
|
{
|
||||||
*(unsigned long*)val+=1;
|
*val+=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
new_count_func(const HashTable h, const void *key, void **val)
|
new_count_func(const HashTable *h, const Pixel key, uint32_t *val)
|
||||||
{
|
{
|
||||||
*(unsigned long*)val=1;
|
*val=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rehash_collide(HashTable h,
|
rehash_collide(const HashTable *h,
|
||||||
void **keyp,
|
Pixel *keyp,
|
||||||
void **valp,
|
uint32_t *valp,
|
||||||
void *newkey,
|
Pixel newkey,
|
||||||
void *newval)
|
uint32_t newval)
|
||||||
{
|
{
|
||||||
*valp = (void *)(((unsigned long) *valp) + ((unsigned long) newval));
|
*valp += newval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* %% */
|
/* %% */
|
||||||
|
|
||||||
static HashTable
|
static HashTable *
|
||||||
create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
create_pixel_hash(Pixel *pixelData,uint32_t nPixels)
|
||||||
{
|
{
|
||||||
PixelHashData *d;
|
PixelHashData *d;
|
||||||
HashTable *hash;
|
HashTable *hash;
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
unsigned long timer,timer2,timer3;
|
#ifndef NO_OUTPUT
|
||||||
|
uint32_t timer,timer2,timer3;
|
||||||
|
#endif
|
||||||
|
|
||||||
d=malloc(sizeof(PixelHashData));
|
d=malloc(sizeof(PixelHashData));
|
||||||
if (!d) return NULL;
|
if (!d) return NULL;
|
||||||
hash=hashtable_new(pixel_hash,pixel_cmp);
|
hash=hashtable_new(pixel_hash,pixel_cmp);
|
||||||
hashtable_set_user_data(hash,d);
|
hashtable_set_user_data(hash,d);
|
||||||
d->scale=0;
|
d->scale=0;
|
||||||
|
#ifndef NO_OUTPUT
|
||||||
timer=timer3=clock();
|
timer=timer3=clock();
|
||||||
|
#endif
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (!hashtable_insert_or_update_computed(hash,
|
if (!hashtable_insert_or_update_computed(hash,
|
||||||
(void *)pixelData[i].v,
|
pixelData[i],
|
||||||
new_count_func,
|
new_count_func,
|
||||||
exists_count_func)) {;
|
exists_count_func)) {;
|
||||||
}
|
}
|
||||||
|
@ -181,14 +167,14 @@ create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
||||||
d->scale++;
|
d->scale++;
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
printf ("rehashing - new scale: %d\n",(int)d->scale);
|
printf ("rehashing - new scale: %d\n",(int)d->scale);
|
||||||
#endif
|
|
||||||
timer2=clock();
|
timer2=clock();
|
||||||
hashtable_rehash_compute(hash,rehash_collide);
|
|
||||||
timer2=clock()-timer2;
|
|
||||||
#ifndef NO_OUTPUT
|
|
||||||
printf ("rehash took %f sec\n",timer2/(double)CLOCKS_PER_SEC);
|
|
||||||
#endif
|
#endif
|
||||||
|
hashtable_rehash_compute(hash,rehash_collide);
|
||||||
|
#ifndef NO_OUTPUT
|
||||||
|
timer2=clock()-timer2;
|
||||||
|
printf ("rehash took %f sec\n",timer2/(double)CLOCKS_PER_SEC);
|
||||||
timer+=timer2;
|
timer+=timer2;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
|
@ -201,7 +187,7 @@ create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_pixel_hash(HashTable hash)
|
destroy_pixel_hash(HashTable *hash)
|
||||||
{
|
{
|
||||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(hash);
|
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(hash);
|
||||||
if (d) free(d);
|
if (d) free(d);
|
||||||
|
@ -237,17 +223,15 @@ compute_box_volume(BoxNode *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hash_to_list(HashTable h, const void *key, const void *val, void *u)
|
hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *u)
|
||||||
{
|
{
|
||||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
||||||
PixelList **pl=(PixelList **)u;
|
PixelList **pl=(PixelList **)u;
|
||||||
PixelList *p;
|
PixelList *p;
|
||||||
Pixel *pixel=(Pixel *)&key;
|
|
||||||
int i;
|
int i;
|
||||||
Pixel q;
|
Pixel q;
|
||||||
int count=(unsigned long) val;
|
|
||||||
|
|
||||||
PIXEL_SCALE(pixel,&q,d->scale);
|
PIXEL_SCALE(&pixel,&q,d->scale);
|
||||||
|
|
||||||
p=malloc(sizeof(PixelList));
|
p=malloc(sizeof(PixelList));
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
|
@ -327,7 +311,7 @@ test_sorted(PixelList *pl[3])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
box_heap_cmp(const Heap h, const void *A, const void *B)
|
box_heap_cmp(const Heap *h, const void *A, const void *B)
|
||||||
{
|
{
|
||||||
BoxNode *a=(BoxNode *)A;
|
BoxNode *a=(BoxNode *)A;
|
||||||
BoxNode *b=(BoxNode *)B;
|
BoxNode *b=(BoxNode *)B;
|
||||||
|
@ -341,11 +325,11 @@ splitlists(PixelList *h[3],
|
||||||
PixelList *t[3],
|
PixelList *t[3],
|
||||||
PixelList *nh[2][3],
|
PixelList *nh[2][3],
|
||||||
PixelList *nt[2][3],
|
PixelList *nt[2][3],
|
||||||
unsigned long nCount[2],
|
uint32_t nCount[2],
|
||||||
int axis,
|
int axis,
|
||||||
unsigned long pixelCount)
|
uint32_t pixelCount)
|
||||||
{
|
{
|
||||||
unsigned long left;
|
uint32_t left;
|
||||||
|
|
||||||
PixelList *l,*r,*c,*n;
|
PixelList *l,*r,*c,*n;
|
||||||
int i;
|
int i;
|
||||||
|
@ -476,7 +460,7 @@ split(BoxNode *node)
|
||||||
int i;
|
int i;
|
||||||
PixelList *heads[2][3];
|
PixelList *heads[2][3];
|
||||||
PixelList *tails[2][3];
|
PixelList *tails[2][3];
|
||||||
unsigned long newCounts[2];
|
uint32_t newCounts[2];
|
||||||
BoxNode *left,*right;
|
BoxNode *left,*right;
|
||||||
|
|
||||||
rh=node->head[0]->p.c.r;
|
rh=node->head[0]->p.c.r;
|
||||||
|
@ -618,13 +602,13 @@ split(BoxNode *node)
|
||||||
|
|
||||||
static BoxNode *
|
static BoxNode *
|
||||||
median_cut(PixelList *hl[3],
|
median_cut(PixelList *hl[3],
|
||||||
unsigned long imPixelCount,
|
uint32_t imPixelCount,
|
||||||
int nPixels)
|
int nPixels)
|
||||||
{
|
{
|
||||||
PixelList *tl[3];
|
PixelList *tl[3];
|
||||||
int i;
|
int i;
|
||||||
BoxNode *root;
|
BoxNode *root;
|
||||||
Heap h;
|
Heap* h;
|
||||||
BoxNode *thisNode;
|
BoxNode *thisNode;
|
||||||
|
|
||||||
h=ImagingQuantHeapNew(box_heap_cmp);
|
h=ImagingQuantHeapNew(box_heap_cmp);
|
||||||
|
@ -701,7 +685,7 @@ checkContained(BoxNode *n,Pixel *pp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
annotate_hash_table(BoxNode *n,HashTable h,unsigned long *box)
|
annotate_hash_table(BoxNode *n,HashTable *h,uint32_t *box)
|
||||||
{
|
{
|
||||||
PixelList *p;
|
PixelList *p;
|
||||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
||||||
|
@ -717,7 +701,7 @@ annotate_hash_table(BoxNode *n,HashTable h,unsigned long *box)
|
||||||
}
|
}
|
||||||
for (p=n->head[0];p;p=p->next[0]) {
|
for (p=n->head[0];p;p=p->next[0]) {
|
||||||
PIXEL_UNSCALE(&(p->p),&q,d->scale);
|
PIXEL_UNSCALE(&(p->p),&q,d->scale);
|
||||||
if (!hashtable_insert(h,(void *)q.v,(void *)*box)) {
|
if (!hashtable_insert(h,q,*box)) {
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
printf ("hashtable insert failed\n");
|
printf ("hashtable insert failed\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -731,20 +715,20 @@ annotate_hash_table(BoxNode *n,HashTable h,unsigned long *box)
|
||||||
static int
|
static int
|
||||||
_sort_ulong_ptr_keys(const void *a, const void *b)
|
_sort_ulong_ptr_keys(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
unsigned long A=**(unsigned long **)a;
|
uint32_t A=**(uint32_t **)a;
|
||||||
unsigned long B=**(unsigned long **)b;
|
uint32_t B=**(uint32_t **)b;
|
||||||
return (A==B)?0:((A<B)?-1:+1);
|
return (A==B)?0:((A<B)?-1:+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
resort_distance_tables(unsigned long *avgDist,
|
resort_distance_tables(uint32_t *avgDist,
|
||||||
unsigned long **avgDistSortKey,
|
uint32_t **avgDistSortKey,
|
||||||
Pixel *p,
|
Pixel *p,
|
||||||
unsigned long nEntries)
|
uint32_t nEntries)
|
||||||
{
|
{
|
||||||
unsigned long i,j,k;
|
uint32_t i,j,k;
|
||||||
unsigned long **skRow;
|
uint32_t **skRow;
|
||||||
unsigned long *skElt;
|
uint32_t *skElt;
|
||||||
|
|
||||||
for (i=0;i<nEntries;i++) {
|
for (i=0;i<nEntries;i++) {
|
||||||
avgDist[i*nEntries+i]=0;
|
avgDist[i*nEntries+i]=0;
|
||||||
|
@ -767,12 +751,12 @@ resort_distance_tables(unsigned long *avgDist,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_distance_tables(unsigned long *avgDist,
|
build_distance_tables(uint32_t *avgDist,
|
||||||
unsigned long **avgDistSortKey,
|
uint32_t **avgDistSortKey,
|
||||||
Pixel *p,
|
Pixel *p,
|
||||||
unsigned long nEntries)
|
uint32_t nEntries)
|
||||||
{
|
{
|
||||||
unsigned long i,j;
|
uint32_t i,j;
|
||||||
|
|
||||||
for (i=0;i<nEntries;i++) {
|
for (i=0;i<nEntries;i++) {
|
||||||
avgDist[i*nEntries+i]=0;
|
avgDist[i*nEntries+i]=0;
|
||||||
|
@ -787,7 +771,7 @@ build_distance_tables(unsigned long *avgDist,
|
||||||
for (i=0;i<nEntries;i++) {
|
for (i=0;i<nEntries;i++) {
|
||||||
qsort(avgDistSortKey+i*nEntries,
|
qsort(avgDistSortKey+i*nEntries,
|
||||||
nEntries,
|
nEntries,
|
||||||
sizeof(unsigned long *),
|
sizeof(uint32_t *),
|
||||||
_sort_ulong_ptr_keys);
|
_sort_ulong_ptr_keys);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -795,23 +779,23 @@ build_distance_tables(unsigned long *avgDist,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
map_image_pixels(Pixel *pixelData,
|
map_image_pixels(Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
Pixel *paletteData,
|
Pixel *paletteData,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
unsigned long *avgDist,
|
uint32_t *avgDist,
|
||||||
unsigned long **avgDistSortKey,
|
uint32_t **avgDistSortKey,
|
||||||
unsigned long *pixelArray)
|
uint32_t *pixelArray)
|
||||||
{
|
{
|
||||||
unsigned long *aD,**aDSK;
|
uint32_t *aD,**aDSK;
|
||||||
unsigned long idx;
|
uint32_t idx;
|
||||||
unsigned long i,j;
|
uint32_t i,j;
|
||||||
unsigned long bestdist,bestmatch,dist;
|
uint32_t bestdist,bestmatch,dist;
|
||||||
unsigned long initialdist;
|
uint32_t initialdist;
|
||||||
HashTable h2;
|
HashTable *h2;
|
||||||
|
|
||||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (!hashtable_lookup(h2,(void *)pixelData[i].v,(void **)&bestmatch)) {
|
if (!hashtable_lookup(h2,pixelData[i],&bestmatch)) {
|
||||||
bestmatch=0;
|
bestmatch=0;
|
||||||
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
||||||
bestdist=initialdist;
|
bestdist=initialdist;
|
||||||
|
@ -830,7 +814,7 @@ map_image_pixels(Pixel *pixelData,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||||
}
|
}
|
||||||
pixelArray[i]=bestmatch;
|
pixelArray[i]=bestmatch;
|
||||||
}
|
}
|
||||||
|
@ -841,26 +825,26 @@ map_image_pixels(Pixel *pixelData,
|
||||||
static int
|
static int
|
||||||
map_image_pixels_from_quantized_pixels(
|
map_image_pixels_from_quantized_pixels(
|
||||||
Pixel *pixelData,
|
Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
Pixel *paletteData,
|
Pixel *paletteData,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
unsigned long *avgDist,
|
uint32_t *avgDist,
|
||||||
unsigned long **avgDistSortKey,
|
uint32_t **avgDistSortKey,
|
||||||
unsigned long *pixelArray,
|
uint32_t *pixelArray,
|
||||||
unsigned long *avg[3],
|
uint32_t *avg[3],
|
||||||
unsigned long *count)
|
uint32_t *count)
|
||||||
{
|
{
|
||||||
unsigned long *aD,**aDSK;
|
uint32_t *aD,**aDSK;
|
||||||
unsigned long idx;
|
uint32_t idx;
|
||||||
unsigned long i,j;
|
uint32_t i,j;
|
||||||
unsigned long bestdist,bestmatch,dist;
|
uint32_t bestdist,bestmatch,dist;
|
||||||
unsigned long initialdist;
|
uint32_t initialdist;
|
||||||
HashTable h2;
|
HashTable *h2;
|
||||||
int changes=0;
|
int changes=0;
|
||||||
|
|
||||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (!hashtable_lookup(h2,(void *)pixelData[i].v,(void **)&bestmatch)) {
|
if (!hashtable_lookup(h2,pixelData[i],&bestmatch)) {
|
||||||
bestmatch=pixelArray[i];
|
bestmatch=pixelArray[i];
|
||||||
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
||||||
bestdist=initialdist;
|
bestdist=initialdist;
|
||||||
|
@ -879,7 +863,7 @@ map_image_pixels_from_quantized_pixels(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||||
}
|
}
|
||||||
if (pixelArray[i]!=bestmatch) {
|
if (pixelArray[i]!=bestmatch) {
|
||||||
changes++;
|
changes++;
|
||||||
|
@ -901,29 +885,29 @@ map_image_pixels_from_quantized_pixels(
|
||||||
static int
|
static int
|
||||||
map_image_pixels_from_median_box(
|
map_image_pixels_from_median_box(
|
||||||
Pixel *pixelData,
|
Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
Pixel *paletteData,
|
Pixel *paletteData,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
HashTable *medianBoxHash,
|
HashTable *medianBoxHash,
|
||||||
unsigned long *avgDist,
|
uint32_t *avgDist,
|
||||||
unsigned long **avgDistSortKey,
|
uint32_t **avgDistSortKey,
|
||||||
unsigned long *pixelArray)
|
uint32_t *pixelArray)
|
||||||
{
|
{
|
||||||
unsigned long *aD,**aDSK;
|
uint32_t *aD,**aDSK;
|
||||||
unsigned long idx;
|
uint32_t idx;
|
||||||
unsigned long i,j;
|
uint32_t i,j;
|
||||||
unsigned long bestdist,bestmatch,dist;
|
uint32_t bestdist,bestmatch,dist;
|
||||||
unsigned long initialdist;
|
uint32_t initialdist;
|
||||||
HashTable h2;
|
HashTable *h2;
|
||||||
unsigned long pixelVal;
|
uint32_t pixelVal;
|
||||||
|
|
||||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (hashtable_lookup(h2,(void *)pixelData[i].v,(void **)&pixelVal)) {
|
if (hashtable_lookup(h2,pixelData[i],&pixelVal)) {
|
||||||
pixelArray[i]=pixelVal;
|
pixelArray[i]=pixelVal;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!hashtable_lookup(medianBoxHash,(void *)pixelData[i].v,(void **)&pixelVal)) {
|
if (!hashtable_lookup(medianBoxHash,pixelData[i],&pixelVal)) {
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
printf ("pixel lookup failed\n");
|
printf ("pixel lookup failed\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -948,7 +932,7 @@ map_image_pixels_from_median_box(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pixelArray[i]=bestmatch;
|
pixelArray[i]=bestmatch;
|
||||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||||
}
|
}
|
||||||
hashtable_free(h2);
|
hashtable_free(h2);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -957,27 +941,27 @@ map_image_pixels_from_median_box(
|
||||||
static int
|
static int
|
||||||
compute_palette_from_median_cut(
|
compute_palette_from_median_cut(
|
||||||
Pixel *pixelData,
|
Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
HashTable medianBoxHash,
|
HashTable *medianBoxHash,
|
||||||
Pixel **palette,
|
Pixel **palette,
|
||||||
unsigned long nPaletteEntries)
|
uint32_t nPaletteEntries)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
unsigned long paletteEntry;
|
uint32_t paletteEntry;
|
||||||
Pixel *p;
|
Pixel *p;
|
||||||
unsigned long *avg[3];
|
uint32_t *avg[3];
|
||||||
unsigned long *count;
|
uint32_t *count;
|
||||||
|
|
||||||
*palette=NULL;
|
*palette=NULL;
|
||||||
if (!(count=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset(count,0,sizeof(unsigned long)*nPaletteEntries);
|
memset(count,0,sizeof(uint32_t)*nPaletteEntries);
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
avg[i]=NULL;
|
avg[i]=NULL;
|
||||||
}
|
}
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
if (!(avg[i]=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
if (!(avg[i]=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
if (avg[i]) free (avg[i]);
|
if (avg[i]) free (avg[i]);
|
||||||
}
|
}
|
||||||
|
@ -986,7 +970,7 @@ compute_palette_from_median_cut(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
memset(avg[i],0,sizeof(unsigned long)*nPaletteEntries);
|
memset(avg[i],0,sizeof(uint32_t)*nPaletteEntries);
|
||||||
}
|
}
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
#ifdef TEST_SPLIT_INTEGRITY
|
#ifdef TEST_SPLIT_INTEGRITY
|
||||||
|
@ -998,7 +982,7 @@ compute_palette_from_median_cut(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!hashtable_lookup(medianBoxHash,(void *)pixelData[i].v,(void **)&paletteEntry)) {
|
if (!hashtable_lookup(medianBoxHash,pixelData[i],&paletteEntry)) {
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
printf ("pixel lookup failed\n");
|
printf ("pixel lookup failed\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -1039,11 +1023,11 @@ compute_palette_from_median_cut(
|
||||||
static int
|
static int
|
||||||
recompute_palette_from_averages(
|
recompute_palette_from_averages(
|
||||||
Pixel *palette,
|
Pixel *palette,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
unsigned long *avg[3],
|
uint32_t *avg[3],
|
||||||
unsigned long *count)
|
uint32_t *count)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i=0;i<nPaletteEntries;i++) {
|
for (i=0;i<nPaletteEntries;i++) {
|
||||||
palette[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
|
palette[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
|
||||||
|
@ -1056,18 +1040,18 @@ recompute_palette_from_averages(
|
||||||
static int
|
static int
|
||||||
compute_palette_from_quantized_pixels(
|
compute_palette_from_quantized_pixels(
|
||||||
Pixel *pixelData,
|
Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
Pixel *palette,
|
Pixel *palette,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
unsigned long *avg[3],
|
uint32_t *avg[3],
|
||||||
unsigned long *count,
|
uint32_t *count,
|
||||||
unsigned long *qp)
|
uint32_t *qp)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
|
|
||||||
memset(count,0,sizeof(unsigned long)*nPaletteEntries);
|
memset(count,0,sizeof(uint32_t)*nPaletteEntries);
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
memset(avg[i],0,sizeof(unsigned long)*nPaletteEntries);
|
memset(avg[i],0,sizeof(uint32_t)*nPaletteEntries);
|
||||||
}
|
}
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (qp[i]>=nPaletteEntries) {
|
if (qp[i]>=nPaletteEntries) {
|
||||||
|
@ -1091,35 +1075,35 @@ compute_palette_from_quantized_pixels(
|
||||||
|
|
||||||
static int
|
static int
|
||||||
k_means(Pixel *pixelData,
|
k_means(Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
Pixel *paletteData,
|
Pixel *paletteData,
|
||||||
unsigned long nPaletteEntries,
|
uint32_t nPaletteEntries,
|
||||||
unsigned long *qp,
|
uint32_t *qp,
|
||||||
int threshold)
|
int threshold)
|
||||||
{
|
{
|
||||||
unsigned long *avg[3];
|
uint32_t *avg[3];
|
||||||
unsigned long *count;
|
uint32_t *count;
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
unsigned long *avgDist;
|
uint32_t *avgDist;
|
||||||
unsigned long **avgDistSortKey;
|
uint32_t **avgDistSortKey;
|
||||||
int changes;
|
int changes;
|
||||||
int built=0;
|
int built=0;
|
||||||
|
|
||||||
if (!(count=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
avg[i]=NULL;
|
avg[i]=NULL;
|
||||||
}
|
}
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
if (!(avg[i]=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
if (!(avg[i]=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||||
goto error_1;
|
goto error_1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avgDist=malloc(sizeof(unsigned long)*nPaletteEntries*nPaletteEntries);
|
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries);
|
||||||
if (!avgDist) { goto error_1; }
|
if (!avgDist) { goto error_1; }
|
||||||
|
|
||||||
avgDistSortKey=malloc(sizeof(unsigned long *)*nPaletteEntries*nPaletteEntries);
|
avgDistSortKey=malloc(sizeof(uint32_t *)*nPaletteEntries*nPaletteEntries);
|
||||||
if (!avgDistSortKey) { goto error_2; }
|
if (!avgDistSortKey) { goto error_2; }
|
||||||
|
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
|
@ -1172,26 +1156,26 @@ error_1:
|
||||||
|
|
||||||
int
|
int
|
||||||
quantize(Pixel *pixelData,
|
quantize(Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
unsigned long nQuantPixels,
|
uint32_t nQuantPixels,
|
||||||
Pixel **palette,
|
Pixel **palette,
|
||||||
unsigned long *paletteLength,
|
uint32_t *paletteLength,
|
||||||
unsigned long **quantizedPixels,
|
uint32_t **quantizedPixels,
|
||||||
int kmeans)
|
int kmeans)
|
||||||
{
|
{
|
||||||
PixelList *hl[3];
|
PixelList *hl[3];
|
||||||
HashTable h;
|
HashTable *h;
|
||||||
BoxNode *root;
|
BoxNode *root;
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
unsigned long *qp;
|
uint32_t *qp;
|
||||||
unsigned long nPaletteEntries;
|
uint32_t nPaletteEntries;
|
||||||
|
|
||||||
unsigned long *avgDist;
|
uint32_t *avgDist;
|
||||||
unsigned long **avgDistSortKey;
|
uint32_t **avgDistSortKey;
|
||||||
Pixel *p;
|
Pixel *p;
|
||||||
|
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
unsigned long timer,timer2;
|
uint32_t timer,timer2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NO_OUTPUT
|
#ifndef NO_OUTPUT
|
||||||
|
@ -1266,13 +1250,13 @@ quantize(Pixel *pixelData,
|
||||||
free_box_tree(root);
|
free_box_tree(root);
|
||||||
root=NULL;
|
root=NULL;
|
||||||
|
|
||||||
qp=malloc(sizeof(unsigned long)*nPixels);
|
qp=malloc(sizeof(uint32_t)*nPixels);
|
||||||
if (!qp) { goto error_4; }
|
if (!qp) { goto error_4; }
|
||||||
|
|
||||||
avgDist=malloc(sizeof(unsigned long)*nPaletteEntries*nPaletteEntries);
|
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries);
|
||||||
if (!avgDist) { goto error_5; }
|
if (!avgDist) { goto error_5; }
|
||||||
|
|
||||||
avgDistSortKey=malloc(sizeof(unsigned long *)*nPaletteEntries*nPaletteEntries);
|
avgDistSortKey=malloc(sizeof(uint32_t *)*nPaletteEntries*nPaletteEntries);
|
||||||
if (!avgDistSortKey) { goto error_6; }
|
if (!avgDistSortKey) { goto error_6; }
|
||||||
|
|
||||||
if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) {
|
if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) {
|
||||||
|
@ -1286,12 +1270,12 @@ quantize(Pixel *pixelData,
|
||||||
#ifdef TEST_NEAREST_NEIGHBOUR
|
#ifdef TEST_NEAREST_NEIGHBOUR
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
{
|
{
|
||||||
unsigned long bestmatch,bestdist,dist;
|
uint32_t bestmatch,bestdist,dist;
|
||||||
HashTable h2;
|
HashTable *h2;
|
||||||
printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock();
|
printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock();
|
||||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
if (hashtable_lookup(h2,(void *)pixelData[i].v,(void **)&paletteEntry)) {
|
if (hashtable_lookup(h2,pixelData[i],&paletteEntry)) {
|
||||||
bestmatch=paletteEntry;
|
bestmatch=paletteEntry;
|
||||||
} else {
|
} else {
|
||||||
bestmatch=0;
|
bestmatch=0;
|
||||||
|
@ -1312,7 +1296,7 @@ quantize(Pixel *pixelData,
|
||||||
bestmatch=j;
|
bestmatch=j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||||
}
|
}
|
||||||
if (qp[i]!=bestmatch ) {
|
if (qp[i]!=bestmatch ) {
|
||||||
printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n",
|
printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n",
|
||||||
|
@ -1375,53 +1359,52 @@ error_0:
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Pixel new;
|
Pixel new;
|
||||||
Pixel furthest;
|
Pixel furthest;
|
||||||
unsigned long furthestDistance;
|
uint32_t furthestDistance;
|
||||||
int secondPixel;
|
int secondPixel;
|
||||||
} DistanceData;
|
} DistanceData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
compute_distances(const HashTable h, const void *key, void **val, void *u)
|
compute_distances(const HashTable *h, const Pixel pixel, uint32_t *dist, void *u)
|
||||||
{
|
{
|
||||||
DistanceData *data=(DistanceData *)u;
|
DistanceData *data=(DistanceData *)u;
|
||||||
Pixel *pixel=(Pixel *)&key;
|
uint32_t oldDist=*dist;
|
||||||
unsigned long oldDist=*(unsigned long *)val;
|
uint32_t newDist;
|
||||||
unsigned long newDist;
|
newDist=_DISTSQR(&(data->new),&pixel);
|
||||||
newDist=_DISTSQR(&(data->new),pixel);
|
|
||||||
if (data->secondPixel || newDist<oldDist) {
|
if (data->secondPixel || newDist<oldDist) {
|
||||||
*(unsigned long *)val=newDist;
|
*dist=newDist;
|
||||||
oldDist=newDist;
|
oldDist=newDist;
|
||||||
}
|
}
|
||||||
if (oldDist>data->furthestDistance) {
|
if (oldDist>data->furthestDistance) {
|
||||||
data->furthestDistance=oldDist;
|
data->furthestDistance=oldDist;
|
||||||
data->furthest.v=pixel->v;
|
data->furthest.v=pixel.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
quantize2(Pixel *pixelData,
|
quantize2(Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
unsigned long nQuantPixels,
|
uint32_t nQuantPixels,
|
||||||
Pixel **palette,
|
Pixel **palette,
|
||||||
unsigned long *paletteLength,
|
uint32_t *paletteLength,
|
||||||
unsigned long **quantizedPixels,
|
uint32_t **quantizedPixels,
|
||||||
int kmeans)
|
int kmeans)
|
||||||
{
|
{
|
||||||
HashTable h;
|
HashTable *h;
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
unsigned long mean[3];
|
uint32_t mean[3];
|
||||||
Pixel *p;
|
Pixel *p;
|
||||||
DistanceData data;
|
DistanceData data;
|
||||||
|
|
||||||
unsigned long *qp;
|
uint32_t *qp;
|
||||||
unsigned long *avgDist;
|
uint32_t *avgDist;
|
||||||
unsigned long **avgDistSortKey;
|
uint32_t **avgDistSortKey;
|
||||||
|
|
||||||
p=malloc(sizeof(Pixel)*nQuantPixels);
|
p=malloc(sizeof(Pixel)*nQuantPixels);
|
||||||
if (!p) return 0;
|
if (!p) return 0;
|
||||||
mean[0]=mean[1]=mean[2]=0;
|
mean[0]=mean[1]=mean[2]=0;
|
||||||
h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||||
for (i=0;i<nPixels;i++) {
|
for (i=0;i<nPixels;i++) {
|
||||||
hashtable_insert(h,(void *)pixelData[i].v,(void *)0xffffffff);
|
hashtable_insert(h,pixelData[i],0xffffffff);
|
||||||
mean[0]+=pixelData[i].c.r;
|
mean[0]+=pixelData[i].c.r;
|
||||||
mean[1]+=pixelData[i].c.g;
|
mean[1]+=pixelData[i].c.g;
|
||||||
mean[2]+=pixelData[i].c.b;
|
mean[2]+=pixelData[i].c.b;
|
||||||
|
@ -1438,13 +1421,13 @@ quantize2(Pixel *pixelData,
|
||||||
}
|
}
|
||||||
hashtable_free(h);
|
hashtable_free(h);
|
||||||
|
|
||||||
qp=malloc(sizeof(unsigned long)*nPixels);
|
qp=malloc(sizeof(uint32_t)*nPixels);
|
||||||
if (!qp) { goto error_1; }
|
if (!qp) { goto error_1; }
|
||||||
|
|
||||||
avgDist=malloc(sizeof(unsigned long)*nQuantPixels*nQuantPixels);
|
avgDist=malloc(sizeof(uint32_t)*nQuantPixels*nQuantPixels);
|
||||||
if (!avgDist) { goto error_2; }
|
if (!avgDist) { goto error_2; }
|
||||||
|
|
||||||
avgDistSortKey=malloc(sizeof(unsigned long *)*nQuantPixels*nQuantPixels);
|
avgDistSortKey=malloc(sizeof(uint32_t *)*nQuantPixels*nQuantPixels);
|
||||||
if (!avgDistSortKey) { goto error_3; }
|
if (!avgDistSortKey) { goto error_3; }
|
||||||
|
|
||||||
if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) {
|
if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) {
|
||||||
|
@ -1482,9 +1465,9 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
||||||
UINT8* pp;
|
UINT8* pp;
|
||||||
Pixel* p;
|
Pixel* p;
|
||||||
Pixel* palette;
|
Pixel* palette;
|
||||||
unsigned long paletteLength;
|
uint32_t paletteLength;
|
||||||
int result;
|
int result;
|
||||||
unsigned long* newData;
|
uint32_t* newData;
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
int withAlpha = 0;
|
int withAlpha = 0;
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* The Python Imaging Library
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* image quantizer
|
|
||||||
*
|
|
||||||
* Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
|
|
||||||
*
|
|
||||||
* See the README file for information on usage and redistribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __QUANT_H__
|
|
||||||
#define __QUANT_H__
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
unsigned char r,g,b,a;
|
|
||||||
} c;
|
|
||||||
struct {
|
|
||||||
unsigned char v[4];
|
|
||||||
} a;
|
|
||||||
unsigned long v;
|
|
||||||
} Pixel;
|
|
||||||
|
|
||||||
int quantize(Pixel *,
|
|
||||||
unsigned long,
|
|
||||||
unsigned long,
|
|
||||||
Pixel **,
|
|
||||||
unsigned long *,
|
|
||||||
unsigned long **,
|
|
||||||
int);
|
|
||||||
|
|
||||||
int quantize2(Pixel *,
|
|
||||||
unsigned long,
|
|
||||||
unsigned long,
|
|
||||||
Pixel **,
|
|
||||||
unsigned long *,
|
|
||||||
unsigned long **,
|
|
||||||
int);
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* The Python Imaging Library
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* image quantizer
|
|
||||||
*
|
|
||||||
* Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
|
|
||||||
*
|
|
||||||
* See the README file for information on usage and redistribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DEFINES_H__
|
|
||||||
#define __DEFINES_H__
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
void *newMalloc(size_t,const char *,const char *,int);
|
|
||||||
void newFree(void *,const char *,const char *,int);
|
|
||||||
void print_malloc_stats();
|
|
||||||
#define malloc(x) newMalloc(x,__FILE__,__FUNCTION__,__LINE__)
|
|
||||||
#define free(x) newFree(x,__FILE__,__FUNCTION__,__LINE__)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -22,35 +22,35 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "QuantHash.h"
|
#include "QuantHash.h"
|
||||||
#include "QuantDefines.h"
|
|
||||||
|
|
||||||
typedef struct _IntHashNode {
|
typedef struct _HashNode {
|
||||||
struct _IntHashNode *next;
|
struct _HashNode *next;
|
||||||
void *key,*value;
|
HashKey_t key;
|
||||||
} IntHashNode;
|
HashVal_t value;
|
||||||
|
} HashNode;
|
||||||
|
|
||||||
typedef struct _IntHashTable {
|
typedef struct _HashTable {
|
||||||
IntHashNode **table;
|
HashNode **table;
|
||||||
unsigned long length;
|
uint32_t length;
|
||||||
unsigned long count;
|
uint32_t count;
|
||||||
HashFunc hashFunc;
|
HashFunc hashFunc;
|
||||||
HashCmpFunc cmpFunc;
|
HashCmpFunc cmpFunc;
|
||||||
DestroyFunc keyDestroyFunc;
|
KeyDestroyFunc keyDestroyFunc;
|
||||||
DestroyFunc valDestroyFunc;
|
ValDestroyFunc valDestroyFunc;
|
||||||
void *userData;
|
void *userData;
|
||||||
} IntHashTable;
|
} HashTable;
|
||||||
|
|
||||||
#define MIN_LENGTH 11
|
#define MIN_LENGTH 11
|
||||||
#define RESIZE_FACTOR 3
|
#define RESIZE_FACTOR 3
|
||||||
|
|
||||||
static int _hashtable_insert_node(IntHashTable *,IntHashNode *,int,int,CollisionFunc);
|
static int _hashtable_insert_node(HashTable *,HashNode *,int,int,CollisionFunc);
|
||||||
#if 0
|
#if 0
|
||||||
static int _hashtable_test(IntHashTable *);
|
static int _hashtable_test(HashTable *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HashTable hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
||||||
IntHashTable *h;
|
HashTable *h;
|
||||||
h=malloc(sizeof(IntHashTable));
|
h=malloc(sizeof(HashTable));
|
||||||
if (!h) { return NULL; }
|
if (!h) { return NULL; }
|
||||||
h->hashFunc=hf;
|
h->hashFunc=hf;
|
||||||
h->cmpFunc=cf;
|
h->cmpFunc=cf;
|
||||||
|
@ -59,25 +59,24 @@ HashTable hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
||||||
h->length=MIN_LENGTH;
|
h->length=MIN_LENGTH;
|
||||||
h->count=0;
|
h->count=0;
|
||||||
h->userData=NULL;
|
h->userData=NULL;
|
||||||
h->table=malloc(sizeof(IntHashNode *)*h->length);
|
h->table=malloc(sizeof(HashNode *)*h->length);
|
||||||
if (!h->table) { free(h); return NULL; }
|
if (!h->table) { free(h); return NULL; }
|
||||||
memset (h->table,0,sizeof(IntHashNode *)*h->length);
|
memset (h->table,0,sizeof(HashNode *)*h->length);
|
||||||
return (HashTable)h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hashtable_destroy(HashTable H,const void *key,const void *val,void *u) {
|
static void _hashtable_destroy(const HashTable *h,const HashKey_t key,const HashVal_t val,void *u) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
if (h->keyDestroyFunc) {
|
||||||
if (h->keyDestroyFunc&&key) {
|
h->keyDestroyFunc(h,key);
|
||||||
h->keyDestroyFunc((HashTable)h,(void *)key);
|
|
||||||
}
|
}
|
||||||
if (h->valDestroyFunc&&val) {
|
if (h->valDestroyFunc) {
|
||||||
h->valDestroyFunc((HashTable)h,(void *)val);
|
h->valDestroyFunc(h,val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long _findPrime(unsigned long start,int dir) {
|
static uint32_t _findPrime(uint32_t start,int dir) {
|
||||||
static int unit[]={0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0};
|
static int unit[]={0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0};
|
||||||
unsigned long t;
|
uint32_t t;
|
||||||
while (start>1) {
|
while (start>1) {
|
||||||
if (!unit[start&0x0f]) {
|
if (!unit[start&0x0f]) {
|
||||||
start+=dir;
|
start+=dir;
|
||||||
|
@ -94,22 +93,20 @@ static unsigned long _findPrime(unsigned long start,int dir) {
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hashtable_rehash(IntHashTable *h,
|
static void _hashtable_rehash(HashTable *h,CollisionFunc cf,uint32_t newSize) {
|
||||||
CollisionFunc cf,
|
HashNode **oldTable=h->table;
|
||||||
unsigned long newSize) {
|
uint32_t i;
|
||||||
IntHashNode **oldTable=h->table;
|
HashNode *n,*nn;
|
||||||
unsigned long i;
|
uint32_t oldSize;
|
||||||
IntHashNode *n,*nn;
|
|
||||||
unsigned long oldSize;
|
|
||||||
oldSize=h->length;
|
oldSize=h->length;
|
||||||
h->table=malloc(sizeof(IntHashNode *)*newSize);
|
h->table=malloc(sizeof(HashNode *)*newSize);
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
h->table=oldTable;
|
h->table=oldTable;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
h->length=newSize;
|
h->length=newSize;
|
||||||
h->count=0;
|
h->count=0;
|
||||||
memset (h->table,0,sizeof(IntHashNode *)*h->length);
|
memset (h->table,0,sizeof(HashNode *)*h->length);
|
||||||
for (i=0;i<oldSize;i++) {
|
for (i=0;i<oldSize;i++) {
|
||||||
for (n=oldTable[i];n;n=nn) {
|
for (n=oldTable[i];n;n=nn) {
|
||||||
nn=n->next;
|
nn=n->next;
|
||||||
|
@ -119,9 +116,9 @@ static void _hashtable_rehash(IntHashTable *h,
|
||||||
free(oldTable);
|
free(oldTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hashtable_resize(IntHashTable *h) {
|
static void _hashtable_resize(HashTable *h) {
|
||||||
unsigned long newSize;
|
uint32_t newSize;
|
||||||
unsigned long oldSize;
|
uint32_t oldSize;
|
||||||
oldSize=h->length;
|
oldSize=h->length;
|
||||||
newSize=oldSize;
|
newSize=oldSize;
|
||||||
if (h->count*RESIZE_FACTOR<h->length) {
|
if (h->count*RESIZE_FACTOR<h->length) {
|
||||||
|
@ -136,13 +133,13 @@ static void _hashtable_resize(IntHashTable *h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int _hashtable_test(IntHashTable *h) {
|
static int _hashtable_test(HashTable *h) {
|
||||||
unsigned long i;
|
uint32_t i;
|
||||||
int j;
|
int j;
|
||||||
IntHashNode *n;
|
HashNode *n;
|
||||||
for (i=0;i<h->length;i++) {
|
for (i=0;i<h->length;i++) {
|
||||||
for (n=h->table[i];n&&n->next;n=n->next) {
|
for (n=h->table[i];n&&n->next;n=n->next) {
|
||||||
j=h->cmpFunc((HashTable)h,n->key,n->next->key);
|
j=h->cmpFunc(h,n->key,n->next->key);
|
||||||
printf ("%c",j?(j<0?'-':'+'):'=');
|
printf ("%c",j?(j<0?'-':'+'):'=');
|
||||||
}
|
}
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
|
@ -151,26 +148,26 @@ static int _hashtable_test(IntHashTable *h) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int _hashtable_insert_node(IntHashTable *h,IntHashNode *node,int resize,int update,CollisionFunc cf) {
|
static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) {
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,node->key)%h->length;
|
uint32_t hash=h->hashFunc(h,node->key)%h->length;
|
||||||
IntHashNode **n,*nv;
|
HashNode **n,*nv;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
||||||
nv=*n;
|
nv=*n;
|
||||||
i=h->cmpFunc((HashTable)h,nv->key,node->key);
|
i=h->cmpFunc(h,nv->key,node->key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
if (cf) {
|
if (cf) {
|
||||||
nv->key=node->key;
|
nv->key=node->key;
|
||||||
cf((HashTable)h,&(nv->key),&(nv->value),node->key,node->value);
|
cf(h,&(nv->key),&(nv->value),node->key,node->value);
|
||||||
free(node);
|
free(node);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if (h->valDestroyFunc) {
|
if (h->valDestroyFunc) {
|
||||||
h->valDestroyFunc((HashTable)h,nv->value);
|
h->valDestroyFunc(h,nv->value);
|
||||||
}
|
}
|
||||||
if (h->keyDestroyFunc) {
|
if (h->keyDestroyFunc) {
|
||||||
h->keyDestroyFunc((HashTable)h,nv->key);
|
h->keyDestroyFunc(h,nv->key);
|
||||||
}
|
}
|
||||||
nv->key=node->key;
|
nv->key=node->key;
|
||||||
nv->value=node->value;
|
nv->value=node->value;
|
||||||
|
@ -192,17 +189,17 @@ static int _hashtable_insert_node(IntHashTable *h,IntHashNode *node,int resize,i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _hashtable_insert(IntHashTable *h,void *key,void *val,int resize,int update) {
|
static int _hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val,int resize,int update) {
|
||||||
IntHashNode **n,*nv;
|
HashNode **n,*nv;
|
||||||
IntHashNode *t;
|
HashNode *t;
|
||||||
int i;
|
int i;
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
|
|
||||||
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
||||||
nv=*n;
|
nv=*n;
|
||||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
i=h->cmpFunc(h,nv->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
if (h->valDestroyFunc) { h->valDestroyFunc((HashTable)h,nv->value); }
|
if (h->valDestroyFunc) { h->valDestroyFunc(h,nv->value); }
|
||||||
nv->value=val;
|
nv->value=val;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (i>0) {
|
} else if (i>0) {
|
||||||
|
@ -210,7 +207,7 @@ static int _hashtable_insert(IntHashTable *h,void *key,void *val,int resize,int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!update) {
|
if (!update) {
|
||||||
t=malloc(sizeof(IntHashNode));
|
t=malloc(sizeof(HashNode));
|
||||||
if (!t) return 0;
|
if (!t) return 0;
|
||||||
t->next=*n;
|
t->next=*n;
|
||||||
*n=t;
|
*n=t;
|
||||||
|
@ -224,15 +221,15 @@ static int _hashtable_insert(IntHashTable *h,void *key,void *val,int resize,int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _hashtable_lookup_or_insert(IntHashTable *h,void *key,void **retVal,void *newVal,int resize) {
|
static int _hashtable_lookup_or_insert(HashTable *h,HashKey_t key,HashVal_t *retVal,HashVal_t newVal,int resize) {
|
||||||
IntHashNode **n,*nv;
|
HashNode **n,*nv;
|
||||||
IntHashNode *t;
|
HashNode *t;
|
||||||
int i;
|
int i;
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
|
|
||||||
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
||||||
nv=*n;
|
nv=*n;
|
||||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
i=h->cmpFunc(h,nv->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
*retVal=nv->value;
|
*retVal=nv->value;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -240,7 +237,7 @@ static int _hashtable_lookup_or_insert(IntHashTable *h,void *key,void **retVal,v
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t=malloc(sizeof(IntHashNode));
|
t=malloc(sizeof(HashNode));
|
||||||
if (!t) return 0;
|
if (!t) return 0;
|
||||||
t->next=*n;
|
t->next=*n;
|
||||||
*n=t;
|
*n=t;
|
||||||
|
@ -252,26 +249,25 @@ static int _hashtable_lookup_or_insert(IntHashTable *h,void *key,void **retVal,v
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_insert_or_update_computed(HashTable H,
|
int hashtable_insert_or_update_computed(HashTable *h,
|
||||||
void *key,
|
HashKey_t key,
|
||||||
ComputeFunc newFunc,
|
ComputeFunc newFunc,
|
||||||
ComputeFunc existsFunc) {
|
ComputeFunc existsFunc) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
HashNode **n,*nv;
|
||||||
IntHashNode **n,*nv;
|
HashNode *t;
|
||||||
IntHashNode *t;
|
|
||||||
int i;
|
int i;
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
|
|
||||||
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
||||||
nv=*n;
|
nv=*n;
|
||||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
i=h->cmpFunc(h,nv->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
void *old=nv->value;
|
HashVal_t old=nv->value;
|
||||||
if (existsFunc) {
|
if (existsFunc) {
|
||||||
existsFunc(H,nv->key,&(nv->value));
|
existsFunc(h,nv->key,&(nv->value));
|
||||||
if (nv->value!=old) {
|
if (nv->value!=old) {
|
||||||
if (h->valDestroyFunc) {
|
if (h->valDestroyFunc) {
|
||||||
h->valDestroyFunc((HashTable)h,old);
|
h->valDestroyFunc(h,old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,13 +278,13 @@ int hashtable_insert_or_update_computed(HashTable H,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t=malloc(sizeof(IntHashNode));
|
t=malloc(sizeof(HashNode));
|
||||||
if (!t) return 0;
|
if (!t) return 0;
|
||||||
t->key=key;
|
t->key=key;
|
||||||
t->next=*n;
|
t->next=*n;
|
||||||
*n=t;
|
*n=t;
|
||||||
if (newFunc) {
|
if (newFunc) {
|
||||||
newFunc(H,t->key,&(t->value));
|
newFunc(h,t->key,&(t->value));
|
||||||
} else {
|
} else {
|
||||||
free(t);
|
free(t);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -298,52 +294,47 @@ int hashtable_insert_or_update_computed(HashTable H,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_update(HashTable H,void *key,void *val) {
|
int hashtable_update(HashTable *h,HashKey_t key,HashVal_t val) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return _hashtable_insert(h,key,val,1,0);
|
return _hashtable_insert(h,key,val,1,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_insert(HashTable H,void *key,void *val) {
|
int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return _hashtable_insert(h,key,val,1,0);
|
return _hashtable_insert(h,key,val,1,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_foreach_update(HashTable H,IteratorUpdateFunc i,void *u) {
|
void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
HashNode *n;
|
||||||
IntHashNode *n;
|
uint32_t x;
|
||||||
unsigned long x;
|
|
||||||
|
|
||||||
if (h->table) {
|
if (h->table) {
|
||||||
for (x=0;x<h->length;x++) {
|
for (x=0;x<h->length;x++) {
|
||||||
for (n=h->table[x];n;n=n->next) {
|
for (n=h->table[x];n;n=n->next) {
|
||||||
i((HashTable)h,n->key,(void **)&(n->value),u);
|
i(h,n->key,&(n->value),u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_foreach(HashTable H,IteratorFunc i,void *u) {
|
void hashtable_foreach(HashTable *h,IteratorFunc i,void *u) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
HashNode *n;
|
||||||
IntHashNode *n;
|
uint32_t x;
|
||||||
unsigned long x;
|
|
||||||
|
|
||||||
if (h->table) {
|
if (h->table) {
|
||||||
for (x=0;x<h->length;x++) {
|
for (x=0;x<h->length;x++) {
|
||||||
for (n=h->table[x];n;n=n->next) {
|
for (n=h->table[x];n;n=n->next) {
|
||||||
i((HashTable)h,n->key,n->value,u);
|
i(h,n->key,n->value,u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_free(HashTable H) {
|
void hashtable_free(HashTable *h) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
HashNode *n,*nn;
|
||||||
IntHashNode *n,*nn;
|
uint32_t i;
|
||||||
unsigned long i;
|
|
||||||
|
|
||||||
if (h->table) {
|
if (h->table) {
|
||||||
if (h->keyDestroyFunc || h->keyDestroyFunc) {
|
if (h->keyDestroyFunc || h->keyDestroyFunc) {
|
||||||
hashtable_foreach(H,_hashtable_destroy,NULL);
|
hashtable_foreach(h,_hashtable_destroy,NULL);
|
||||||
}
|
}
|
||||||
for (i=0;i<h->length;i++) {
|
for (i=0;i<h->length;i++) {
|
||||||
for (n=h->table[i];n;n=nn) {
|
for (n=h->table[i];n;n=nn) {
|
||||||
|
@ -356,31 +347,29 @@ void hashtable_free(HashTable H) {
|
||||||
free(h);
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
DestroyFunc hashtable_set_value_destroy_func(HashTable H,DestroyFunc d) {
|
ValDestroyFunc hashtable_set_value_destroy_func(HashTable *h,ValDestroyFunc d) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
ValDestroyFunc r=h->valDestroyFunc;
|
||||||
DestroyFunc r=h->valDestroyFunc;
|
|
||||||
h->valDestroyFunc=d;
|
h->valDestroyFunc=d;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
DestroyFunc hashtable_set_key_destroy_func(HashTable H,DestroyFunc d) {
|
KeyDestroyFunc hashtable_set_key_destroy_func(HashTable *h,KeyDestroyFunc d) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
KeyDestroyFunc r=h->keyDestroyFunc;
|
||||||
DestroyFunc r=h->keyDestroyFunc;
|
|
||||||
h->keyDestroyFunc=d;
|
h->keyDestroyFunc=d;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _hashtable_remove(IntHashTable *h,
|
static int _hashtable_remove(HashTable *h,
|
||||||
const void *key,
|
const HashKey_t key,
|
||||||
void **keyRet,
|
HashKey_t *keyRet,
|
||||||
void **valRet,
|
HashVal_t *valRet,
|
||||||
int resize) {
|
int resize) {
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
IntHashNode *n,*p;
|
HashNode *n,*p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (p=NULL,n=h->table[hash];n;p=n,n=n->next) {
|
for (p=NULL,n=h->table[hash];n;p=n,n=n->next) {
|
||||||
i=h->cmpFunc((HashTable)h,n->key,key);
|
i=h->cmpFunc(h,n->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
if (p) p=n->next; else h->table[hash]=n->next;
|
if (p) p=n->next; else h->table[hash]=n->next;
|
||||||
*keyRet=n->key;
|
*keyRet=n->key;
|
||||||
|
@ -395,17 +384,17 @@ static int _hashtable_remove(IntHashTable *h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _hashtable_delete(IntHashTable *h,const void *key,int resize) {
|
static int _hashtable_delete(HashTable *h,const HashKey_t key,int resize) {
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
IntHashNode *n,*p;
|
HashNode *n,*p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (p=NULL,n=h->table[hash];n;p=n,n=n->next) {
|
for (p=NULL,n=h->table[hash];n;p=n,n=n->next) {
|
||||||
i=h->cmpFunc((HashTable)h,n->key,key);
|
i=h->cmpFunc(h,n->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
if (p) p=n->next; else h->table[hash]=n->next;
|
if (p) p=n->next; else h->table[hash]=n->next;
|
||||||
if (h->valDestroyFunc) { h->valDestroyFunc((HashTable)h,n->value); }
|
if (h->valDestroyFunc) { h->valDestroyFunc(h,n->value); }
|
||||||
if (h->keyDestroyFunc) { h->keyDestroyFunc((HashTable)h,n->key); }
|
if (h->keyDestroyFunc) { h->keyDestroyFunc(h,n->key); }
|
||||||
free(n);
|
free(n);
|
||||||
h->count++;
|
h->count++;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -416,39 +405,33 @@ static int _hashtable_delete(IntHashTable *h,const void *key,int resize) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_remove(HashTable H,const void *key,void **keyRet,void **valRet) {
|
int hashtable_remove(HashTable *h,const HashKey_t key,HashKey_t *keyRet,HashVal_t *valRet) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return _hashtable_remove(h,key,keyRet,valRet,1);
|
return _hashtable_remove(h,key,keyRet,valRet,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_delete(HashTable H,const void *key) {
|
int hashtable_delete(HashTable *h,const HashKey_t key) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return _hashtable_delete(h,key,1);
|
return _hashtable_delete(h,key,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_rehash_compute(HashTable H,CollisionFunc cf) {
|
void hashtable_rehash_compute(HashTable *h,CollisionFunc cf) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
_hashtable_rehash(h,cf,h->length);
|
_hashtable_rehash(h,cf,h->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hashtable_rehash(HashTable H) {
|
void hashtable_rehash(HashTable *h) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
_hashtable_rehash(h,NULL,h->length);
|
_hashtable_rehash(h,NULL,h->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_lookup_or_insert(HashTable H,void *key,void **valp,void *val) {
|
int hashtable_lookup_or_insert(HashTable *h,HashKey_t key,HashVal_t *valp,HashVal_t val) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return _hashtable_lookup_or_insert(h,key,valp,val,1);
|
return _hashtable_lookup_or_insert(h,key,valp,val,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashtable_lookup(const HashTable H,const void *key,void **valp) {
|
int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
HashNode *n;
|
||||||
IntHashNode *n;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (n=h->table[hash];n;n=n->next) {
|
for (n=h->table[hash];n;n=n->next) {
|
||||||
i=h->cmpFunc((HashTable)h,n->key,key);
|
i=h->cmpFunc(h,n->key,key);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
*valp=n->value;
|
*valp=n->value;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -459,18 +442,15 @@ int hashtable_lookup(const HashTable H,const void *key,void **valp) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long hashtable_get_count(const HashTable H) {
|
uint32_t hashtable_get_count(const HashTable *h) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return h->count;
|
return h->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_get_user_data(const HashTable H) {
|
void *hashtable_get_user_data(const HashTable *h) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
return h->userData;
|
return h->userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashtable_set_user_data(HashTable H,void *data) {
|
void *hashtable_set_user_data(HashTable *h,void *data) {
|
||||||
IntHashTable *h=(IntHashTable *)H;
|
|
||||||
void *r=h->userData;
|
void *r=h->userData;
|
||||||
h->userData=data;
|
h->userData=data;
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -9,28 +9,41 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __HASH_H__
|
#ifndef __QUANTHASH_H__
|
||||||
#define __HASH_H__
|
#define __QUANTHASH_H__
|
||||||
|
|
||||||
#include "QuantTypes.h"
|
#include "QuantTypes.h"
|
||||||
|
|
||||||
HashTable hashtable_new(HashFunc,HashCmpFunc);
|
typedef struct _HashTable HashTable;
|
||||||
void hashtable_free(HashTable);
|
typedef Pixel HashKey_t;
|
||||||
void hashtable_foreach(HashTable,IteratorFunc,void *);
|
typedef uint32_t HashVal_t;
|
||||||
void hashtable_foreach_update(HashTable,IteratorUpdateFunc,void *);
|
|
||||||
int hashtable_insert(HashTable,void *,void *);
|
|
||||||
int hashtable_update(HashTable,void *,void *);
|
|
||||||
int hashtable_lookup(const HashTable,const void *,void **);
|
|
||||||
int hashtable_lookup_or_insert(HashTable,void *,void **,void *);
|
|
||||||
int hashtable_insert_or_update_computed(HashTable,void *,ComputeFunc,ComputeFunc);
|
|
||||||
int hashtable_delete(HashTable,const void *);
|
|
||||||
int hashtable_remove(HashTable,const void *,void **,void **);
|
|
||||||
void *hashtable_set_user_data(HashTable,void *);
|
|
||||||
void *hashtable_get_user_data(const HashTable);
|
|
||||||
DestroyFunc hashtable_set_key_destroy_func(HashTable,DestroyFunc);
|
|
||||||
DestroyFunc hashtable_set_value_destroy_func(HashTable,DestroyFunc);
|
|
||||||
unsigned long hashtable_get_count(const HashTable);
|
|
||||||
void hashtable_rehash(HashTable);
|
|
||||||
void hashtable_rehash_compute(HashTable,CollisionFunc);
|
|
||||||
|
|
||||||
#endif
|
typedef uint32_t (*HashFunc)(const HashTable *,const HashKey_t);
|
||||||
|
typedef int (*HashCmpFunc)(const HashTable *,const HashKey_t,const HashKey_t);
|
||||||
|
typedef void (*IteratorFunc)(const HashTable *,const HashKey_t,const HashVal_t,void *);
|
||||||
|
typedef void (*IteratorUpdateFunc)(const HashTable *,const HashKey_t,HashVal_t *,void *);
|
||||||
|
typedef void (*KeyDestroyFunc)(const HashTable *,HashKey_t);
|
||||||
|
typedef void (*ValDestroyFunc)(const HashTable *,HashVal_t);
|
||||||
|
typedef void (*ComputeFunc)(const HashTable *,const HashKey_t,HashVal_t *);
|
||||||
|
typedef void (*CollisionFunc)(const HashTable *,HashKey_t *,HashVal_t *,HashKey_t,HashVal_t);
|
||||||
|
|
||||||
|
HashTable * hashtable_new(HashFunc hf,HashCmpFunc cf);
|
||||||
|
void hashtable_free(HashTable *h);
|
||||||
|
void hashtable_foreach(HashTable *h,IteratorFunc i,void *u);
|
||||||
|
void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u);
|
||||||
|
int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val);
|
||||||
|
int hashtable_update(HashTable *h,HashKey_t key,HashVal_t val);
|
||||||
|
int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp);
|
||||||
|
int hashtable_lookup_or_insert(HashTable *h,HashKey_t key,HashVal_t *valp,HashVal_t val);
|
||||||
|
int hashtable_insert_or_update_computed(HashTable *h,HashKey_t key,ComputeFunc newFunc,ComputeFunc existsFunc);
|
||||||
|
int hashtable_delete(HashTable *h,const HashKey_t key);
|
||||||
|
int hashtable_remove(HashTable *h,const HashKey_t key,HashKey_t *keyRet,HashVal_t *valRet);
|
||||||
|
void *hashtable_set_user_data(HashTable *h,void *data);
|
||||||
|
void *hashtable_get_user_data(const HashTable *h);
|
||||||
|
KeyDestroyFunc hashtable_set_key_destroy_func(HashTable *,KeyDestroyFunc d);
|
||||||
|
ValDestroyFunc hashtable_set_value_destroy_func(HashTable *,ValDestroyFunc d);
|
||||||
|
uint32_t hashtable_get_count(const HashTable *h);
|
||||||
|
void hashtable_rehash(HashTable *h);
|
||||||
|
void hashtable_rehash_compute(HashTable *h,CollisionFunc cf);
|
||||||
|
|
||||||
|
#endif // __QUANTHASH_H__
|
||||||
|
|
|
@ -21,31 +21,29 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "QuantHash.h"
|
#include "QuantHeap.h"
|
||||||
#include "QuantDefines.h"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct _Heap {
|
||||||
void **heap;
|
void **heap;
|
||||||
int heapsize;
|
int heapsize;
|
||||||
int heapcount;
|
int heapcount;
|
||||||
HeapCmpFunc cf;
|
HeapCmpFunc cf;
|
||||||
} IntHeap;
|
} Heap;
|
||||||
|
|
||||||
#define INITIAL_SIZE 256
|
#define INITIAL_SIZE 256
|
||||||
|
|
||||||
#define DEBUG
|
// #define DEBUG
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static int _heap_test(Heap);
|
static int _heap_test(Heap *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ImagingQuantHeapFree(Heap H) {
|
void ImagingQuantHeapFree(Heap *h) {
|
||||||
IntHeap *h=(IntHeap *)H;
|
|
||||||
free(h->heap);
|
free(h->heap);
|
||||||
free(h);
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _heap_grow(IntHeap *h,int newsize) {
|
static int _heap_grow(Heap *h,int newsize) {
|
||||||
void *newheap;
|
void *newheap;
|
||||||
if (!newsize) newsize=h->heapsize<<1;
|
if (!newsize) newsize=h->heapsize<<1;
|
||||||
if (newsize<h->heapsize) return 0;
|
if (newsize<h->heapsize) return 0;
|
||||||
|
@ -59,15 +57,14 @@ static int _heap_grow(IntHeap *h,int newsize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static int _heap_test(Heap H) {
|
static int _heap_test(Heap *h) {
|
||||||
IntHeap *h=(IntHeap *)H;
|
|
||||||
int k;
|
int k;
|
||||||
for (k=1;k*2<=h->heapcount;k++) {
|
for (k=1;k*2<=h->heapcount;k++) {
|
||||||
if (h->cf(H,h->heap[k],h->heap[k*2])<0) {
|
if (h->cf(h,h->heap[k],h->heap[k*2])<0) {
|
||||||
printf ("heap is bad\n");
|
printf ("heap is bad\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (k*2+1<=h->heapcount && h->cf(H,h->heap[k],h->heap[k*2+1])<0) {
|
if (k*2+1<=h->heapcount && h->cf(h,h->heap[k],h->heap[k*2+1])<0) {
|
||||||
printf ("heap is bad\n");
|
printf ("heap is bad\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -76,8 +73,7 @@ static int _heap_test(Heap H) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ImagingQuantHeapRemove(Heap H,void **r) {
|
int ImagingQuantHeapRemove(Heap* h,void **r) {
|
||||||
IntHeap *h=(IntHeap *)H;
|
|
||||||
int k,l;
|
int k,l;
|
||||||
void *v;
|
void *v;
|
||||||
|
|
||||||
|
@ -89,31 +85,30 @@ int ImagingQuantHeapRemove(Heap H,void **r) {
|
||||||
for (k=1;k*2<=h->heapcount;k=l) {
|
for (k=1;k*2<=h->heapcount;k=l) {
|
||||||
l=k*2;
|
l=k*2;
|
||||||
if (l<h->heapcount) {
|
if (l<h->heapcount) {
|
||||||
if (h->cf(H,h->heap[l],h->heap[l+1])<0) {
|
if (h->cf(h,h->heap[l],h->heap[l+1])<0) {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (h->cf(H,v,h->heap[l])>0) {
|
if (h->cf(h,v,h->heap[l])>0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
h->heap[k]=h->heap[l];
|
h->heap[k]=h->heap[l];
|
||||||
}
|
}
|
||||||
h->heap[k]=v;
|
h->heap[k]=v;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!_heap_test(H)) { printf ("oops - heap_remove messed up the heap\n"); exit(1); }
|
if (!_heap_test(h)) { printf ("oops - heap_remove messed up the heap\n"); exit(1); }
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImagingQuantHeapAdd(Heap H,void *val) {
|
int ImagingQuantHeapAdd(Heap *h,void *val) {
|
||||||
IntHeap *h=(IntHeap *)H;
|
|
||||||
int k;
|
int k;
|
||||||
if (h->heapcount==h->heapsize-1) {
|
if (h->heapcount==h->heapsize-1) {
|
||||||
_heap_grow(h,0);
|
_heap_grow(h,0);
|
||||||
}
|
}
|
||||||
k=++h->heapcount;
|
k=++h->heapcount;
|
||||||
while (k!=1) {
|
while (k!=1) {
|
||||||
if (h->cf(H,val,h->heap[k/2])<=0) {
|
if (h->cf(h,val,h->heap[k/2])<=0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
h->heap[k]=h->heap[k/2];
|
h->heap[k]=h->heap[k/2];
|
||||||
|
@ -121,13 +116,12 @@ int ImagingQuantHeapAdd(Heap H,void *val) {
|
||||||
}
|
}
|
||||||
h->heap[k]=val;
|
h->heap[k]=val;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!_heap_test(H)) { printf ("oops - heap_add messed up the heap\n"); exit(1); }
|
if (!_heap_test(h)) { printf ("oops - heap_add messed up the heap\n"); exit(1); }
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImagingQuantHeapTop(Heap H,void **r) {
|
int ImagingQuantHeapTop(Heap *h,void **r) {
|
||||||
IntHeap *h=(IntHeap *)H;
|
|
||||||
if (!h->heapcount) {
|
if (!h->heapcount) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -136,15 +130,14 @@ int ImagingQuantHeapTop(Heap H,void **r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap *ImagingQuantHeapNew(HeapCmpFunc cf) {
|
Heap *ImagingQuantHeapNew(HeapCmpFunc cf) {
|
||||||
IntHeap *h;
|
Heap *h;
|
||||||
|
|
||||||
h=malloc(sizeof(IntHeap));
|
h=malloc(sizeof(Heap));
|
||||||
if (!h) return NULL;
|
if (!h) return NULL;
|
||||||
h->heapsize=INITIAL_SIZE;
|
h->heapsize=INITIAL_SIZE;
|
||||||
h->heap=malloc(sizeof(void *)*h->heapsize);
|
h->heap=malloc(sizeof(void *)*h->heapsize);
|
||||||
if (!h->heap) { free(h); return NULL; }
|
if (!h->heap) { free(h); return NULL; }
|
||||||
h->heapcount=0;
|
h->heapcount=0;
|
||||||
h->cf=cf;
|
h->cf=cf;
|
||||||
return (Heap)h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,19 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __HEAP_H__
|
#ifndef __QUANTHEAP_H__
|
||||||
#define __HEAP_H__
|
#define __QUANTHEAP_H__
|
||||||
|
|
||||||
#include "QuantTypes.h"
|
#include "QuantTypes.h"
|
||||||
|
|
||||||
void ImagingQuantHeapFree(Heap);
|
typedef struct _Heap Heap;
|
||||||
int ImagingQuantHeapRemove(Heap,void **);
|
|
||||||
int ImagingQuantHeapAdd(Heap,void *);
|
typedef int (*HeapCmpFunc)(const Heap *,const void *,const void *);
|
||||||
int ImagingQuantHeapTop(Heap,void **);
|
|
||||||
|
void ImagingQuantHeapFree(Heap *);
|
||||||
|
int ImagingQuantHeapRemove(Heap *,void **);
|
||||||
|
int ImagingQuantHeapAdd(Heap *,void *);
|
||||||
|
int ImagingQuantHeapTop(Heap *,void **);
|
||||||
Heap *ImagingQuantHeapNew(HeapCmpFunc);
|
Heap *ImagingQuantHeapNew(HeapCmpFunc);
|
||||||
|
|
||||||
#endif
|
#endif // __QUANTHEAP_H__
|
||||||
|
|
|
@ -27,15 +27,15 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "Quant.h"
|
#include "QuantOctree.h"
|
||||||
|
|
||||||
typedef struct _ColorBucket{
|
typedef struct _ColorBucket{
|
||||||
/* contains palette index when used for look up cube */
|
/* contains palette index when used for look up cube */
|
||||||
unsigned long count;
|
uint32_t count;
|
||||||
unsigned long r;
|
uint32_t r;
|
||||||
unsigned long g;
|
uint32_t g;
|
||||||
unsigned long b;
|
uint32_t b;
|
||||||
unsigned long a;
|
uint32_t a;
|
||||||
} *ColorBucket;
|
} *ColorBucket;
|
||||||
|
|
||||||
typedef struct _ColorCube{
|
typedef struct _ColorCube{
|
||||||
|
@ -262,7 +262,7 @@ set_lookup_value(const ColorCube cube, const Pixel *p, long value) {
|
||||||
bucket->count = value;
|
bucket->count = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
uint32_t
|
||||||
lookup_color(const ColorCube cube, const Pixel *p) {
|
lookup_color(const ColorCube cube, const Pixel *p) {
|
||||||
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
||||||
return bucket->count;
|
return bucket->count;
|
||||||
|
@ -302,9 +302,9 @@ create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
|
||||||
|
|
||||||
static void
|
static void
|
||||||
map_image_pixels(const Pixel *pixelData,
|
map_image_pixels(const Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
const ColorCube lookupCube,
|
const ColorCube lookupCube,
|
||||||
unsigned long *pixelArray)
|
uint32_t *pixelArray)
|
||||||
{
|
{
|
||||||
long i;
|
long i;
|
||||||
for (i=0; i<nPixels; i++) {
|
for (i=0; i<nPixels; i++) {
|
||||||
|
@ -316,11 +316,11 @@ const int CUBE_LEVELS[8] = {4, 4, 4, 0, 2, 2, 2, 0};
|
||||||
const int CUBE_LEVELS_ALPHA[8] = {3, 4, 3, 3, 2, 2, 2, 2};
|
const int CUBE_LEVELS_ALPHA[8] = {3, 4, 3, 3, 2, 2, 2, 2};
|
||||||
|
|
||||||
int quantize_octree(Pixel *pixelData,
|
int quantize_octree(Pixel *pixelData,
|
||||||
unsigned long nPixels,
|
uint32_t nPixels,
|
||||||
unsigned long nQuantPixels,
|
uint32_t nQuantPixels,
|
||||||
Pixel **palette,
|
Pixel **palette,
|
||||||
unsigned long *paletteLength,
|
uint32_t *paletteLength,
|
||||||
unsigned long **quantizedPixels,
|
uint32_t **quantizedPixels,
|
||||||
int withAlpha)
|
int withAlpha)
|
||||||
{
|
{
|
||||||
ColorCube fineCube = NULL;
|
ColorCube fineCube = NULL;
|
||||||
|
@ -330,7 +330,7 @@ int quantize_octree(Pixel *pixelData,
|
||||||
ColorBucket paletteBucketsCoarse = NULL;
|
ColorBucket paletteBucketsCoarse = NULL;
|
||||||
ColorBucket paletteBucketsFine = NULL;
|
ColorBucket paletteBucketsFine = NULL;
|
||||||
ColorBucket paletteBuckets = NULL;
|
ColorBucket paletteBuckets = NULL;
|
||||||
unsigned long *qp = NULL;
|
uint32_t *qp = NULL;
|
||||||
long i;
|
long i;
|
||||||
long nCoarseColors, nFineColors, nAlreadySubtracted;
|
long nCoarseColors, nFineColors, nAlreadySubtracted;
|
||||||
const int *cubeBits;
|
const int *cubeBits;
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#ifndef __QUANT_OCTREE_H__
|
#ifndef __QUANT_OCTREE_H__
|
||||||
#define __QUANT_OCTREE_H__
|
#define __QUANT_OCTREE_H__
|
||||||
|
|
||||||
|
#include "QuantTypes.h"
|
||||||
|
|
||||||
int quantize_octree(Pixel *,
|
int quantize_octree(Pixel *,
|
||||||
unsigned long,
|
uint32_t,
|
||||||
unsigned long,
|
uint32_t,
|
||||||
Pixel **,
|
Pixel **,
|
||||||
unsigned long *,
|
uint32_t *,
|
||||||
unsigned long **,
|
uint32_t **,
|
||||||
int);
|
int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,17 +12,20 @@
|
||||||
#ifndef __TYPES_H__
|
#ifndef __TYPES_H__
|
||||||
#define __TYPES_H__
|
#define __TYPES_H__
|
||||||
|
|
||||||
typedef void *HashTable;
|
#ifdef _MSC_VER
|
||||||
typedef void *Heap;
|
typedef unsigned __int32 uint32_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef unsigned long (*HashFunc)(const HashTable,const void *);
|
typedef union {
|
||||||
typedef int (*HashCmpFunc)(const HashTable,const void *,const void *);
|
struct {
|
||||||
typedef void (*IteratorFunc)(const HashTable,const void *,const void *,void *);
|
unsigned char r,g,b,a;
|
||||||
typedef void (*IteratorUpdateFunc)(const HashTable,const void *,void **,void *);
|
} c;
|
||||||
typedef void (*DestroyFunc)(const HashTable,void *);
|
struct {
|
||||||
typedef void (*ComputeFunc)(const HashTable,const void *,void **);
|
unsigned char v[4];
|
||||||
typedef void (*CollisionFunc)(const HashTable,void **,void **,void *,void *);
|
} a;
|
||||||
|
uint32_t v;
|
||||||
typedef int (*HeapCmpFunc)(const Heap,const void *,const void *);
|
} Pixel;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user