From 103cf49c910b62660b9c9f03b19484462aea4c7d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 31 Jan 2013 14:52:15 +0900 Subject: [PATCH 1/4] Fix rendered characters have been chipped for some TrueType fonts ImageFont ignores descender value of TrueType fonts (uses ascender only), then some fonts which use descender is chipped on rendering. --- _imagingft.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/_imagingft.c b/_imagingft.c index f54e38553..5dcd20e37 100644 --- a/_imagingft.c +++ b/_imagingft.c @@ -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; From 2a2a1ea144554cc17d141374e2d9223bfd2f5e07 Mon Sep 17 00:00:00 2001 From: Sandro Mani Date: Sun, 7 Apr 2013 19:02:11 +0200 Subject: [PATCH 2/4] Fix tests which are hardcoded for little-endian CPUs --- Tests/test_image_array.py | 4 ++-- Tests/test_lib_pack.py | 6 ++++-- Tests/test_mode_i16.py | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Tests/test_image_array.py b/Tests/test_image_array.py index c2e85903a..351621d3a 100644 --- a/Tests/test_image_array.py +++ b/Tests/test_image_array.py @@ -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), ' Date: Mon, 8 Apr 2013 00:52:15 +0200 Subject: [PATCH 3/4] Make quantization code more portable --- _imaging.c | 1 - libImaging/Quant.c | 395 ++++++++++++++++++-------------------- libImaging/Quant.h | 40 ---- libImaging/QuantDefines.h | 25 --- libImaging/QuantHash.c | 250 +++++++++++------------- libImaging/QuantHash.h | 55 ++++-- libImaging/QuantHeap.c | 49 ++--- libImaging/QuantHeap.h | 18 +- libImaging/QuantOctree.c | 28 +-- libImaging/QuantOctree.h | 12 +- libImaging/QuantTypes.h | 25 +-- 11 files changed, 405 insertions(+), 493 deletions(-) delete mode 100644 libImaging/Quant.h delete mode 100644 libImaging/QuantDefines.h diff --git a/_imaging.c b/_imaging.c index c9d3c8247..2ee7eef42 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1369,7 +1369,6 @@ _putdata(ImagingObject* self, PyObject* args) #ifdef WITH_QUANTIZE -#include "Quant.h" static PyObject* _quantize(ImagingObject* self, PyObject* args) { diff --git a/libImaging/Quant.c b/libImaging/Quant.c index ff15ac01f..7f328bda9 100644 --- a/libImaging/Quant.c +++ b/libImaging/Quant.c @@ -25,17 +25,15 @@ #include #include -#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:((Ascale=0; +#ifndef NO_OUTPUT timer=timer3=clock(); +#endif for (i=0;iscale++; #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=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 { - 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;inew),pixel); + uint32_t oldDist=*dist; + uint32_t newDist; + newDist=_DISTSQR(&(data->new),&pixel); if (data->secondPixel || newDistdata->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. - * - * 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 diff --git a/libImaging/QuantDefines.h b/libImaging/QuantDefines.h deleted file mode 100644 index 5b080104e..000000000 --- a/libImaging/QuantDefines.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * The Python Imaging Library - * $Id$ - * - * image quantizer - * - * Written by Toby J Sargeant . - * - * 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 diff --git a/libImaging/QuantHash.c b/libImaging/QuantHash.c index e6438402d..58d881349 100644 --- a/libImaging/QuantHash.c +++ b/libImaging/QuantHash.c @@ -22,35 +22,35 @@ #include #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;inext; @@ -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_FACTORlength) { @@ -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;ilength;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;xlength;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;xlength;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;ilength;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; diff --git a/libImaging/QuantHash.h b/libImaging/QuantHash.h index b98b56eaa..028b4af89 100644 --- a/libImaging/QuantHash.h +++ b/libImaging/QuantHash.h @@ -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__ diff --git a/libImaging/QuantHeap.c b/libImaging/QuantHeap.c index 9332a5cd7..bddcf142c 100644 --- a/libImaging/QuantHeap.c +++ b/libImaging/QuantHeap.c @@ -21,31 +21,29 @@ #include #include -#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 (newsizeheapsize) 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 (lheapcount) { - 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; } - diff --git a/libImaging/QuantHeap.h b/libImaging/QuantHeap.h index 5a213c42a..77bf0d9d5 100644 --- a/libImaging/QuantHeap.h +++ b/libImaging/QuantHeap.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__ diff --git a/libImaging/QuantOctree.c b/libImaging/QuantOctree.c index fcdf9e0b0..e841d6fbb 100644 --- a/libImaging/QuantOctree.c +++ b/libImaging/QuantOctree.c @@ -27,15 +27,15 @@ #include #include -#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 +#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 From 836e3e05d8644d4f65c44a1aa02d953762900615 Mon Sep 17 00:00:00 2001 From: David Schmidt Date: Tue, 9 Apr 2013 13:21:38 +0200 Subject: [PATCH 4/4] create a palette before converting transparent L-Mode to RGBA fixes #154 --- PIL/Image.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/PIL/Image.py b/PIL/Image.py index 1e29db198..cafc5a22f 100644 --- a/PIL/Image.py +++ b/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: