mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-24 16:24:11 +03:00
Merge branch 'readme' of https://github.com/wiredfool/Pillow into readme
This commit is contained in:
commit
bb5f61fd80
10
PIL/Image.py
10
PIL/Image.py
|
@ -713,6 +713,16 @@ class Image:
|
|||
if dither is None:
|
||||
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:
|
||||
im = self.im.convert(mode, dither)
|
||||
except ValueError:
|
||||
|
|
|
@ -433,8 +433,9 @@ class Parser:
|
|||
# @param im Image object.
|
||||
# @param fp File object.
|
||||
# @param tile Tile list.
|
||||
# @param bufsize Optional buffer size
|
||||
|
||||
def _save(im, fp, tile):
|
||||
def _save(im, fp, tile, bufsize=0):
|
||||
"Helper to save image based on tile list"
|
||||
|
||||
im.load()
|
||||
|
@ -442,7 +443,10 @@ def _save(im, fp, tile):
|
|||
im.encoderconfig = ()
|
||||
tile.sort(key=_tilesort)
|
||||
# FIXME: make MAXBLOCK a configuration parameter
|
||||
bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
|
||||
# It would be great if we could have the encoder specifiy what it needs
|
||||
# But, it would need at least the image size in most cases. RawEncode is
|
||||
# a tricky case.
|
||||
bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c
|
||||
try:
|
||||
fh = fp.fileno()
|
||||
fp.flush()
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
from functools import reduce
|
||||
|
||||
class Filter:
|
||||
class Filter(object):
|
||||
pass
|
||||
|
||||
##
|
||||
|
|
|
@ -36,7 +36,7 @@ __version__ = "0.6"
|
|||
|
||||
import array, struct
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from JpegPresets import presets
|
||||
from PIL.JpegPresets import presets
|
||||
|
||||
i8 = _binary.i8
|
||||
o8 = _binary.o8
|
||||
|
@ -483,7 +483,7 @@ def _save(im, fp, filename):
|
|||
elif subsampling == "keep":
|
||||
if im.format != "JPEG":
|
||||
raise ValueError("Cannot use 'keep' when original image is not a JPEG")
|
||||
subsampling = get_sampling(im)
|
||||
subsampling = get_sampling(im)
|
||||
|
||||
def validate_qtables(qtables):
|
||||
if qtables is None:
|
||||
|
@ -513,7 +513,7 @@ def _save(im, fp, filename):
|
|||
else:
|
||||
qtables[idx] = list(table)
|
||||
return qtables
|
||||
|
||||
|
||||
if qtables == "keep":
|
||||
if im.format != "JPEG":
|
||||
raise ValueError("Cannot use 'keep' when original image is not a JPEG")
|
||||
|
@ -554,7 +554,15 @@ def _save(im, fp, filename):
|
|||
info.get("exif", b"")
|
||||
)
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
|
||||
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
||||
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
||||
# is a value that's been used in a django patch.
|
||||
# https://github.com/jdriscoll/django-imagekit/issues/50
|
||||
bufsize=0
|
||||
if "optimize" in info:
|
||||
bufsize = im.size[0]*im.size[1]
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
|
||||
|
||||
def _save_cjpeg(im, fp, filename):
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||
|
|
|
@ -70,7 +70,7 @@ _MODES = {
|
|||
}
|
||||
|
||||
|
||||
_simple_palette = re.compile(b'^\xff+\x00+$')
|
||||
_simple_palette = re.compile(b'^\xff+\x00\xff*$')
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Support classes. Suitable for PNG and related formats like MNG etc.
|
||||
|
@ -550,11 +550,14 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
|
|||
|
||||
if "transparency" in im.encoderinfo:
|
||||
if im.mode == "P":
|
||||
transparency = max(0, min(255, im.encoderinfo["transparency"]))
|
||||
alpha = b'\xFF' * transparency + b'\0'
|
||||
# limit to actual palette size
|
||||
alpha_bytes = 2**bits
|
||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||
if isinstance(im.encoderinfo["transparency"], bytes):
|
||||
chunk(fp, b"tRNS", im.encoderinfo["transparency"][:alpha_bytes])
|
||||
else:
|
||||
transparency = max(0, min(255, im.encoderinfo["transparency"]))
|
||||
alpha = b'\xFF' * transparency + b'\0'
|
||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||
elif im.mode == "L":
|
||||
transparency = max(0, min(65535, im.encoderinfo["transparency"]))
|
||||
chunk(fp, b"tRNS", o16(transparency))
|
||||
|
|
56
README.rst
56
README.rst
|
@ -4,6 +4,7 @@ Pillow
|
|||
.. Note:: Pillow >= 2.0.0 supports Python versions: 2.6, 2.7, 3.2, 3.3; Pillow < 2.0.0 supports Python versions: 2.4, 2.5, 2.6, 2.7.
|
||||
|
||||
.. image:: https://travis-ci.org/python-imaging/Pillow.png
|
||||
:target: https://travis-ci.org/python-imaging/Pillow
|
||||
|
||||
Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||
|
||||
|
@ -22,6 +23,26 @@ Why a fork?
|
|||
|
||||
PIL is not setuptools compatible. Please see http://mail.python.org/pipermail/image-sig/2010-August/006480.html for a more detailed explanation. Also, PIL's current bi-yearly (or greater) release schedule is too infrequent to accomodate the large number and frequency of issues reported.
|
||||
|
||||
Porting
|
||||
-------
|
||||
|
||||
Pillow is a functional dropin for the Python Imaging Library. To run
|
||||
under Pillow, existing code needs to be modified to import the Imaging
|
||||
modules from the PIL namespace instead of the global namespace.
|
||||
|
||||
Change::
|
||||
|
||||
import Image
|
||||
|
||||
to::
|
||||
|
||||
from PIL import Image
|
||||
|
||||
Note that if your code imports _imaging, that will also be hosted in the PIL namespace. The preferred method of importing _imaging is::
|
||||
|
||||
from PIL import Image
|
||||
_imaging = Image.core
|
||||
|
||||
What about image code bugs?
|
||||
---------------------------
|
||||
|
||||
|
@ -80,18 +101,18 @@ Current platform support for Pillow. Binary distributions are contributed for ea
|
|||
.. [2] In some cases, x86 support may indicate 32-bit compilation on 64-bit architecture (vs. compilation on 32-bit hardware).
|
||||
|
||||
Installation
|
||||
============
|
||||
------------
|
||||
|
||||
If there is a binary package for your system, that is the preferred way of obtaining Pillow.
|
||||
|
||||
Building from Source
|
||||
--------------------
|
||||
+++++++++
|
||||
|
||||
Some of Pillow's features require external libraries.
|
||||
|
||||
* libjpeg provides JPEG functionality.
|
||||
|
||||
* Pillow has been tested with libjpev versions 6b and 8
|
||||
* Pillow has been tested with libjpev versions 6b, 8, and 9
|
||||
|
||||
* zlib provides access to compressed PNGs
|
||||
|
||||
|
@ -105,7 +126,7 @@ Some of Pillow's features require external libraries.
|
|||
|
||||
* libwebp provides the Webp format.
|
||||
|
||||
If the prerequisites are installed in the standard library locations for your machine, no configuration shoule be required. If they are installed in a non-standard location, you may need to configure setuptools to use those locations. See [[url here]] for more information.
|
||||
If the prerequisites are installed in the standard library locations for your machine, no configuration shoule be required. If they are installed in a non-standard location, you may need to configure setuptools to use those locations.
|
||||
|
||||
Once you have assembed the prerequisites, run:
|
||||
|
||||
|
@ -114,7 +135,7 @@ Once you have assembed the prerequisites, run:
|
|||
$ pip install pillow
|
||||
|
||||
Platform Specific Instructions
|
||||
------------------------------
|
||||
+++++++++
|
||||
|
||||
Mac OSX
|
||||
*******
|
||||
|
@ -137,23 +158,23 @@ The library prerequisites are installed with::
|
|||
# Ubuntu 12.04 LTS
|
||||
sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms1-dev libwebp-dev
|
||||
|
||||
##Undone## Debian library versions.
|
||||
Windows
|
||||
*******
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
You can help fund Pillow development!
|
||||
|
||||
Porting
|
||||
=======
|
||||
.. Note:: New contributors: please add your name (and donation preference) here and send a pull request.
|
||||
|
||||
Pillow is a functional dropin for the Python Imaging Library. To run under Pillow, existing code needs to be modified to import the Imaging modules from the PIL namespace instead of the global namespace.
|
||||
|
||||
Change::
|
||||
|
||||
import Image
|
||||
|
||||
to::
|
||||
|
||||
from PIL import Image
|
||||
Pillow is a volunteer effort led by Alex Clark. Any contributor interested in receiving donations may add their name (and donation preference) here.
|
||||
|
||||
+--------------------------------------+---------------------------------------+
|
||||
| **Developer** | **Preference** |
|
||||
+--------------------------------------+---------------------------------------+
|
||||
| Alex Clark (fork author) | http://gittip.com/aclark4life |
|
||||
+--------------------------------------+---------------------------------------+
|
||||
|
||||
|
||||
|
||||
|
@ -463,4 +484,3 @@ Python Imaging Library
|
|||
http://mingw.org (compiler)
|
||||
http://sebsauvage.net/python/mingw.html (build instructions)
|
||||
http://sourceforge.net/projects/gnuwin32 (prebuilt libraries)
|
||||
|
||||
|
|
|
@ -1202,7 +1202,7 @@ PySane_get_devices(PyObject *self, PyObject *args)
|
|||
const SANE_Device *dev;
|
||||
SANE_Status st;
|
||||
PyObject *list;
|
||||
int local_only, i;
|
||||
int local_only = 0, i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|i", &local_only))
|
||||
{
|
||||
|
|
BIN
Tests/images/l_trns.png
Normal file
BIN
Tests/images/l_trns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
Tests/images/p_trns_single.png
Normal file
BIN
Tests/images/p_trns_single.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -113,6 +113,13 @@ def test_optimize():
|
|||
assert_image_equal(im1, im2)
|
||||
assert_true(im1.bytes >= im2.bytes)
|
||||
|
||||
def test_optimize_large_buffer():
|
||||
#https://github.com/python-imaging/Pillow/issues/148
|
||||
f = tempfile('temp.jpg')
|
||||
# this requires ~ 1.5x Image.MAXBLOCK
|
||||
im = Image.new("RGB", (4096,4096), 0xff3333)
|
||||
im.save(f, format="JPEG", optimize=True)
|
||||
|
||||
def test_progressive():
|
||||
im1 = roundtrip(lena())
|
||||
im2 = roundtrip(lena(), progressive=1)
|
||||
|
|
|
@ -128,6 +128,34 @@ def test_load_transparent_p():
|
|||
# image has 124 uniqe qlpha values
|
||||
assert_equal(len(im.split()[3].getcolors()), 124)
|
||||
|
||||
def test_save_p_transparent_palette():
|
||||
in_file = "Tests/images/pil123p.png"
|
||||
im = Image.open(in_file)
|
||||
|
||||
file = tempfile("temp.png")
|
||||
assert_no_exception(lambda: im.save(file))
|
||||
|
||||
def test_save_p_single_transparency():
|
||||
in_file = "Tests/images/p_trns_single.png"
|
||||
im = Image.open(in_file)
|
||||
|
||||
file = tempfile("temp.png")
|
||||
assert_no_exception(lambda: im.save(file))
|
||||
|
||||
def test_save_l_transparency():
|
||||
in_file = "Tests/images/l_trns.png"
|
||||
im = Image.open(in_file)
|
||||
|
||||
file = tempfile("temp.png")
|
||||
assert_no_exception(lambda: im.save(file))
|
||||
|
||||
def test_save_rgb_single_transparency():
|
||||
in_file = "Tests/images/caption_6_33_22.png"
|
||||
im = Image.open(in_file)
|
||||
|
||||
file = tempfile("temp.png")
|
||||
assert_no_exception(lambda: im.save(file))
|
||||
|
||||
def test_load_verify():
|
||||
# Check open/load/verify exception (@PIL150)
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ def test_g4_write():
|
|||
file = "Tests/images/lena_g4_500.tif"
|
||||
orig = Image.open(file)
|
||||
|
||||
out = "temp.tif"
|
||||
out = tempfile("temp.tif")
|
||||
rot = orig.transpose(Image.ROTATE_90)
|
||||
assert_equal(rot.size,(500,500))
|
||||
rot.save(out)
|
||||
|
|
|
@ -2,6 +2,11 @@ from tester import *
|
|||
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
import _webp
|
||||
except:
|
||||
skip('webp support not installed')
|
||||
|
||||
def test_read():
|
||||
""" Can we write a webp without error. Does it have the bits we expect?"""
|
||||
|
||||
|
@ -37,7 +42,18 @@ def test_write():
|
|||
assert_no_exception(lambda: im.load())
|
||||
assert_no_exception(lambda: im.getdata())
|
||||
|
||||
# If we're using the exact same version of webp, this test should pass.
|
||||
# but it doesn't if the webp is generated on Ubuntu and tested on Fedora.
|
||||
|
||||
# generated with: dwebp -ppm temp.webp -o lena_webp_write.ppm
|
||||
target = Image.open('Tests/images/lena_webp_write.ppm')
|
||||
assert_image_equal(im, target)
|
||||
#target = Image.open('Tests/images/lena_webp_write.ppm')
|
||||
#assert_image_equal(im, target)
|
||||
|
||||
# This test asserts that the images are similar. If the average pixel difference
|
||||
# between the two images is less than the epsilon value, then we're going to
|
||||
# accept that it's a reasonable lossy version of the image. The included lena images
|
||||
# for webp are showing ~16 on Ubuntu, the jpegs are showing ~18.
|
||||
target = lena('RGB')
|
||||
assert_image_similar(im, target, 20.0)
|
||||
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ def test_toarray():
|
|||
return ai["shape"], ai["typestr"], len(ai["data"])
|
||||
# assert_equal(test("1"), ((100, 128), '|b1', 1600))
|
||||
assert_equal(test("L"), ((100, 128), '|u1', 12800))
|
||||
assert_equal(test("I"), ((100, 128), '<i4', 51200)) # FIXME: wrong?
|
||||
assert_equal(test("F"), ((100, 128), '<f4', 51200)) # FIXME: wrong?
|
||||
assert_equal(test("I"), ((100, 128), Image._ENDIAN + 'i4', 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("RGBA"), ((100, 128, 4), '|u1', 51200))
|
||||
assert_equal(test("RGBX"), ((100, 128, 4), '|u1', 51200))
|
||||
|
|
|
@ -18,6 +18,8 @@ def test_pack():
|
|||
else:
|
||||
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;I"), [0])
|
||||
assert_equal(pack("1", "1;R"), [1])
|
||||
|
@ -25,9 +27,9 @@ def test_pack():
|
|||
|
||||
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])
|
||||
|
||||
|
|
|
@ -84,10 +84,12 @@ def test_tobytes():
|
|||
def tobytes(mode):
|
||||
return Image.new(mode, (1, 1), 1).tobytes()
|
||||
|
||||
order = 1 if Image._ENDIAN == '<' else -1
|
||||
|
||||
assert_equal(tobytes("L"), b"\x01")
|
||||
assert_equal(tobytes("I;16"), b"\x01\x00")
|
||||
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():
|
||||
|
|
|
@ -150,6 +150,26 @@ def assert_image_equal(a, b, msg=None):
|
|||
else:
|
||||
success()
|
||||
|
||||
def assert_image_similar(a, b, epsilon, msg=None):
|
||||
epsilon = float(epsilon)
|
||||
if a.mode != b.mode:
|
||||
return failure(msg or "got mode %r, expected %r" % (a.mode, b.mode))
|
||||
elif a.size != b.size:
|
||||
return failure(msg or "got size %r, expected %r" % (a.size, b.size))
|
||||
diff = 0
|
||||
try:
|
||||
ord(b'0')
|
||||
for abyte,bbyte in zip(a.tobytes(),b.tobytes()):
|
||||
diff += abs(ord(abyte)-ord(bbyte))
|
||||
except:
|
||||
for abyte,bbyte in zip(a.tobytes(),b.tobytes()):
|
||||
diff += abs(abyte-bbyte)
|
||||
ave_diff = float(diff)/(a.size[0]*a.size[1])
|
||||
if epsilon < ave_diff:
|
||||
failure(msg or "average pixel value difference %.4f > epsilon %.4f" %(ave_diff, epsilon))
|
||||
else:
|
||||
success()
|
||||
|
||||
def tempfile(template, *extra):
|
||||
import os, sys
|
||||
files = []
|
||||
|
|
449
_imaging.c
449
_imaging.c
File diff suppressed because it is too large
Load Diff
|
@ -282,7 +282,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
{
|
||||
int i, x, y;
|
||||
Imaging im;
|
||||
int index, error, ascender;
|
||||
int index, error, ascender, descender;
|
||||
int load_flags;
|
||||
unsigned char *source;
|
||||
FT_ULong ch;
|
||||
|
@ -332,6 +332,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
int xx, x0, x1;
|
||||
source = (unsigned char*) glyph->bitmap.buffer;
|
||||
ascender = PIXEL(self->face->size->metrics.ascender);
|
||||
descender = PIXEL(self->face->size->metrics.descender);
|
||||
xx = x + glyph->bitmap_left;
|
||||
x0 = 0;
|
||||
x1 = glyph->bitmap.width;
|
||||
|
@ -340,7 +341,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
if (xx + x1 > im->xsize)
|
||||
x1 = im->xsize - xx;
|
||||
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) {
|
||||
/* blend this glyph into the buffer */
|
||||
unsigned char *target = im->image8[yy] + xx;
|
||||
|
@ -361,6 +362,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
int xx, x0, x1;
|
||||
source = (unsigned char*) glyph->bitmap.buffer;
|
||||
ascender = PIXEL(self->face->size->metrics.ascender);
|
||||
descender = PIXEL(self->face->size->metrics.descender);
|
||||
xx = x + glyph->bitmap_left;
|
||||
x0 = 0;
|
||||
x1 = glyph->bitmap.width;
|
||||
|
@ -369,7 +371,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
if (xx + x1 > im->xsize)
|
||||
x1 = im->xsize - xx;
|
||||
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) {
|
||||
/* blend this glyph into the buffer */
|
||||
int i;
|
||||
|
|
|
@ -12,81 +12,85 @@
|
|||
#include "Imaging.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 r;
|
||||
UINT8 g;
|
||||
UINT8 b;
|
||||
UINT8 a;
|
||||
} rgba8;
|
||||
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
|
||||
{
|
||||
Imaging imOut;
|
||||
int x, y;
|
||||
float dstR, dstG, dstB, dstA;
|
||||
float srcR, srcG, srcB, srcA;
|
||||
float outR, outG, outB, outA;
|
||||
|
||||
/* Check arguments */
|
||||
if (!imDst || !imSrc ||
|
||||
strcmp(imDst->mode, "RGBA") ||
|
||||
imDst->type != IMAGING_TYPE_UINT8 ||
|
||||
imDst->bands != 4)
|
||||
return ImagingError_ModeError();
|
||||
strcmp(imDst->mode, "RGBA") ||
|
||||
imDst->type != IMAGING_TYPE_UINT8 ||
|
||||
imDst->bands != 4)
|
||||
return ImagingError_ModeError();
|
||||
|
||||
if (strcmp(imDst->mode, imSrc->mode) ||
|
||||
imDst->type != imSrc->type ||
|
||||
imDst->bands != imSrc->bands ||
|
||||
imDst->xsize != imSrc->xsize ||
|
||||
imDst->ysize != imSrc->ysize)
|
||||
return ImagingError_Mismatch();
|
||||
imDst->type != imSrc->type ||
|
||||
imDst->bands != imSrc->bands ||
|
||||
imDst->xsize != imSrc->xsize ||
|
||||
imDst->ysize != imSrc->ysize)
|
||||
return ImagingError_Mismatch();
|
||||
|
||||
imOut = ImagingNew(imDst->mode, imDst->xsize, imDst->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
ImagingCopyInfo(imOut, imDst);
|
||||
|
||||
for (y = 0; y < imDst->ysize; y++) {
|
||||
|
||||
UINT8* dst = (UINT8*) imDst->image[y];
|
||||
UINT8* src = (UINT8*) imSrc->image[y];
|
||||
UINT8* out = (UINT8*) imOut->image[y];
|
||||
rgba8* dst = (rgba8*) imDst->image[y];
|
||||
rgba8* src = (rgba8*) imSrc->image[y];
|
||||
rgba8* out = (rgba8*) imOut->image[y];
|
||||
|
||||
for (x = 0; x < imDst->linesize; x += 4) {
|
||||
for (x = 0; x < imDst->xsize; x ++) {
|
||||
|
||||
dstR = dst[x + 0] / 255.0;
|
||||
dstG = dst[x + 1] / 255.0;
|
||||
dstB = dst[x + 2] / 255.0;
|
||||
dstA = dst[x + 3] / 255.0;
|
||||
if (src->a == 0) {
|
||||
// Copy 4 bytes at once.
|
||||
*out = *dst;
|
||||
} else {
|
||||
// Integer implementation with increased precision.
|
||||
// Each variable has extra meaningful bits.
|
||||
// Divisions are rounded.
|
||||
|
||||
srcR = src[x + 0] / 255.0;
|
||||
srcG = src[x + 1] / 255.0;
|
||||
srcB = src[x + 2] / 255.0;
|
||||
srcA = src[x + 3] / 255.0;
|
||||
// This code uses trick from Paste.c:
|
||||
// (a + (2 << (n-1)) - 1) / ((2 << n)-1)
|
||||
// almost equivalent to:
|
||||
// tmp = a + (2 << (n-1)), ((tmp >> n) + tmp) >> n
|
||||
|
||||
if (dstA == 1.0) {
|
||||
outR = srcR * srcA + dstR * (1.0 - srcA);
|
||||
outG = srcG * srcA + dstG * (1.0 - srcA);
|
||||
outB = srcB * srcA + dstB * (1.0 - srcA);
|
||||
outA = 1.0;
|
||||
} else if (srcA == 0.0) {
|
||||
outR = dstR;
|
||||
outG = dstG;
|
||||
outB = dstB;
|
||||
outA = dstA;
|
||||
} else {
|
||||
outA = srcA + dstA * (1.0 - srcA);
|
||||
if (outA == 0.0) {
|
||||
outR = 0.0;
|
||||
outG = 0.0;
|
||||
outB = 0.0;
|
||||
} else {
|
||||
outR = (srcR * srcA + dstR * dstA * (1.0 - srcA)) / outA;
|
||||
outG = (srcG * srcA + dstG * dstA * (1.0 - srcA)) / outA;
|
||||
outB = (srcB * srcA + dstB * dstA * (1.0 - srcA)) / outA;
|
||||
}
|
||||
}
|
||||
UINT32 tmpr, tmpg, tmpb;
|
||||
UINT16 blend = dst->a * (255 - src->a);
|
||||
UINT16 outa255 = src->a * 255 + blend;
|
||||
// There we use 7 bits for precision.
|
||||
// We could use more, but we go beyond 32 bits.
|
||||
UINT16 coef1 = src->a * 255 * 255 * 128 / outa255;
|
||||
UINT16 coef2 = 255 * 128 - coef1;
|
||||
|
||||
out[x + 0] = (UINT8) (255.0 * outR + 0.5);
|
||||
out[x + 1] = (UINT8) (255.0 * outG + 0.5);
|
||||
out[x + 2] = (UINT8) (255.0 * outB + 0.5);
|
||||
out[x + 3] = (UINT8) (255.0 * outA + 0.5);
|
||||
#define SHIFTFORDIV255(a)\
|
||||
((((a) >> 8) + a) >> 8)
|
||||
|
||||
}
|
||||
tmpr = src->r * coef1 + dst->r * coef2 + (0x80 << 7);
|
||||
out->r = SHIFTFORDIV255(tmpr) >> 7;
|
||||
tmpg = src->g * coef1 + dst->g * coef2 + (0x80 << 7);
|
||||
out->g = SHIFTFORDIV255(tmpg) >> 7;
|
||||
tmpb = src->b * coef1 + dst->b * coef2 + (0x80 << 7);
|
||||
out->b = SHIFTFORDIV255(tmpb) >> 7;
|
||||
out->a = SHIFTFORDIV255(outa255 + 0x80);
|
||||
}
|
||||
|
||||
dst++; src++; out++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,17 +25,15 @@
|
|||
#include <memory.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "Quant.h"
|
||||
#include "QuantTypes.h"
|
||||
#include "QuantOctree.h"
|
||||
|
||||
#include "QuantDefines.h"
|
||||
#include "QuantHash.h"
|
||||
#include "QuantHeap.h"
|
||||
|
||||
#define NO_OUTPUT
|
||||
|
||||
typedef struct {
|
||||
unsigned long scale;
|
||||
uint32_t scale;
|
||||
} PixelHashData;
|
||||
|
||||
typedef struct _PixelList {
|
||||
|
@ -50,7 +48,7 @@ typedef struct _BoxNode {
|
|||
PixelList *head[3],*tail[3];
|
||||
int axis;
|
||||
int volume;
|
||||
unsigned long pixelCount;
|
||||
uint32_t pixelCount;
|
||||
} BoxNode;
|
||||
|
||||
#define _SQR(x) ((x)*(x))
|
||||
|
@ -76,104 +74,92 @@ typedef struct _BoxNode {
|
|||
((q)->c.g=(p)->c.g>>(s)), \
|
||||
((q)->c.b=(p)->c.b>>(s))
|
||||
|
||||
static unsigned long
|
||||
unshifted_pixel_hash(const HashTable h, const void *p)
|
||||
static uint32_t
|
||||
unshifted_pixel_hash(const HashTable *h, const Pixel pixel)
|
||||
{
|
||||
Pixel *pixel=(Pixel *)&p;
|
||||
unsigned long hash=PIXEL_HASH(pixel->c.r,
|
||||
pixel->c.g,
|
||||
pixel->c.b);
|
||||
return hash;
|
||||
return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b);
|
||||
}
|
||||
|
||||
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;
|
||||
Pixel *pixel2=(Pixel *)&b;
|
||||
if (pixel1->c.r==pixel2->c.r) {
|
||||
if (pixel1->c.g==pixel2->c.g) {
|
||||
if (pixel1->c.b==pixel2->c.b) {
|
||||
if (pixel1.c.r==pixel2.c.r) {
|
||||
if (pixel1.c.g==pixel2.c.g) {
|
||||
if (pixel1.c.b==pixel2.c.b) {
|
||||
return 0;
|
||||
} else {
|
||||
return (int)(pixel1->c.b)-(int)(pixel2->c.b);
|
||||
return (int)(pixel1.c.b)-(int)(pixel2.c.b);
|
||||
}
|
||||
} else {
|
||||
return (int)(pixel1->c.g)-(int)(pixel2->c.g);
|
||||
return (int)(pixel1.c.g)-(int)(pixel2.c.g);
|
||||
}
|
||||
} else {
|
||||
return (int)(pixel1->c.r)-(int)(pixel2->c.r);
|
||||
return (int)(pixel1.c.r)-(int)(pixel2.c.r);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
pixel_hash(const HashTable h,const void *p)
|
||||
static uint32_t
|
||||
pixel_hash(const HashTable *h,const Pixel pixel)
|
||||
{
|
||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
|
||||
Pixel *pixel=(Pixel *)&p;
|
||||
unsigned long hash=PIXEL_HASH(pixel->c.r>>d->scale,
|
||||
pixel->c.g>>d->scale,
|
||||
pixel->c.b>>d->scale);
|
||||
return hash;
|
||||
return PIXEL_HASH(pixel.c.r>>d->scale, pixel.c.g>>d->scale, pixel.c.b>>d->scale);
|
||||
}
|
||||
|
||||
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);
|
||||
Pixel *pixel1=(Pixel *)&a;
|
||||
Pixel *pixel2=(Pixel *)&b;
|
||||
unsigned long A,B;
|
||||
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);
|
||||
uint32_t A,B;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
rehash_collide(HashTable h,
|
||||
void **keyp,
|
||||
void **valp,
|
||||
void *newkey,
|
||||
void *newval)
|
||||
rehash_collide(const HashTable *h,
|
||||
Pixel *keyp,
|
||||
uint32_t *valp,
|
||||
Pixel newkey,
|
||||
uint32_t newval)
|
||||
{
|
||||
*valp = (void *)(((unsigned long) *valp) + ((unsigned long) newval));
|
||||
*valp += newval;
|
||||
}
|
||||
|
||||
/* %% */
|
||||
|
||||
static HashTable
|
||||
create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
||||
static HashTable *
|
||||
create_pixel_hash(Pixel *pixelData,uint32_t nPixels)
|
||||
{
|
||||
PixelHashData *d;
|
||||
HashTable *hash;
|
||||
unsigned long i;
|
||||
unsigned long timer,timer2,timer3;
|
||||
uint32_t i;
|
||||
#ifndef NO_OUTPUT
|
||||
uint32_t timer,timer2,timer3;
|
||||
#endif
|
||||
|
||||
d=malloc(sizeof(PixelHashData));
|
||||
if (!d) return NULL;
|
||||
hash=hashtable_new(pixel_hash,pixel_cmp);
|
||||
hashtable_set_user_data(hash,d);
|
||||
d->scale=0;
|
||||
#ifndef NO_OUTPUT
|
||||
timer=timer3=clock();
|
||||
#endif
|
||||
for (i=0;i<nPixels;i++) {
|
||||
if (!hashtable_insert_or_update_computed(hash,
|
||||
(void *)pixelData[i].v,
|
||||
pixelData[i],
|
||||
new_count_func,
|
||||
exists_count_func)) {;
|
||||
}
|
||||
|
@ -181,14 +167,14 @@ create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
|||
d->scale++;
|
||||
#ifndef NO_OUTPUT
|
||||
printf ("rehashing - new scale: %d\n",(int)d->scale);
|
||||
#endif
|
||||
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
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifndef NO_OUTPUT
|
||||
|
@ -201,7 +187,7 @@ create_pixel_hash(Pixel *pixelData,unsigned long nPixels)
|
|||
}
|
||||
|
||||
static void
|
||||
destroy_pixel_hash(HashTable hash)
|
||||
destroy_pixel_hash(HashTable *hash)
|
||||
{
|
||||
PixelHashData *d=(PixelHashData *)hashtable_get_user_data(hash);
|
||||
if (d) free(d);
|
||||
|
@ -237,17 +223,15 @@ compute_box_volume(BoxNode *b)
|
|||
}
|
||||
|
||||
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);
|
||||
PixelList **pl=(PixelList **)u;
|
||||
PixelList *p;
|
||||
Pixel *pixel=(Pixel *)&key;
|
||||
int i;
|
||||
Pixel q;
|
||||
int count=(unsigned long) val;
|
||||
|
||||
PIXEL_SCALE(pixel,&q,d->scale);
|
||||
PIXEL_SCALE(&pixel,&q,d->scale);
|
||||
|
||||
p=malloc(sizeof(PixelList));
|
||||
if (!p) return;
|
||||
|
@ -327,7 +311,7 @@ test_sorted(PixelList *pl[3])
|
|||
#endif
|
||||
|
||||
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 *b=(BoxNode *)B;
|
||||
|
@ -341,11 +325,11 @@ splitlists(PixelList *h[3],
|
|||
PixelList *t[3],
|
||||
PixelList *nh[2][3],
|
||||
PixelList *nt[2][3],
|
||||
unsigned long nCount[2],
|
||||
uint32_t nCount[2],
|
||||
int axis,
|
||||
unsigned long pixelCount)
|
||||
uint32_t pixelCount)
|
||||
{
|
||||
unsigned long left;
|
||||
uint32_t left;
|
||||
|
||||
PixelList *l,*r,*c,*n;
|
||||
int i;
|
||||
|
@ -476,7 +460,7 @@ split(BoxNode *node)
|
|||
int i;
|
||||
PixelList *heads[2][3];
|
||||
PixelList *tails[2][3];
|
||||
unsigned long newCounts[2];
|
||||
uint32_t newCounts[2];
|
||||
BoxNode *left,*right;
|
||||
|
||||
rh=node->head[0]->p.c.r;
|
||||
|
@ -618,13 +602,13 @@ split(BoxNode *node)
|
|||
|
||||
static BoxNode *
|
||||
median_cut(PixelList *hl[3],
|
||||
unsigned long imPixelCount,
|
||||
uint32_t imPixelCount,
|
||||
int nPixels)
|
||||
{
|
||||
PixelList *tl[3];
|
||||
int i;
|
||||
BoxNode *root;
|
||||
Heap h;
|
||||
Heap* h;
|
||||
BoxNode *thisNode;
|
||||
|
||||
h=ImagingQuantHeapNew(box_heap_cmp);
|
||||
|
@ -701,7 +685,7 @@ checkContained(BoxNode *n,Pixel *pp)
|
|||
#endif
|
||||
|
||||
static int
|
||||
annotate_hash_table(BoxNode *n,HashTable h,unsigned long *box)
|
||||
annotate_hash_table(BoxNode *n,HashTable *h,uint32_t *box)
|
||||
{
|
||||
PixelList *p;
|
||||
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]) {
|
||||
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
|
||||
printf ("hashtable insert failed\n");
|
||||
#endif
|
||||
|
@ -731,20 +715,20 @@ annotate_hash_table(BoxNode *n,HashTable h,unsigned long *box)
|
|||
static int
|
||||
_sort_ulong_ptr_keys(const void *a, const void *b)
|
||||
{
|
||||
unsigned long A=**(unsigned long **)a;
|
||||
unsigned long B=**(unsigned long **)b;
|
||||
uint32_t A=**(uint32_t **)a;
|
||||
uint32_t B=**(uint32_t **)b;
|
||||
return (A==B)?0:((A<B)?-1:+1);
|
||||
}
|
||||
|
||||
static int
|
||||
resort_distance_tables(unsigned long *avgDist,
|
||||
unsigned long **avgDistSortKey,
|
||||
resort_distance_tables(uint32_t *avgDist,
|
||||
uint32_t **avgDistSortKey,
|
||||
Pixel *p,
|
||||
unsigned long nEntries)
|
||||
uint32_t nEntries)
|
||||
{
|
||||
unsigned long i,j,k;
|
||||
unsigned long **skRow;
|
||||
unsigned long *skElt;
|
||||
uint32_t i,j,k;
|
||||
uint32_t **skRow;
|
||||
uint32_t *skElt;
|
||||
|
||||
for (i=0;i<nEntries;i++) {
|
||||
avgDist[i*nEntries+i]=0;
|
||||
|
@ -767,12 +751,12 @@ resort_distance_tables(unsigned long *avgDist,
|
|||
}
|
||||
|
||||
static int
|
||||
build_distance_tables(unsigned long *avgDist,
|
||||
unsigned long **avgDistSortKey,
|
||||
build_distance_tables(uint32_t *avgDist,
|
||||
uint32_t **avgDistSortKey,
|
||||
Pixel *p,
|
||||
unsigned long nEntries)
|
||||
uint32_t nEntries)
|
||||
{
|
||||
unsigned long i,j;
|
||||
uint32_t i,j;
|
||||
|
||||
for (i=0;i<nEntries;i++) {
|
||||
avgDist[i*nEntries+i]=0;
|
||||
|
@ -787,7 +771,7 @@ build_distance_tables(unsigned long *avgDist,
|
|||
for (i=0;i<nEntries;i++) {
|
||||
qsort(avgDistSortKey+i*nEntries,
|
||||
nEntries,
|
||||
sizeof(unsigned long *),
|
||||
sizeof(uint32_t *),
|
||||
_sort_ulong_ptr_keys);
|
||||
}
|
||||
return 1;
|
||||
|
@ -795,23 +779,23 @@ build_distance_tables(unsigned long *avgDist,
|
|||
|
||||
static int
|
||||
map_image_pixels(Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
Pixel *paletteData,
|
||||
unsigned long nPaletteEntries,
|
||||
unsigned long *avgDist,
|
||||
unsigned long **avgDistSortKey,
|
||||
unsigned long *pixelArray)
|
||||
uint32_t nPaletteEntries,
|
||||
uint32_t *avgDist,
|
||||
uint32_t **avgDistSortKey,
|
||||
uint32_t *pixelArray)
|
||||
{
|
||||
unsigned long *aD,**aDSK;
|
||||
unsigned long idx;
|
||||
unsigned long i,j;
|
||||
unsigned long bestdist,bestmatch,dist;
|
||||
unsigned long initialdist;
|
||||
HashTable h2;
|
||||
uint32_t *aD,**aDSK;
|
||||
uint32_t idx;
|
||||
uint32_t i,j;
|
||||
uint32_t bestdist,bestmatch,dist;
|
||||
uint32_t initialdist;
|
||||
HashTable *h2;
|
||||
|
||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||
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;
|
||||
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
||||
bestdist=initialdist;
|
||||
|
@ -830,7 +814,7 @@ map_image_pixels(Pixel *pixelData,
|
|||
break;
|
||||
}
|
||||
}
|
||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
||||
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||
}
|
||||
pixelArray[i]=bestmatch;
|
||||
}
|
||||
|
@ -841,26 +825,26 @@ map_image_pixels(Pixel *pixelData,
|
|||
static int
|
||||
map_image_pixels_from_quantized_pixels(
|
||||
Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
Pixel *paletteData,
|
||||
unsigned long nPaletteEntries,
|
||||
unsigned long *avgDist,
|
||||
unsigned long **avgDistSortKey,
|
||||
unsigned long *pixelArray,
|
||||
unsigned long *avg[3],
|
||||
unsigned long *count)
|
||||
uint32_t nPaletteEntries,
|
||||
uint32_t *avgDist,
|
||||
uint32_t **avgDistSortKey,
|
||||
uint32_t *pixelArray,
|
||||
uint32_t *avg[3],
|
||||
uint32_t *count)
|
||||
{
|
||||
unsigned long *aD,**aDSK;
|
||||
unsigned long idx;
|
||||
unsigned long i,j;
|
||||
unsigned long bestdist,bestmatch,dist;
|
||||
unsigned long initialdist;
|
||||
HashTable h2;
|
||||
uint32_t *aD,**aDSK;
|
||||
uint32_t idx;
|
||||
uint32_t i,j;
|
||||
uint32_t bestdist,bestmatch,dist;
|
||||
uint32_t initialdist;
|
||||
HashTable *h2;
|
||||
int changes=0;
|
||||
|
||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||
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];
|
||||
initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
|
||||
bestdist=initialdist;
|
||||
|
@ -879,7 +863,7 @@ map_image_pixels_from_quantized_pixels(
|
|||
break;
|
||||
}
|
||||
}
|
||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
||||
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||
}
|
||||
if (pixelArray[i]!=bestmatch) {
|
||||
changes++;
|
||||
|
@ -901,29 +885,29 @@ map_image_pixels_from_quantized_pixels(
|
|||
static int
|
||||
map_image_pixels_from_median_box(
|
||||
Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
Pixel *paletteData,
|
||||
unsigned long nPaletteEntries,
|
||||
uint32_t nPaletteEntries,
|
||||
HashTable *medianBoxHash,
|
||||
unsigned long *avgDist,
|
||||
unsigned long **avgDistSortKey,
|
||||
unsigned long *pixelArray)
|
||||
uint32_t *avgDist,
|
||||
uint32_t **avgDistSortKey,
|
||||
uint32_t *pixelArray)
|
||||
{
|
||||
unsigned long *aD,**aDSK;
|
||||
unsigned long idx;
|
||||
unsigned long i,j;
|
||||
unsigned long bestdist,bestmatch,dist;
|
||||
unsigned long initialdist;
|
||||
HashTable h2;
|
||||
unsigned long pixelVal;
|
||||
uint32_t *aD,**aDSK;
|
||||
uint32_t idx;
|
||||
uint32_t i,j;
|
||||
uint32_t bestdist,bestmatch,dist;
|
||||
uint32_t initialdist;
|
||||
HashTable *h2;
|
||||
uint32_t pixelVal;
|
||||
|
||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
if (!hashtable_lookup(medianBoxHash,(void *)pixelData[i].v,(void **)&pixelVal)) {
|
||||
if (!hashtable_lookup(medianBoxHash,pixelData[i],&pixelVal)) {
|
||||
#ifndef NO_OUTPUT
|
||||
printf ("pixel lookup failed\n");
|
||||
#endif
|
||||
|
@ -948,7 +932,7 @@ map_image_pixels_from_median_box(
|
|||
}
|
||||
}
|
||||
pixelArray[i]=bestmatch;
|
||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
||||
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||
}
|
||||
hashtable_free(h2);
|
||||
return 1;
|
||||
|
@ -957,27 +941,27 @@ map_image_pixels_from_median_box(
|
|||
static int
|
||||
compute_palette_from_median_cut(
|
||||
Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
HashTable medianBoxHash,
|
||||
uint32_t nPixels,
|
||||
HashTable *medianBoxHash,
|
||||
Pixel **palette,
|
||||
unsigned long nPaletteEntries)
|
||||
uint32_t nPaletteEntries)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned long paletteEntry;
|
||||
uint32_t i;
|
||||
uint32_t paletteEntry;
|
||||
Pixel *p;
|
||||
unsigned long *avg[3];
|
||||
unsigned long *count;
|
||||
uint32_t *avg[3];
|
||||
uint32_t *count;
|
||||
|
||||
*palette=NULL;
|
||||
if (!(count=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
||||
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||
return 0;
|
||||
}
|
||||
memset(count,0,sizeof(unsigned long)*nPaletteEntries);
|
||||
memset(count,0,sizeof(uint32_t)*nPaletteEntries);
|
||||
for(i=0;i<3;i++) {
|
||||
avg[i]=NULL;
|
||||
}
|
||||
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++) {
|
||||
if (avg[i]) free (avg[i]);
|
||||
}
|
||||
|
@ -986,7 +970,7 @@ compute_palette_from_median_cut(
|
|||
}
|
||||
}
|
||||
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++) {
|
||||
#ifdef TEST_SPLIT_INTEGRITY
|
||||
|
@ -998,7 +982,7 @@ compute_palette_from_median_cut(
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (!hashtable_lookup(medianBoxHash,(void *)pixelData[i].v,(void **)&paletteEntry)) {
|
||||
if (!hashtable_lookup(medianBoxHash,pixelData[i],&paletteEntry)) {
|
||||
#ifndef NO_OUTPUT
|
||||
printf ("pixel lookup failed\n");
|
||||
#endif
|
||||
|
@ -1039,11 +1023,11 @@ compute_palette_from_median_cut(
|
|||
static int
|
||||
recompute_palette_from_averages(
|
||||
Pixel *palette,
|
||||
unsigned long nPaletteEntries,
|
||||
unsigned long *avg[3],
|
||||
unsigned long *count)
|
||||
uint32_t nPaletteEntries,
|
||||
uint32_t *avg[3],
|
||||
uint32_t *count)
|
||||
{
|
||||
unsigned long i;
|
||||
uint32_t i;
|
||||
|
||||
for (i=0;i<nPaletteEntries;i++) {
|
||||
palette[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
|
||||
|
@ -1056,18 +1040,18 @@ recompute_palette_from_averages(
|
|||
static int
|
||||
compute_palette_from_quantized_pixels(
|
||||
Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
Pixel *palette,
|
||||
unsigned long nPaletteEntries,
|
||||
unsigned long *avg[3],
|
||||
unsigned long *count,
|
||||
unsigned long *qp)
|
||||
uint32_t nPaletteEntries,
|
||||
uint32_t *avg[3],
|
||||
uint32_t *count,
|
||||
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++) {
|
||||
memset(avg[i],0,sizeof(unsigned long)*nPaletteEntries);
|
||||
memset(avg[i],0,sizeof(uint32_t)*nPaletteEntries);
|
||||
}
|
||||
for (i=0;i<nPixels;i++) {
|
||||
if (qp[i]>=nPaletteEntries) {
|
||||
|
@ -1091,35 +1075,35 @@ compute_palette_from_quantized_pixels(
|
|||
|
||||
static int
|
||||
k_means(Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
Pixel *paletteData,
|
||||
unsigned long nPaletteEntries,
|
||||
unsigned long *qp,
|
||||
uint32_t nPaletteEntries,
|
||||
uint32_t *qp,
|
||||
int threshold)
|
||||
{
|
||||
unsigned long *avg[3];
|
||||
unsigned long *count;
|
||||
unsigned long i;
|
||||
unsigned long *avgDist;
|
||||
unsigned long **avgDistSortKey;
|
||||
uint32_t *avg[3];
|
||||
uint32_t *count;
|
||||
uint32_t i;
|
||||
uint32_t *avgDist;
|
||||
uint32_t **avgDistSortKey;
|
||||
int changes;
|
||||
int built=0;
|
||||
|
||||
if (!(count=malloc(sizeof(unsigned long)*nPaletteEntries))) {
|
||||
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) {
|
||||
return 0;
|
||||
}
|
||||
for(i=0;i<3;i++) {
|
||||
avg[i]=NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
avgDist=malloc(sizeof(unsigned long)*nPaletteEntries*nPaletteEntries);
|
||||
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries);
|
||||
if (!avgDist) { goto error_1; }
|
||||
|
||||
avgDistSortKey=malloc(sizeof(unsigned long *)*nPaletteEntries*nPaletteEntries);
|
||||
avgDistSortKey=malloc(sizeof(uint32_t *)*nPaletteEntries*nPaletteEntries);
|
||||
if (!avgDistSortKey) { goto error_2; }
|
||||
|
||||
#ifndef NO_OUTPUT
|
||||
|
@ -1172,26 +1156,26 @@ error_1:
|
|||
|
||||
int
|
||||
quantize(Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
unsigned long nQuantPixels,
|
||||
uint32_t nPixels,
|
||||
uint32_t nQuantPixels,
|
||||
Pixel **palette,
|
||||
unsigned long *paletteLength,
|
||||
unsigned long **quantizedPixels,
|
||||
uint32_t *paletteLength,
|
||||
uint32_t **quantizedPixels,
|
||||
int kmeans)
|
||||
{
|
||||
PixelList *hl[3];
|
||||
HashTable h;
|
||||
HashTable *h;
|
||||
BoxNode *root;
|
||||
unsigned long i;
|
||||
unsigned long *qp;
|
||||
unsigned long nPaletteEntries;
|
||||
uint32_t i;
|
||||
uint32_t *qp;
|
||||
uint32_t nPaletteEntries;
|
||||
|
||||
unsigned long *avgDist;
|
||||
unsigned long **avgDistSortKey;
|
||||
uint32_t *avgDist;
|
||||
uint32_t **avgDistSortKey;
|
||||
Pixel *p;
|
||||
|
||||
#ifndef NO_OUTPUT
|
||||
unsigned long timer,timer2;
|
||||
uint32_t timer,timer2;
|
||||
#endif
|
||||
|
||||
#ifndef NO_OUTPUT
|
||||
|
@ -1266,13 +1250,13 @@ quantize(Pixel *pixelData,
|
|||
free_box_tree(root);
|
||||
root=NULL;
|
||||
|
||||
qp=malloc(sizeof(unsigned long)*nPixels);
|
||||
qp=malloc(sizeof(uint32_t)*nPixels);
|
||||
if (!qp) { goto error_4; }
|
||||
|
||||
avgDist=malloc(sizeof(unsigned long)*nPaletteEntries*nPaletteEntries);
|
||||
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries);
|
||||
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 (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) {
|
||||
|
@ -1286,12 +1270,12 @@ quantize(Pixel *pixelData,
|
|||
#ifdef TEST_NEAREST_NEIGHBOUR
|
||||
#include <math.h>
|
||||
{
|
||||
unsigned long bestmatch,bestdist,dist;
|
||||
HashTable h2;
|
||||
uint32_t bestmatch,bestdist,dist;
|
||||
HashTable *h2;
|
||||
printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock();
|
||||
h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||
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;
|
||||
} else {
|
||||
bestmatch=0;
|
||||
|
@ -1312,7 +1296,7 @@ quantize(Pixel *pixelData,
|
|||
bestmatch=j;
|
||||
}
|
||||
}
|
||||
hashtable_insert(h2,(void *)pixelData[i].v,(void *)bestmatch);
|
||||
hashtable_insert(h2,pixelData[i],bestmatch);
|
||||
}
|
||||
if (qp[i]!=bestmatch ) {
|
||||
printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n",
|
||||
|
@ -1375,53 +1359,52 @@ error_0:
|
|||
typedef struct {
|
||||
Pixel new;
|
||||
Pixel furthest;
|
||||
unsigned long furthestDistance;
|
||||
uint32_t furthestDistance;
|
||||
int secondPixel;
|
||||
} DistanceData;
|
||||
|
||||
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;
|
||||
Pixel *pixel=(Pixel *)&key;
|
||||
unsigned long oldDist=*(unsigned long *)val;
|
||||
unsigned long newDist;
|
||||
newDist=_DISTSQR(&(data->new),pixel);
|
||||
uint32_t oldDist=*dist;
|
||||
uint32_t newDist;
|
||||
newDist=_DISTSQR(&(data->new),&pixel);
|
||||
if (data->secondPixel || newDist<oldDist) {
|
||||
*(unsigned long *)val=newDist;
|
||||
*dist=newDist;
|
||||
oldDist=newDist;
|
||||
}
|
||||
if (oldDist>data->furthestDistance) {
|
||||
data->furthestDistance=oldDist;
|
||||
data->furthest.v=pixel->v;
|
||||
data->furthest.v=pixel.v;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
quantize2(Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
unsigned long nQuantPixels,
|
||||
uint32_t nPixels,
|
||||
uint32_t nQuantPixels,
|
||||
Pixel **palette,
|
||||
unsigned long *paletteLength,
|
||||
unsigned long **quantizedPixels,
|
||||
uint32_t *paletteLength,
|
||||
uint32_t **quantizedPixels,
|
||||
int kmeans)
|
||||
{
|
||||
HashTable h;
|
||||
unsigned long i;
|
||||
unsigned long mean[3];
|
||||
HashTable *h;
|
||||
uint32_t i;
|
||||
uint32_t mean[3];
|
||||
Pixel *p;
|
||||
DistanceData data;
|
||||
|
||||
unsigned long *qp;
|
||||
unsigned long *avgDist;
|
||||
unsigned long **avgDistSortKey;
|
||||
uint32_t *qp;
|
||||
uint32_t *avgDist;
|
||||
uint32_t **avgDistSortKey;
|
||||
|
||||
p=malloc(sizeof(Pixel)*nQuantPixels);
|
||||
if (!p) return 0;
|
||||
mean[0]=mean[1]=mean[2]=0;
|
||||
h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
|
||||
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[1]+=pixelData[i].c.g;
|
||||
mean[2]+=pixelData[i].c.b;
|
||||
|
@ -1438,13 +1421,13 @@ quantize2(Pixel *pixelData,
|
|||
}
|
||||
hashtable_free(h);
|
||||
|
||||
qp=malloc(sizeof(unsigned long)*nPixels);
|
||||
qp=malloc(sizeof(uint32_t)*nPixels);
|
||||
if (!qp) { goto error_1; }
|
||||
|
||||
avgDist=malloc(sizeof(unsigned long)*nQuantPixels*nQuantPixels);
|
||||
avgDist=malloc(sizeof(uint32_t)*nQuantPixels*nQuantPixels);
|
||||
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 (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) {
|
||||
|
@ -1482,9 +1465,9 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
|
|||
UINT8* pp;
|
||||
Pixel* p;
|
||||
Pixel* palette;
|
||||
unsigned long paletteLength;
|
||||
uint32_t paletteLength;
|
||||
int result;
|
||||
unsigned long* newData;
|
||||
uint32_t* newData;
|
||||
Imaging imOut;
|
||||
int withAlpha = 0;
|
||||
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 "QuantHash.h"
|
||||
#include "QuantDefines.h"
|
||||
|
||||
typedef struct _IntHashNode {
|
||||
struct _IntHashNode *next;
|
||||
void *key,*value;
|
||||
} IntHashNode;
|
||||
typedef struct _HashNode {
|
||||
struct _HashNode *next;
|
||||
HashKey_t key;
|
||||
HashVal_t value;
|
||||
} HashNode;
|
||||
|
||||
typedef struct _IntHashTable {
|
||||
IntHashNode **table;
|
||||
unsigned long length;
|
||||
unsigned long count;
|
||||
typedef struct _HashTable {
|
||||
HashNode **table;
|
||||
uint32_t length;
|
||||
uint32_t count;
|
||||
HashFunc hashFunc;
|
||||
HashCmpFunc cmpFunc;
|
||||
DestroyFunc keyDestroyFunc;
|
||||
DestroyFunc valDestroyFunc;
|
||||
KeyDestroyFunc keyDestroyFunc;
|
||||
ValDestroyFunc valDestroyFunc;
|
||||
void *userData;
|
||||
} IntHashTable;
|
||||
} HashTable;
|
||||
|
||||
#define MIN_LENGTH 11
|
||||
#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
|
||||
static int _hashtable_test(IntHashTable *);
|
||||
static int _hashtable_test(HashTable *);
|
||||
#endif
|
||||
|
||||
HashTable hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
||||
IntHashTable *h;
|
||||
h=malloc(sizeof(IntHashTable));
|
||||
HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
||||
HashTable *h;
|
||||
h=malloc(sizeof(HashTable));
|
||||
if (!h) { return NULL; }
|
||||
h->hashFunc=hf;
|
||||
h->cmpFunc=cf;
|
||||
|
@ -59,25 +59,24 @@ HashTable hashtable_new(HashFunc hf,HashCmpFunc cf) {
|
|||
h->length=MIN_LENGTH;
|
||||
h->count=0;
|
||||
h->userData=NULL;
|
||||
h->table=malloc(sizeof(IntHashNode *)*h->length);
|
||||
h->table=malloc(sizeof(HashNode *)*h->length);
|
||||
if (!h->table) { free(h); return NULL; }
|
||||
memset (h->table,0,sizeof(IntHashNode *)*h->length);
|
||||
return (HashTable)h;
|
||||
memset (h->table,0,sizeof(HashNode *)*h->length);
|
||||
return h;
|
||||
}
|
||||
|
||||
static void _hashtable_destroy(HashTable H,const void *key,const void *val,void *u) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
if (h->keyDestroyFunc&&key) {
|
||||
h->keyDestroyFunc((HashTable)h,(void *)key);
|
||||
static void _hashtable_destroy(const HashTable *h,const HashKey_t key,const HashVal_t val,void *u) {
|
||||
if (h->keyDestroyFunc) {
|
||||
h->keyDestroyFunc(h,key);
|
||||
}
|
||||
if (h->valDestroyFunc&&val) {
|
||||
h->valDestroyFunc((HashTable)h,(void *)val);
|
||||
if (h->valDestroyFunc) {
|
||||
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};
|
||||
unsigned long t;
|
||||
uint32_t t;
|
||||
while (start>1) {
|
||||
if (!unit[start&0x0f]) {
|
||||
start+=dir;
|
||||
|
@ -94,22 +93,20 @@ static unsigned long _findPrime(unsigned long start,int dir) {
|
|||
return start;
|
||||
}
|
||||
|
||||
static void _hashtable_rehash(IntHashTable *h,
|
||||
CollisionFunc cf,
|
||||
unsigned long newSize) {
|
||||
IntHashNode **oldTable=h->table;
|
||||
unsigned long i;
|
||||
IntHashNode *n,*nn;
|
||||
unsigned long oldSize;
|
||||
static void _hashtable_rehash(HashTable *h,CollisionFunc cf,uint32_t newSize) {
|
||||
HashNode **oldTable=h->table;
|
||||
uint32_t i;
|
||||
HashNode *n,*nn;
|
||||
uint32_t oldSize;
|
||||
oldSize=h->length;
|
||||
h->table=malloc(sizeof(IntHashNode *)*newSize);
|
||||
h->table=malloc(sizeof(HashNode *)*newSize);
|
||||
if (!h->table) {
|
||||
h->table=oldTable;
|
||||
return;
|
||||
}
|
||||
h->length=newSize;
|
||||
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 (n=oldTable[i];n;n=nn) {
|
||||
nn=n->next;
|
||||
|
@ -119,9 +116,9 @@ static void _hashtable_rehash(IntHashTable *h,
|
|||
free(oldTable);
|
||||
}
|
||||
|
||||
static void _hashtable_resize(IntHashTable *h) {
|
||||
unsigned long newSize;
|
||||
unsigned long oldSize;
|
||||
static void _hashtable_resize(HashTable *h) {
|
||||
uint32_t newSize;
|
||||
uint32_t oldSize;
|
||||
oldSize=h->length;
|
||||
newSize=oldSize;
|
||||
if (h->count*RESIZE_FACTOR<h->length) {
|
||||
|
@ -136,13 +133,13 @@ static void _hashtable_resize(IntHashTable *h) {
|
|||
}
|
||||
|
||||
#if 0
|
||||
static int _hashtable_test(IntHashTable *h) {
|
||||
unsigned long i;
|
||||
static int _hashtable_test(HashTable *h) {
|
||||
uint32_t i;
|
||||
int j;
|
||||
IntHashNode *n;
|
||||
HashNode *n;
|
||||
for (i=0;i<h->length;i++) {
|
||||
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 ("\n");
|
||||
|
@ -151,26 +148,26 @@ static int _hashtable_test(IntHashTable *h) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static int _hashtable_insert_node(IntHashTable *h,IntHashNode *node,int resize,int update,CollisionFunc cf) {
|
||||
unsigned long hash=h->hashFunc((HashTable)h,node->key)%h->length;
|
||||
IntHashNode **n,*nv;
|
||||
static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) {
|
||||
uint32_t hash=h->hashFunc(h,node->key)%h->length;
|
||||
HashNode **n,*nv;
|
||||
int i;
|
||||
|
||||
for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
|
||||
nv=*n;
|
||||
i=h->cmpFunc((HashTable)h,nv->key,node->key);
|
||||
i=h->cmpFunc(h,nv->key,node->key);
|
||||
if (!i) {
|
||||
if (cf) {
|
||||
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);
|
||||
return 1;
|
||||
} else {
|
||||
if (h->valDestroyFunc) {
|
||||
h->valDestroyFunc((HashTable)h,nv->value);
|
||||
h->valDestroyFunc(h,nv->value);
|
||||
}
|
||||
if (h->keyDestroyFunc) {
|
||||
h->keyDestroyFunc((HashTable)h,nv->key);
|
||||
h->keyDestroyFunc(h,nv->key);
|
||||
}
|
||||
nv->key=node->key;
|
||||
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) {
|
||||
IntHashNode **n,*nv;
|
||||
IntHashNode *t;
|
||||
static int _hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val,int resize,int update) {
|
||||
HashNode **n,*nv;
|
||||
HashNode *t;
|
||||
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)) {
|
||||
nv=*n;
|
||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
||||
i=h->cmpFunc(h,nv->key,key);
|
||||
if (!i) {
|
||||
if (h->valDestroyFunc) { h->valDestroyFunc((HashTable)h,nv->value); }
|
||||
if (h->valDestroyFunc) { h->valDestroyFunc(h,nv->value); }
|
||||
nv->value=val;
|
||||
return 1;
|
||||
} else if (i>0) {
|
||||
|
@ -210,7 +207,7 @@ static int _hashtable_insert(IntHashTable *h,void *key,void *val,int resize,int
|
|||
}
|
||||
}
|
||||
if (!update) {
|
||||
t=malloc(sizeof(IntHashNode));
|
||||
t=malloc(sizeof(HashNode));
|
||||
if (!t) return 0;
|
||||
t->next=*n;
|
||||
*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) {
|
||||
IntHashNode **n,*nv;
|
||||
IntHashNode *t;
|
||||
static int _hashtable_lookup_or_insert(HashTable *h,HashKey_t key,HashVal_t *retVal,HashVal_t newVal,int resize) {
|
||||
HashNode **n,*nv;
|
||||
HashNode *t;
|
||||
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)) {
|
||||
nv=*n;
|
||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
||||
i=h->cmpFunc(h,nv->key,key);
|
||||
if (!i) {
|
||||
*retVal=nv->value;
|
||||
return 1;
|
||||
|
@ -240,7 +237,7 @@ static int _hashtable_lookup_or_insert(IntHashTable *h,void *key,void **retVal,v
|
|||
break;
|
||||
}
|
||||
}
|
||||
t=malloc(sizeof(IntHashNode));
|
||||
t=malloc(sizeof(HashNode));
|
||||
if (!t) return 0;
|
||||
t->next=*n;
|
||||
*n=t;
|
||||
|
@ -252,26 +249,25 @@ static int _hashtable_lookup_or_insert(IntHashTable *h,void *key,void **retVal,v
|
|||
return 1;
|
||||
}
|
||||
|
||||
int hashtable_insert_or_update_computed(HashTable H,
|
||||
void *key,
|
||||
int hashtable_insert_or_update_computed(HashTable *h,
|
||||
HashKey_t key,
|
||||
ComputeFunc newFunc,
|
||||
ComputeFunc existsFunc) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
IntHashNode **n,*nv;
|
||||
IntHashNode *t;
|
||||
HashNode **n,*nv;
|
||||
HashNode *t;
|
||||
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)) {
|
||||
nv=*n;
|
||||
i=h->cmpFunc((HashTable)h,nv->key,key);
|
||||
i=h->cmpFunc(h,nv->key,key);
|
||||
if (!i) {
|
||||
void *old=nv->value;
|
||||
HashVal_t old=nv->value;
|
||||
if (existsFunc) {
|
||||
existsFunc(H,nv->key,&(nv->value));
|
||||
existsFunc(h,nv->key,&(nv->value));
|
||||
if (nv->value!=old) {
|
||||
if (h->valDestroyFunc) {
|
||||
h->valDestroyFunc((HashTable)h,old);
|
||||
h->valDestroyFunc(h,old);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -282,13 +278,13 @@ int hashtable_insert_or_update_computed(HashTable H,
|
|||
break;
|
||||
}
|
||||
}
|
||||
t=malloc(sizeof(IntHashNode));
|
||||
t=malloc(sizeof(HashNode));
|
||||
if (!t) return 0;
|
||||
t->key=key;
|
||||
t->next=*n;
|
||||
*n=t;
|
||||
if (newFunc) {
|
||||
newFunc(H,t->key,&(t->value));
|
||||
newFunc(h,t->key,&(t->value));
|
||||
} else {
|
||||
free(t);
|
||||
return 0;
|
||||
|
@ -298,52 +294,47 @@ int hashtable_insert_or_update_computed(HashTable H,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int hashtable_update(HashTable H,void *key,void *val) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
int hashtable_update(HashTable *h,HashKey_t key,HashVal_t val) {
|
||||
return _hashtable_insert(h,key,val,1,0);
|
||||
}
|
||||
|
||||
int hashtable_insert(HashTable H,void *key,void *val) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val) {
|
||||
return _hashtable_insert(h,key,val,1,0);
|
||||
}
|
||||
|
||||
void hashtable_foreach_update(HashTable H,IteratorUpdateFunc i,void *u) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
IntHashNode *n;
|
||||
unsigned long x;
|
||||
void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u) {
|
||||
HashNode *n;
|
||||
uint32_t x;
|
||||
|
||||
if (h->table) {
|
||||
for (x=0;x<h->length;x++) {
|
||||
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) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
IntHashNode *n;
|
||||
unsigned long x;
|
||||
void hashtable_foreach(HashTable *h,IteratorFunc i,void *u) {
|
||||
HashNode *n;
|
||||
uint32_t x;
|
||||
|
||||
if (h->table) {
|
||||
for (x=0;x<h->length;x++) {
|
||||
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) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
IntHashNode *n,*nn;
|
||||
unsigned long i;
|
||||
void hashtable_free(HashTable *h) {
|
||||
HashNode *n,*nn;
|
||||
uint32_t i;
|
||||
|
||||
if (h->table) {
|
||||
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 (n=h->table[i];n;n=nn) {
|
||||
|
@ -356,31 +347,29 @@ void hashtable_free(HashTable H) {
|
|||
free(h);
|
||||
}
|
||||
|
||||
DestroyFunc hashtable_set_value_destroy_func(HashTable H,DestroyFunc d) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
DestroyFunc r=h->valDestroyFunc;
|
||||
ValDestroyFunc hashtable_set_value_destroy_func(HashTable *h,ValDestroyFunc d) {
|
||||
ValDestroyFunc r=h->valDestroyFunc;
|
||||
h->valDestroyFunc=d;
|
||||
return r;
|
||||
}
|
||||
|
||||
DestroyFunc hashtable_set_key_destroy_func(HashTable H,DestroyFunc d) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
DestroyFunc r=h->keyDestroyFunc;
|
||||
KeyDestroyFunc hashtable_set_key_destroy_func(HashTable *h,KeyDestroyFunc d) {
|
||||
KeyDestroyFunc r=h->keyDestroyFunc;
|
||||
h->keyDestroyFunc=d;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _hashtable_remove(IntHashTable *h,
|
||||
const void *key,
|
||||
void **keyRet,
|
||||
void **valRet,
|
||||
static int _hashtable_remove(HashTable *h,
|
||||
const HashKey_t key,
|
||||
HashKey_t *keyRet,
|
||||
HashVal_t *valRet,
|
||||
int resize) {
|
||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
||||
IntHashNode *n,*p;
|
||||
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||
HashNode *n,*p;
|
||||
int i;
|
||||
|
||||
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 (p) p=n->next; else h->table[hash]=n->next;
|
||||
*keyRet=n->key;
|
||||
|
@ -395,17 +384,17 @@ static int _hashtable_remove(IntHashTable *h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _hashtable_delete(IntHashTable *h,const void *key,int resize) {
|
||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
||||
IntHashNode *n,*p;
|
||||
static int _hashtable_delete(HashTable *h,const HashKey_t key,int resize) {
|
||||
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||
HashNode *n,*p;
|
||||
int i;
|
||||
|
||||
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 (p) p=n->next; else h->table[hash]=n->next;
|
||||
if (h->valDestroyFunc) { h->valDestroyFunc((HashTable)h,n->value); }
|
||||
if (h->keyDestroyFunc) { h->keyDestroyFunc((HashTable)h,n->key); }
|
||||
if (h->valDestroyFunc) { h->valDestroyFunc(h,n->value); }
|
||||
if (h->keyDestroyFunc) { h->keyDestroyFunc(h,n->key); }
|
||||
free(n);
|
||||
h->count++;
|
||||
return 1;
|
||||
|
@ -416,39 +405,33 @@ static int _hashtable_delete(IntHashTable *h,const void *key,int resize) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hashtable_remove(HashTable H,const void *key,void **keyRet,void **valRet) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
int hashtable_remove(HashTable *h,const HashKey_t key,HashKey_t *keyRet,HashVal_t *valRet) {
|
||||
return _hashtable_remove(h,key,keyRet,valRet,1);
|
||||
}
|
||||
|
||||
int hashtable_delete(HashTable H,const void *key) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
int hashtable_delete(HashTable *h,const HashKey_t key) {
|
||||
return _hashtable_delete(h,key,1);
|
||||
}
|
||||
|
||||
void hashtable_rehash_compute(HashTable H,CollisionFunc cf) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
void hashtable_rehash_compute(HashTable *h,CollisionFunc cf) {
|
||||
_hashtable_rehash(h,cf,h->length);
|
||||
}
|
||||
|
||||
void hashtable_rehash(HashTable H) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
void hashtable_rehash(HashTable *h) {
|
||||
_hashtable_rehash(h,NULL,h->length);
|
||||
}
|
||||
|
||||
int hashtable_lookup_or_insert(HashTable H,void *key,void **valp,void *val) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
int hashtable_lookup_or_insert(HashTable *h,HashKey_t key,HashVal_t *valp,HashVal_t val) {
|
||||
return _hashtable_lookup_or_insert(h,key,valp,val,1);
|
||||
}
|
||||
|
||||
int hashtable_lookup(const HashTable H,const void *key,void **valp) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
unsigned long hash=h->hashFunc((HashTable)h,key)%h->length;
|
||||
IntHashNode *n;
|
||||
int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp) {
|
||||
uint32_t hash=h->hashFunc(h,key)%h->length;
|
||||
HashNode *n;
|
||||
int i;
|
||||
|
||||
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) {
|
||||
*valp=n->value;
|
||||
return 1;
|
||||
|
@ -459,18 +442,15 @@ int hashtable_lookup(const HashTable H,const void *key,void **valp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned long hashtable_get_count(const HashTable H) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
uint32_t hashtable_get_count(const HashTable *h) {
|
||||
return h->count;
|
||||
}
|
||||
|
||||
void *hashtable_get_user_data(const HashTable H) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
void *hashtable_get_user_data(const HashTable *h) {
|
||||
return h->userData;
|
||||
}
|
||||
|
||||
void *hashtable_set_user_data(HashTable H,void *data) {
|
||||
IntHashTable *h=(IntHashTable *)H;
|
||||
void *hashtable_set_user_data(HashTable *h,void *data) {
|
||||
void *r=h->userData;
|
||||
h->userData=data;
|
||||
return r;
|
||||
|
|
|
@ -9,28 +9,41 @@
|
|||
* See the README file for information on usage and redistribution.
|
||||
*/
|
||||
|
||||
#ifndef __HASH_H__
|
||||
#define __HASH_H__
|
||||
#ifndef __QUANTHASH_H__
|
||||
#define __QUANTHASH_H__
|
||||
|
||||
#include "QuantTypes.h"
|
||||
|
||||
HashTable hashtable_new(HashFunc,HashCmpFunc);
|
||||
void hashtable_free(HashTable);
|
||||
void hashtable_foreach(HashTable,IteratorFunc,void *);
|
||||
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);
|
||||
typedef struct _HashTable HashTable;
|
||||
typedef Pixel HashKey_t;
|
||||
typedef uint32_t HashVal_t;
|
||||
|
||||
#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 <math.h>
|
||||
|
||||
#include "QuantHash.h"
|
||||
#include "QuantDefines.h"
|
||||
#include "QuantHeap.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct _Heap {
|
||||
void **heap;
|
||||
int heapsize;
|
||||
int heapcount;
|
||||
HeapCmpFunc cf;
|
||||
} IntHeap;
|
||||
} Heap;
|
||||
|
||||
#define INITIAL_SIZE 256
|
||||
|
||||
#define DEBUG
|
||||
// #define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
static int _heap_test(Heap);
|
||||
static int _heap_test(Heap *);
|
||||
#endif
|
||||
|
||||
void ImagingQuantHeapFree(Heap H) {
|
||||
IntHeap *h=(IntHeap *)H;
|
||||
void ImagingQuantHeapFree(Heap *h) {
|
||||
free(h->heap);
|
||||
free(h);
|
||||
}
|
||||
|
||||
static int _heap_grow(IntHeap *h,int newsize) {
|
||||
static int _heap_grow(Heap *h,int newsize) {
|
||||
void *newheap;
|
||||
if (!newsize) newsize=h->heapsize<<1;
|
||||
if (newsize<h->heapsize) return 0;
|
||||
|
@ -59,15 +57,14 @@ static int _heap_grow(IntHeap *h,int newsize) {
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int _heap_test(Heap H) {
|
||||
IntHeap *h=(IntHeap *)H;
|
||||
static int _heap_test(Heap *h) {
|
||||
int 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");
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,8 +73,7 @@ static int _heap_test(Heap H) {
|
|||
}
|
||||
#endif
|
||||
|
||||
int ImagingQuantHeapRemove(Heap H,void **r) {
|
||||
IntHeap *h=(IntHeap *)H;
|
||||
int ImagingQuantHeapRemove(Heap* h,void **r) {
|
||||
int k,l;
|
||||
void *v;
|
||||
|
||||
|
@ -89,31 +85,30 @@ int ImagingQuantHeapRemove(Heap H,void **r) {
|
|||
for (k=1;k*2<=h->heapcount;k=l) {
|
||||
l=k*2;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
if (h->cf(H,v,h->heap[l])>0) {
|
||||
if (h->cf(h,v,h->heap[l])>0) {
|
||||
break;
|
||||
}
|
||||
h->heap[k]=h->heap[l];
|
||||
}
|
||||
h->heap[k]=v;
|
||||
#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
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ImagingQuantHeapAdd(Heap H,void *val) {
|
||||
IntHeap *h=(IntHeap *)H;
|
||||
int ImagingQuantHeapAdd(Heap *h,void *val) {
|
||||
int k;
|
||||
if (h->heapcount==h->heapsize-1) {
|
||||
_heap_grow(h,0);
|
||||
}
|
||||
k=++h->heapcount;
|
||||
while (k!=1) {
|
||||
if (h->cf(H,val,h->heap[k/2])<=0) {
|
||||
if (h->cf(h,val,h->heap[k/2])<=0) {
|
||||
break;
|
||||
}
|
||||
h->heap[k]=h->heap[k/2];
|
||||
|
@ -121,13 +116,12 @@ int ImagingQuantHeapAdd(Heap H,void *val) {
|
|||
}
|
||||
h->heap[k]=val;
|
||||
#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
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ImagingQuantHeapTop(Heap H,void **r) {
|
||||
IntHeap *h=(IntHeap *)H;
|
||||
int ImagingQuantHeapTop(Heap *h,void **r) {
|
||||
if (!h->heapcount) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -136,15 +130,14 @@ int ImagingQuantHeapTop(Heap H,void **r) {
|
|||
}
|
||||
|
||||
Heap *ImagingQuantHeapNew(HeapCmpFunc cf) {
|
||||
IntHeap *h;
|
||||
Heap *h;
|
||||
|
||||
h=malloc(sizeof(IntHeap));
|
||||
h=malloc(sizeof(Heap));
|
||||
if (!h) return NULL;
|
||||
h->heapsize=INITIAL_SIZE;
|
||||
h->heap=malloc(sizeof(void *)*h->heapsize);
|
||||
if (!h->heap) { free(h); return NULL; }
|
||||
h->heapcount=0;
|
||||
h->cf=cf;
|
||||
return (Heap)h;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,19 @@
|
|||
* See the README file for information on usage and redistribution.
|
||||
*/
|
||||
|
||||
#ifndef __HEAP_H__
|
||||
#define __HEAP_H__
|
||||
#ifndef __QUANTHEAP_H__
|
||||
#define __QUANTHEAP_H__
|
||||
|
||||
#include "QuantTypes.h"
|
||||
|
||||
void ImagingQuantHeapFree(Heap);
|
||||
int ImagingQuantHeapRemove(Heap,void **);
|
||||
int ImagingQuantHeapAdd(Heap,void *);
|
||||
int ImagingQuantHeapTop(Heap,void **);
|
||||
typedef struct _Heap Heap;
|
||||
|
||||
typedef int (*HeapCmpFunc)(const Heap *,const void *,const void *);
|
||||
|
||||
void ImagingQuantHeapFree(Heap *);
|
||||
int ImagingQuantHeapRemove(Heap *,void **);
|
||||
int ImagingQuantHeapAdd(Heap *,void *);
|
||||
int ImagingQuantHeapTop(Heap *,void **);
|
||||
Heap *ImagingQuantHeapNew(HeapCmpFunc);
|
||||
|
||||
#endif
|
||||
#endif // __QUANTHEAP_H__
|
||||
|
|
|
@ -27,15 +27,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Quant.h"
|
||||
#include "QuantOctree.h"
|
||||
|
||||
typedef struct _ColorBucket{
|
||||
/* contains palette index when used for look up cube */
|
||||
unsigned long count;
|
||||
unsigned long r;
|
||||
unsigned long g;
|
||||
unsigned long b;
|
||||
unsigned long a;
|
||||
uint32_t count;
|
||||
uint32_t r;
|
||||
uint32_t g;
|
||||
uint32_t b;
|
||||
uint32_t a;
|
||||
} *ColorBucket;
|
||||
|
||||
typedef struct _ColorCube{
|
||||
|
@ -262,7 +262,7 @@ set_lookup_value(const ColorCube cube, const Pixel *p, long value) {
|
|||
bucket->count = value;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
uint32_t
|
||||
lookup_color(const ColorCube cube, const Pixel *p) {
|
||||
ColorBucket bucket = color_bucket_from_cube(cube, p);
|
||||
return bucket->count;
|
||||
|
@ -302,9 +302,9 @@ create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
|
|||
|
||||
static void
|
||||
map_image_pixels(const Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
uint32_t nPixels,
|
||||
const ColorCube lookupCube,
|
||||
unsigned long *pixelArray)
|
||||
uint32_t *pixelArray)
|
||||
{
|
||||
long 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};
|
||||
|
||||
int quantize_octree(Pixel *pixelData,
|
||||
unsigned long nPixels,
|
||||
unsigned long nQuantPixels,
|
||||
uint32_t nPixels,
|
||||
uint32_t nQuantPixels,
|
||||
Pixel **palette,
|
||||
unsigned long *paletteLength,
|
||||
unsigned long **quantizedPixels,
|
||||
uint32_t *paletteLength,
|
||||
uint32_t **quantizedPixels,
|
||||
int withAlpha)
|
||||
{
|
||||
ColorCube fineCube = NULL;
|
||||
|
@ -330,7 +330,7 @@ int quantize_octree(Pixel *pixelData,
|
|||
ColorBucket paletteBucketsCoarse = NULL;
|
||||
ColorBucket paletteBucketsFine = NULL;
|
||||
ColorBucket paletteBuckets = NULL;
|
||||
unsigned long *qp = NULL;
|
||||
uint32_t *qp = NULL;
|
||||
long i;
|
||||
long nCoarseColors, nFineColors, nAlreadySubtracted;
|
||||
const int *cubeBits;
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#ifndef __QUANT_OCTREE_H__
|
||||
#define __QUANT_OCTREE_H__
|
||||
|
||||
#include "QuantTypes.h"
|
||||
|
||||
int quantize_octree(Pixel *,
|
||||
unsigned long,
|
||||
unsigned long,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
Pixel **,
|
||||
unsigned long *,
|
||||
unsigned long **,
|
||||
uint32_t *,
|
||||
uint32_t **,
|
||||
int);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -12,17 +12,20 @@
|
|||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
typedef void *HashTable;
|
||||
typedef void *Heap;
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned long (*HashFunc)(const HashTable,const void *);
|
||||
typedef int (*HashCmpFunc)(const HashTable,const void *,const void *);
|
||||
typedef void (*IteratorFunc)(const HashTable,const void *,const void *,void *);
|
||||
typedef void (*IteratorUpdateFunc)(const HashTable,const void *,void **,void *);
|
||||
typedef void (*DestroyFunc)(const HashTable,void *);
|
||||
typedef void (*ComputeFunc)(const HashTable,const void *,void **);
|
||||
typedef void (*CollisionFunc)(const HashTable,void **,void **,void *,void *);
|
||||
|
||||
typedef int (*HeapCmpFunc)(const Heap,const void *,const void *);
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned char r,g,b,a;
|
||||
} c;
|
||||
struct {
|
||||
unsigned char v[4];
|
||||
} a;
|
||||
uint32_t v;
|
||||
} Pixel;
|
||||
|
||||
#endif
|
||||
|
|
2
setup.py
2
setup.py
|
@ -453,8 +453,6 @@ class pil_build_ext(build_ext):
|
|||
tmpfile = os.path.join(self.build_temp, 'multiarch')
|
||||
if not os.path.exists(self.build_temp):
|
||||
os.makedirs(self.build_temp)
|
||||
ret = os.system('dpkg-architecture -qDEB_HOST_MULTIARCH > %s' %
|
||||
tmpfile)
|
||||
ret = os.system(
|
||||
'dpkg-architecture -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
|
||||
tmpfile)
|
||||
|
|
Loading…
Reference in New Issue
Block a user