12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742 |
- /*
- * The Python Imaging Library
- * $Id$
- *
- * convert images
- *
- * history:
- * 1995-06-15 fl created
- * 1995-11-28 fl added some "RGBA" and "CMYK" conversions
- * 1996-04-22 fl added "1" conversions (same as "L")
- * 1996-05-05 fl added palette conversions (hack)
- * 1996-07-23 fl fixed "1" conversions to zero/non-zero convention
- * 1996-11-01 fl fixed "P" to "L" and "RGB" to "1" conversions
- * 1996-12-29 fl set alpha byte in RGB converters
- * 1997-05-12 fl added ImagingConvert2
- * 1997-05-30 fl added floating point support
- * 1997-08-27 fl added "P" to "1" and "P" to "F" conversions
- * 1998-01-11 fl added integer support
- * 1998-07-01 fl added "YCbCr" support
- * 1998-07-02 fl added "RGBX" conversions (sort of)
- * 1998-07-04 fl added floyd-steinberg dithering
- * 1998-07-12 fl changed "YCrCb" to "YCbCr" (!)
- * 1998-12-29 fl added basic "I;16" and "I;16B" conversions
- * 1999-02-03 fl added "RGBa", and "BGR" conversions (experimental)
- * 2003-09-26 fl added "LA" and "PA" conversions (experimental)
- * 2005-05-05 fl fixed "P" to "1" threshold
- * 2005-12-08 fl fixed palette memory leak in topalette
- *
- * Copyright (c) 1997-2005 by Secret Labs AB.
- * Copyright (c) 1995-1997 by Fredrik Lundh.
- *
- * See the README file for details on usage and redistribution.
- */
- #include "Imaging.h"
- #define MAX(a, b) (a) > (b) ? (a) : (b)
- #define MIN(a, b) (a) < (b) ? (a) : (b)
- #define CLIP16(v) ((v) <= 0 ? 0 : (v) >= 65535 ? 65535 : (v))
- /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
- #define L(rgb) ((INT32)(rgb)[0] * 299 + (INT32)(rgb)[1] * 587 + (INT32)(rgb)[2] * 114)
- #define L24(rgb) ((rgb)[0] * 19595 + (rgb)[1] * 38470 + (rgb)[2] * 7471 + 0x8000)
- /* ------------------- */
- /* 1 (bit) conversions */
- /* ------------------- */
- static void
- bit2l(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) *out++ = (*in++ != 0) ? 255 : 0;
- }
- static void
- bit2rgb(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- UINT8 v = (*in++ != 0) ? 255 : 0;
- *out++ = v;
- *out++ = v;
- *out++ = v;
- *out++ = 255;
- }
- }
- static void
- bit2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = 0;
- *out++ = 0;
- *out++ = 0;
- *out++ = (*in++ != 0) ? 0 : 255;
- }
- }
- static void
- bit2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = (*in++ != 0) ? 255 : 0;
- *out++ = 128;
- *out++ = 128;
- *out++ = 255;
- }
- }
- static void
- bit2hsv(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out += 4) {
- UINT8 v = (*in++ != 0) ? 255 : 0;
- out[0] = 0;
- out[1] = 0;
- out[2] = v;
- out[3] = 255;
- }
- }
- /* ----------------- */
- /* RGB/L conversions */
- /* ----------------- */
- static void
- l2bit(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = (*in++ >= 128) ? 255 : 0;
- }
- }
- static void
- lA2la(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- unsigned int alpha, pixel, tmp;
- for (x = 0; x < xsize; x++, in += 4) {
- alpha = in[3];
- pixel = MULDIV255(in[0], alpha, tmp);
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)alpha;
- }
- }
- /* RGBa -> RGBA conversion to remove premultiplication
- Needed for correct transforms/resizing on RGBA images */
- static void
- la2lA(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- unsigned int alpha, pixel;
- for (x = 0; x < xsize; x++, in += 4) {
- alpha = in[3];
- if (alpha == 255 || alpha == 0) {
- pixel = in[0];
- } else {
- pixel = CLIP8((255 * in[0]) / alpha);
- }
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)pixel;
- *out++ = (UINT8)alpha;
- }
- }
- static void
- l2la(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- UINT8 v = *in++;
- *out++ = v;
- *out++ = v;
- *out++ = v;
- *out++ = 255;
- }
- }
- static void
- l2rgb(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- UINT8 v = *in++;
- *out++ = v;
- *out++ = v;
- *out++ = v;
- *out++ = 255;
- }
- }
- static void
- l2hsv(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out += 4) {
- UINT8 v = *in++;
- out[0] = 0;
- out[1] = 0;
- out[2] = v;
- out[3] = 255;
- }
- }
- static void
- la2l(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = in[0];
- }
- }
- static void
- la2rgb(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- UINT8 v = in[0];
- *out++ = v;
- *out++ = v;
- *out++ = v;
- *out++ = in[3];
- }
- }
- static void
- la2hsv(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- UINT8 v = in[0];
- out[0] = 0;
- out[1] = 0;
- out[2] = v;
- out[3] = in[3];
- }
- }
- static void
- rgb2bit(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
- *out++ = (L(in) >= 128000) ? 255 : 0;
- }
- }
- static void
- rgb2l(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
- *out++ = L24(in) >> 16;
- }
- }
- static void
- rgb2la(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
- out[0] = out[1] = out[2] = L24(in) >> 16;
- out[3] = 255;
- }
- }
- static void
- rgb2i(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
- INT32 v = L24(in) >> 16;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- rgb2f(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
- FLOAT32 v = (float)L(in) / 1000.0F;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- rgb2bgr15(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
- UINT16 v = ((((UINT16)in[0]) << 7) & 0x7c00) +
- ((((UINT16)in[1]) << 2) & 0x03e0) +
- ((((UINT16)in[2]) >> 3) & 0x001f);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- rgb2bgr16(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
- UINT16 v = ((((UINT16)in[0]) << 8) & 0xf800) +
- ((((UINT16)in[1]) << 3) & 0x07e0) +
- ((((UINT16)in[2]) >> 3) & 0x001f);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- rgb2bgr24(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = in[2];
- *out++ = in[1];
- *out++ = in[0];
- }
- }
- static void
- rgb2hsv_row(UINT8 *out, const UINT8 *in) { // following colorsys.py
- float h, s, rc, gc, bc, cr;
- UINT8 maxc, minc;
- UINT8 r, g, b;
- UINT8 uh, us, uv;
- r = in[0];
- g = in[1];
- b = in[2];
- maxc = MAX(r, MAX(g, b));
- minc = MIN(r, MIN(g, b));
- uv = maxc;
- if (minc == maxc) {
- uh = 0;
- us = 0;
- } else {
- cr = (float)(maxc - minc);
- s = cr / (float)maxc;
- rc = ((float)(maxc - r)) / cr;
- gc = ((float)(maxc - g)) / cr;
- bc = ((float)(maxc - b)) / cr;
- if (r == maxc) {
- h = bc - gc;
- } else if (g == maxc) {
- h = 2.0 + rc - bc;
- } else {
- h = 4.0 + gc - rc;
- }
- // incorrect hue happens if h/6 is negative.
- h = fmod((h / 6.0 + 1.0), 1.0);
- uh = (UINT8)CLIP8((int)(h * 255.0));
- us = (UINT8)CLIP8((int)(s * 255.0));
- }
- out[0] = uh;
- out[1] = us;
- out[2] = uv;
- }
- static void
- rgb2hsv(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- rgb2hsv_row(out, in);
- out[3] = in[3];
- }
- }
- static void
- hsv2rgb(UINT8 *out, const UINT8 *in, int xsize) { // following colorsys.py
- int p, q, t;
- UINT8 up, uq, ut;
- int i, x;
- float f, fs;
- UINT8 h, s, v;
- for (x = 0; x < xsize; x++, in += 4) {
- h = in[0];
- s = in[1];
- v = in[2];
- if (s == 0) {
- *out++ = v;
- *out++ = v;
- *out++ = v;
- } else {
- i = floor((float)h * 6.0 / 255.0); // 0 - 6
- f = (float)h * 6.0 / 255.0 - (float)i; // 0-1 : remainder.
- fs = ((float)s) / 255.0;
- p = round((float)v * (1.0 - fs));
- q = round((float)v * (1.0 - fs * f));
- t = round((float)v * (1.0 - fs * (1.0 - f)));
- up = (UINT8)CLIP8(p);
- uq = (UINT8)CLIP8(q);
- ut = (UINT8)CLIP8(t);
- switch (i % 6) {
- case 0:
- *out++ = v;
- *out++ = ut;
- *out++ = up;
- break;
- case 1:
- *out++ = uq;
- *out++ = v;
- *out++ = up;
- break;
- case 2:
- *out++ = up;
- *out++ = v;
- *out++ = ut;
- break;
- case 3:
- *out++ = up;
- *out++ = uq;
- *out++ = v;
- break;
- case 4:
- *out++ = ut;
- *out++ = up;
- *out++ = v;
- break;
- case 5:
- *out++ = v;
- *out++ = up;
- *out++ = uq;
- break;
- }
- }
- *out++ = in[3];
- }
- }
- /* ---------------- */
- /* RGBA conversions */
- /* ---------------- */
- static void
- rgb2rgba(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = *in++;
- *out++ = *in++;
- *out++ = *in++;
- *out++ = 255;
- in++;
- }
- }
- static void
- rgba2la(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
- out[0] = out[1] = out[2] = L24(in) >> 16;
- out[3] = in[3];
- }
- }
- static void
- rgba2rgb(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = *in++;
- *out++ = *in++;
- *out++ = *in++;
- *out++ = 255;
- in++;
- }
- }
- static void
- rgbA2rgba(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- unsigned int alpha, tmp;
- for (x = 0; x < xsize; x++) {
- alpha = in[3];
- *out++ = MULDIV255(*in++, alpha, tmp);
- *out++ = MULDIV255(*in++, alpha, tmp);
- *out++ = MULDIV255(*in++, alpha, tmp);
- *out++ = *in++;
- }
- }
- /* RGBa -> RGBA conversion to remove premultiplication
- Needed for correct transforms/resizing on RGBA images */
- static void
- rgba2rgbA(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- unsigned int alpha;
- for (x = 0; x < xsize; x++, in += 4) {
- alpha = in[3];
- if (alpha == 255 || alpha == 0) {
- *out++ = in[0];
- *out++ = in[1];
- *out++ = in[2];
- } else {
- *out++ = CLIP8((255 * in[0]) / alpha);
- *out++ = CLIP8((255 * in[1]) / alpha);
- *out++ = CLIP8((255 * in[2]) / alpha);
- }
- *out++ = in[3];
- }
- }
- static void
- rgba2rgb_(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- unsigned int alpha;
- for (x = 0; x < xsize; x++, in += 4) {
- alpha = in[3];
- if (alpha == 255 || alpha == 0) {
- *out++ = in[0];
- *out++ = in[1];
- *out++ = in[2];
- } else {
- *out++ = CLIP8((255 * in[0]) / alpha);
- *out++ = CLIP8((255 * in[1]) / alpha);
- *out++ = CLIP8((255 * in[2]) / alpha);
- }
- *out++ = 255;
- }
- }
- /*
- * Conversion of RGB + single transparent color to RGBA,
- * where any pixel that matches the color will have the
- * alpha channel set to 0
- */
- static void
- rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b) {
- #ifdef WORDS_BIGENDIAN
- UINT32 trns = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | 0xff;
- UINT32 repl = trns & 0xffffff00;
- #else
- UINT32 trns = (0xff << 24) | ((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff);
- UINT32 repl = trns & 0x00ffffff;
- #endif
- int i;
- for (i = 0; i < xsize; i++, out += sizeof(trns)) {
- UINT32 v;
- memcpy(&v, out, sizeof(v));
- if (v == trns) {
- memcpy(out, &repl, sizeof(repl));
- }
- }
- }
- /* ---------------- */
- /* CMYK conversions */
- /* ---------------- */
- static void
- l2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = 0;
- *out++ = 0;
- *out++ = 0;
- *out++ = ~(*in++);
- }
- }
- static void
- la2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = 0;
- *out++ = 0;
- *out++ = 0;
- *out++ = ~(in[0]);
- }
- }
- static void
- rgb2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- /* Note: no undercolour removal */
- *out++ = ~(*in++);
- *out++ = ~(*in++);
- *out++ = ~(*in++);
- *out++ = 0;
- in++;
- }
- }
- void
- cmyk2rgb(UINT8 *out, const UINT8 *in, int xsize) {
- int x, nk, tmp;
- for (x = 0; x < xsize; x++) {
- nk = 255 - in[3];
- out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
- out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
- out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
- out[3] = 255;
- out += 4;
- in += 4;
- }
- }
- static void
- cmyk2hsv(UINT8 *out, const UINT8 *in, int xsize) {
- int x, nk, tmp;
- for (x = 0; x < xsize; x++) {
- nk = 255 - in[3];
- out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
- out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
- out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
- rgb2hsv_row(out, out);
- out[3] = 255;
- out += 4;
- in += 4;
- }
- }
- /* ------------- */
- /* I conversions */
- /* ------------- */
- static void
- bit2i(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- INT32 v = (*in++ != 0) ? 255 : 0;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- l2i(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- INT32 v = *in++;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- i2l(UINT8 *out, const UINT8 *in_, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out++, in_ += 4) {
- INT32 v;
- memcpy(&v, in_, sizeof(v));
- if (v <= 0) {
- *out = 0;
- } else if (v >= 255) {
- *out = 255;
- } else {
- *out = (UINT8)v;
- }
- }
- }
- static void
- i2f(UINT8 *out_, const UINT8 *in_, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
- INT32 i;
- FLOAT32 f;
- memcpy(&i, in_, sizeof(i));
- f = i;
- memcpy(out_, &f, sizeof(f));
- }
- }
- static void
- i2rgb(UINT8 *out, const UINT8 *in_, int xsize) {
- int x;
- INT32 *in = (INT32 *)in_;
- for (x = 0; x < xsize; x++, in++, out += 4) {
- if (*in <= 0) {
- out[0] = out[1] = out[2] = 0;
- } else if (*in >= 255) {
- out[0] = out[1] = out[2] = 255;
- } else {
- out[0] = out[1] = out[2] = (UINT8)*in;
- }
- out[3] = 255;
- }
- }
- static void
- i2hsv(UINT8 *out, const UINT8 *in_, int xsize) {
- int x;
- INT32 *in = (INT32 *)in_;
- for (x = 0; x < xsize; x++, in++, out += 4) {
- out[0] = 0;
- out[1] = 0;
- if (*in <= 0) {
- out[2] = 0;
- } else if (*in >= 255) {
- out[2] = 255;
- } else {
- out[2] = (UINT8)*in;
- }
- out[3] = 255;
- }
- }
- /* ------------- */
- /* F conversions */
- /* ------------- */
- static void
- bit2f(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- FLOAT32 f = (*in++ != 0) ? 255.0F : 0.0F;
- memcpy(out_, &f, sizeof(f));
- }
- }
- static void
- l2f(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- FLOAT32 f = (FLOAT32)*in++;
- memcpy(out_, &f, sizeof(f));
- }
- }
- static void
- f2l(UINT8 *out, const UINT8 *in_, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, out++, in_ += 4) {
- FLOAT32 v;
- memcpy(&v, in_, sizeof(v));
- if (v <= 0.0) {
- *out = 0;
- } else if (v >= 255.0) {
- *out = 255;
- } else {
- *out = (UINT8)v;
- }
- }
- }
- static void
- f2i(UINT8 *out_, const UINT8 *in_, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
- FLOAT32 f;
- INT32 i;
- memcpy(&f, in_, sizeof(f));
- i = f;
- memcpy(out_, &i, sizeof(i));
- }
- }
- /* ----------------- */
- /* YCbCr conversions */
- /* ----------------- */
- /* See ConvertYCbCr.c for RGB/YCbCr tables */
- static void
- l2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++) {
- *out++ = *in++;
- *out++ = 128;
- *out++ = 128;
- *out++ = 255;
- }
- }
- static void
- la2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = in[0];
- *out++ = 128;
- *out++ = 128;
- *out++ = 255;
- }
- }
- static void
- ycbcr2l(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = in[0];
- }
- }
- static void
- ycbcr2la(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- out[0] = out[1] = out[2] = in[0];
- out[3] = 255;
- }
- }
- /* ------------------------- */
- /* I;16 (16-bit) conversions */
- /* ------------------------- */
- static void
- I_I16L(UINT8 *out, const UINT8 *in_, int xsize) {
- int x, v;
- for (x = 0; x < xsize; x++, in_ += 4) {
- INT32 i;
- memcpy(&i, in_, sizeof(i));
- v = CLIP16(i);
- *out++ = (UINT8)v;
- *out++ = (UINT8)(v >> 8);
- }
- }
- static void
- I_I16B(UINT8 *out, const UINT8 *in_, int xsize) {
- int x, v;
- for (x = 0; x < xsize; x++, in_ += 4) {
- INT32 i;
- memcpy(&i, in_, sizeof(i));
- v = CLIP16(i);
- *out++ = (UINT8)(v >> 8);
- *out++ = (UINT8)v;
- }
- }
- static void
- I16L_I(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
- INT32 v = in[0] + ((int)in[1] << 8);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- I16B_I(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
- INT32 v = in[1] + ((int)in[0] << 8);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- I16L_F(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
- FLOAT32 v = in[0] + ((int)in[1] << 8);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- I16B_F(UINT8 *out_, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
- FLOAT32 v = in[1] + ((int)in[0] << 8);
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- L_I16L(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in++) {
- *out++ = *in;
- *out++ = 0;
- }
- }
- static void
- L_I16B(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in++) {
- *out++ = 0;
- *out++ = *in;
- }
- }
- static void
- I16L_L(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2) {
- if (in[1] != 0) {
- *out++ = 255;
- } else {
- *out++ = in[0];
- }
- }
- }
- static void
- I16B_L(UINT8 *out, const UINT8 *in, int xsize) {
- int x;
- for (x = 0; x < xsize; x++, in += 2) {
- if (in[0] != 0) {
- *out++ = 255;
- } else {
- *out++ = in[1];
- }
- }
- }
- static struct {
- const char *from;
- const char *to;
- ImagingShuffler convert;
- } converters[] = {
- {"1", "L", bit2l},
- {"1", "I", bit2i},
- {"1", "F", bit2f},
- {"1", "RGB", bit2rgb},
- {"1", "RGBA", bit2rgb},
- {"1", "RGBX", bit2rgb},
- {"1", "CMYK", bit2cmyk},
- {"1", "YCbCr", bit2ycbcr},
- {"1", "HSV", bit2hsv},
- {"L", "1", l2bit},
- {"L", "LA", l2la},
- {"L", "I", l2i},
- {"L", "F", l2f},
- {"L", "RGB", l2rgb},
- {"L", "RGBA", l2rgb},
- {"L", "RGBX", l2rgb},
- {"L", "CMYK", l2cmyk},
- {"L", "YCbCr", l2ycbcr},
- {"L", "HSV", l2hsv},
- {"LA", "L", la2l},
- {"LA", "La", lA2la},
- {"LA", "RGB", la2rgb},
- {"LA", "RGBA", la2rgb},
- {"LA", "RGBX", la2rgb},
- {"LA", "CMYK", la2cmyk},
- {"LA", "YCbCr", la2ycbcr},
- {"LA", "HSV", la2hsv},
- {"La", "LA", la2lA},
- {"I", "L", i2l},
- {"I", "F", i2f},
- {"I", "RGB", i2rgb},
- {"I", "RGBA", i2rgb},
- {"I", "RGBX", i2rgb},
- {"I", "HSV", i2hsv},
- {"F", "L", f2l},
- {"F", "I", f2i},
- {"RGB", "1", rgb2bit},
- {"RGB", "L", rgb2l},
- {"RGB", "LA", rgb2la},
- {"RGB", "I", rgb2i},
- {"RGB", "F", rgb2f},
- {"RGB", "BGR;15", rgb2bgr15},
- {"RGB", "BGR;16", rgb2bgr16},
- {"RGB", "BGR;24", rgb2bgr24},
- {"RGB", "RGBA", rgb2rgba},
- {"RGB", "RGBX", rgb2rgba},
- {"RGB", "CMYK", rgb2cmyk},
- {"RGB", "YCbCr", ImagingConvertRGB2YCbCr},
- {"RGB", "HSV", rgb2hsv},
- {"RGBA", "1", rgb2bit},
- {"RGBA", "L", rgb2l},
- {"RGBA", "LA", rgba2la},
- {"RGBA", "I", rgb2i},
- {"RGBA", "F", rgb2f},
- {"RGBA", "RGB", rgba2rgb},
- {"RGBA", "RGBa", rgbA2rgba},
- {"RGBA", "RGBX", rgb2rgba},
- {"RGBA", "CMYK", rgb2cmyk},
- {"RGBA", "YCbCr", ImagingConvertRGB2YCbCr},
- {"RGBA", "HSV", rgb2hsv},
- {"RGBa", "RGBA", rgba2rgbA},
- {"RGBa", "RGB", rgba2rgb_},
- {"RGBX", "1", rgb2bit},
- {"RGBX", "L", rgb2l},
- {"RGBX", "LA", rgb2la},
- {"RGBX", "I", rgb2i},
- {"RGBX", "F", rgb2f},
- {"RGBX", "RGB", rgba2rgb},
- {"RGBX", "CMYK", rgb2cmyk},
- {"RGBX", "YCbCr", ImagingConvertRGB2YCbCr},
- {"RGBX", "HSV", rgb2hsv},
- {"CMYK", "RGB", cmyk2rgb},
- {"CMYK", "RGBA", cmyk2rgb},
- {"CMYK", "RGBX", cmyk2rgb},
- {"CMYK", "HSV", cmyk2hsv},
- {"YCbCr", "L", ycbcr2l},
- {"YCbCr", "LA", ycbcr2la},
- {"YCbCr", "RGB", ImagingConvertYCbCr2RGB},
- {"HSV", "RGB", hsv2rgb},
- {"I", "I;16", I_I16L},
- {"I;16", "I", I16L_I},
- {"L", "I;16", L_I16L},
- {"I;16", "L", I16L_L},
- {"I", "I;16L", I_I16L},
- {"I;16L", "I", I16L_I},
- {"I", "I;16B", I_I16B},
- {"I;16B", "I", I16B_I},
- {"L", "I;16L", L_I16L},
- {"I;16L", "L", I16L_L},
- {"L", "I;16B", L_I16B},
- {"I;16B", "L", I16B_L},
- #ifdef WORDS_BIGENDIAN
- {"L", "I;16N", L_I16B},
- {"I;16N", "L", I16B_L},
- #else
- {"L", "I;16N", L_I16L},
- {"I;16N", "L", I16L_L},
- #endif
- {"I;16", "F", I16L_F},
- {"I;16L", "F", I16L_F},
- {"I;16B", "F", I16B_F},
- {NULL}};
- /* FIXME: translate indexed versions to pointer versions below this line */
- /* ------------------- */
- /* Palette conversions */
- /* ------------------- */
- static void
- p2bit(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++) {
- *out++ = (L(&palette->palette[in[x] * 4]) >= 128000) ? 255 : 0;
- }
- }
- static void
- pa2bit(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = (L(&palette->palette[in[0] * 4]) >= 128000) ? 255 : 0;
- }
- }
- static void
- p2l(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++) {
- *out++ = L24(&palette->palette[in[x] * 4]) >> 16;
- }
- }
- static void
- pa2l(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = L24(&palette->palette[in[0] * 4]) >> 16;
- }
- }
- static void
- pa2p(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = in[0];
- }
- }
- static void
- p2pa(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- int rgb = strcmp(palette->mode, "RGB");
- for (x = 0; x < xsize; x++, in++) {
- const UINT8 *rgba = &palette->palette[in[0] * 4];
- *out++ = in[0];
- *out++ = in[0];
- *out++ = in[0];
- *out++ = rgb == 0 ? 255 : rgba[3];
- }
- }
- static void
- p2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++, out += 4) {
- const UINT8 *rgba = &palette->palette[*in++ * 4];
- out[0] = out[1] = out[2] = L24(rgba) >> 16;
- out[3] = rgba[3];
- }
- }
- static void
- pa2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- /* FIXME: precalculate grayscale palette? */
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- out[0] = out[1] = out[2] = L24(&palette->palette[in[0] * 4]) >> 16;
- out[3] = in[3];
- }
- }
- static void
- p2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- INT32 v = L24(&palette->palette[in[x] * 4]) >> 16;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- pa2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- INT32 *out = (INT32 *)out_;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = L24(&palette->palette[in[0] * 4]) >> 16;
- }
- }
- static void
- p2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- FLOAT32 v = L(&palette->palette[in[x] * 4]) / 1000.0F;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- pa2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- FLOAT32 *out = (FLOAT32 *)out_;
- for (x = 0; x < xsize; x++, in += 4) {
- *out++ = (float)L(&palette->palette[in[0] * 4]) / 1000.0F;
- }
- }
- static void
- p2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++) {
- const UINT8 *rgb = &palette->palette[*in++ * 4];
- *out++ = rgb[0];
- *out++ = rgb[1];
- *out++ = rgb[2];
- *out++ = 255;
- }
- }
- static void
- pa2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- const UINT8 *rgb = &palette->palette[in[0] * 4];
- *out++ = rgb[0];
- *out++ = rgb[1];
- *out++ = rgb[2];
- *out++ = 255;
- }
- }
- static void
- p2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, out += 4) {
- const UINT8 *rgb = &palette->palette[*in++ * 4];
- rgb2hsv_row(out, rgb);
- out[3] = 255;
- }
- }
- static void
- pa2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- const UINT8 *rgb = &palette->palette[in[0] * 4];
- rgb2hsv_row(out, rgb);
- out[3] = 255;
- }
- }
- static void
- p2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++) {
- const UINT8 *rgba = &palette->palette[*in++ * 4];
- *out++ = rgba[0];
- *out++ = rgba[1];
- *out++ = rgba[2];
- *out++ = rgba[3];
- }
- }
- static void
- pa2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- const UINT8 *rgb = &palette->palette[in[0] * 4];
- *out++ = rgb[0];
- *out++ = rgb[1];
- *out++ = rgb[2];
- *out++ = in[3];
- }
- }
- static void
- p2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- p2rgb(out, in, xsize, palette);
- rgb2cmyk(out, out, xsize);
- }
- static void
- pa2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- pa2rgb(out, in, xsize, palette);
- rgb2cmyk(out, out, xsize);
- }
- static void
- p2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- p2rgb(out, in, xsize, palette);
- ImagingConvertRGB2YCbCr(out, out, xsize);
- }
- static void
- pa2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
- pa2rgb(out, in, xsize, palette);
- ImagingConvertRGB2YCbCr(out, out, xsize);
- }
- static Imaging
- frompalette(Imaging imOut, Imaging imIn, const char *mode) {
- ImagingSectionCookie cookie;
- int alpha;
- int y;
- void (*convert)(UINT8 *, const UINT8 *, int, ImagingPalette);
- /* Map palette image to L, RGB, RGBA, or CMYK */
- if (!imIn->palette) {
- return (Imaging)ImagingError_ValueError("no palette");
- }
- alpha = !strcmp(imIn->mode, "PA");
- if (strcmp(mode, "1") == 0) {
- convert = alpha ? pa2bit : p2bit;
- } else if (strcmp(mode, "L") == 0) {
- convert = alpha ? pa2l : p2l;
- } else if (strcmp(mode, "LA") == 0) {
- convert = alpha ? pa2la : p2la;
- } else if (strcmp(mode, "P") == 0) {
- convert = pa2p;
- } else if (strcmp(mode, "PA") == 0) {
- convert = p2pa;
- } else if (strcmp(mode, "I") == 0) {
- convert = alpha ? pa2i : p2i;
- } else if (strcmp(mode, "F") == 0) {
- convert = alpha ? pa2f : p2f;
- } else if (strcmp(mode, "RGB") == 0) {
- convert = alpha ? pa2rgb : p2rgb;
- } else if (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBX") == 0) {
- convert = alpha ? pa2rgba : p2rgba;
- } else if (strcmp(mode, "CMYK") == 0) {
- convert = alpha ? pa2cmyk : p2cmyk;
- } else if (strcmp(mode, "YCbCr") == 0) {
- convert = alpha ? pa2ycbcr : p2ycbcr;
- } else if (strcmp(mode, "HSV") == 0) {
- convert = alpha ? pa2hsv : p2hsv;
- } else {
- return (Imaging)ImagingError_ValueError("conversion not supported");
- }
- imOut = ImagingNew2Dirty(mode, imOut, imIn);
- if (!imOut) {
- return NULL;
- }
- if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
- ImagingPaletteDelete(imOut->palette);
- imOut->palette = ImagingPaletteDuplicate(imIn->palette);
- }
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- (*convert)(
- (UINT8 *)imOut->image[y],
- (UINT8 *)imIn->image[y],
- imIn->xsize,
- imIn->palette);
- }
- ImagingSectionLeave(&cookie);
- return imOut;
- }
- #if defined(_MSC_VER)
- #pragma optimize("", off)
- #endif
- static Imaging
- topalette(
- Imaging imOut,
- Imaging imIn,
- const char *mode,
- ImagingPalette inpalette,
- int dither) {
- ImagingSectionCookie cookie;
- int alpha;
- int x, y;
- ImagingPalette palette = inpalette;
- /* Map L or RGB/RGBX/RGBA to palette image */
- if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) {
- return (Imaging)ImagingError_ValueError("conversion not supported");
- }
- alpha = !strcmp(mode, "PA");
- if (palette == NULL) {
- /* FIXME: make user configurable */
- if (imIn->bands == 1) {
- palette = ImagingPaletteNew("RGB");
- palette->size = 256;
- int i;
- for (i = 0; i < 256; i++) {
- palette->palette[i * 4] = palette->palette[i * 4 + 1] =
- palette->palette[i * 4 + 2] = (UINT8)i;
- }
- } else {
- palette = ImagingPaletteNewBrowser(); /* Standard colour cube */
- }
- }
- if (!palette) {
- return (Imaging)ImagingError_ValueError("no palette");
- }
- imOut = ImagingNew2Dirty(mode, imOut, imIn);
- if (!imOut) {
- if (palette != inpalette) {
- ImagingPaletteDelete(palette);
- }
- return NULL;
- }
- ImagingPaletteDelete(imOut->palette);
- imOut->palette = ImagingPaletteDuplicate(palette);
- if (imIn->bands == 1) {
- /* grayscale image */
- /* Grayscale palette: copy data as is */
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- if (alpha) {
- l2la((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
- } else {
- memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
- }
- }
- ImagingSectionLeave(&cookie);
- } else {
- /* colour image */
- /* Create mapping cache */
- if (ImagingPaletteCachePrepare(palette) < 0) {
- ImagingDelete(imOut);
- if (palette != inpalette) {
- ImagingPaletteDelete(palette);
- }
- return NULL;
- }
- if (dither) {
- /* floyd-steinberg dither */
- int *errors;
- errors = calloc(imIn->xsize + 1, sizeof(int) * 3);
- if (!errors) {
- ImagingDelete(imOut);
- return ImagingError_MemoryError();
- }
- /* Map each pixel to the nearest palette entry */
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- int r, r0, r1, r2;
- int g, g0, g1, g2;
- int b, b0, b1, b2;
- UINT8 *in = (UINT8 *)imIn->image[y];
- UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];
- int *e = errors;
- r = r0 = r1 = 0;
- g = g0 = g1 = 0;
- b = b0 = b1 = b2 = 0;
- for (x = 0; x < imIn->xsize; x++, in += 4) {
- int d2;
- INT16 *cache;
- r = CLIP8(in[0] + (r + e[3 + 0]) / 16);
- g = CLIP8(in[1] + (g + e[3 + 1]) / 16);
- b = CLIP8(in[2] + (b + e[3 + 2]) / 16);
- /* get closest colour */
- cache = &ImagingPaletteCache(palette, r, g, b);
- if (cache[0] == 0x100) {
- ImagingPaletteCacheUpdate(palette, r, g, b);
- }
- if (alpha) {
- out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
- out[x * 4 + 3] = 255;
- } else {
- out[x] = (UINT8)cache[0];
- }
- r -= (int)palette->palette[cache[0] * 4];
- g -= (int)palette->palette[cache[0] * 4 + 1];
- b -= (int)palette->palette[cache[0] * 4 + 2];
- /* propagate errors (don't ask ;-) */
- r2 = r;
- d2 = r + r;
- r += d2;
- e[0] = r + r0;
- r += d2;
- r0 = r + r1;
- r1 = r2;
- r += d2;
- g2 = g;
- d2 = g + g;
- g += d2;
- e[1] = g + g0;
- g += d2;
- g0 = g + g1;
- g1 = g2;
- g += d2;
- b2 = b;
- d2 = b + b;
- b += d2;
- e[2] = b + b0;
- b += d2;
- b0 = b + b1;
- b1 = b2;
- b += d2;
- e += 3;
- }
- e[0] = b0;
- e[1] = b1;
- e[2] = b2;
- }
- ImagingSectionLeave(&cookie);
- free(errors);
- } else {
- /* closest colour */
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- int r, g, b;
- UINT8 *in = (UINT8 *)imIn->image[y];
- UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];
- for (x = 0; x < imIn->xsize; x++, in += 4) {
- INT16 *cache;
- r = in[0];
- g = in[1];
- b = in[2];
- /* get closest colour */
- cache = &ImagingPaletteCache(palette, r, g, b);
- if (cache[0] == 0x100) {
- ImagingPaletteCacheUpdate(palette, r, g, b);
- }
- if (alpha) {
- out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
- out[x * 4 + 3] = 255;
- } else {
- out[x] = (UINT8)cache[0];
- }
- }
- }
- ImagingSectionLeave(&cookie);
- }
- if (inpalette != palette) {
- ImagingPaletteCacheDelete(palette);
- }
- }
- if (inpalette != palette) {
- ImagingPaletteDelete(palette);
- }
- return imOut;
- }
- static Imaging
- tobilevel(Imaging imOut, Imaging imIn) {
- ImagingSectionCookie cookie;
- int x, y;
- int *errors;
- /* Map L or RGB to dithered 1 image */
- if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0) {
- return (Imaging)ImagingError_ValueError("conversion not supported");
- }
- imOut = ImagingNew2Dirty("1", imOut, imIn);
- if (!imOut) {
- return NULL;
- }
- errors = calloc(imIn->xsize + 1, sizeof(int));
- if (!errors) {
- ImagingDelete(imOut);
- return ImagingError_MemoryError();
- }
- if (imIn->bands == 1) {
- /* map each pixel to black or white, using error diffusion */
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- int l, l0, l1, l2, d2;
- UINT8 *in = (UINT8 *)imIn->image[y];
- UINT8 *out = imOut->image8[y];
- l = l0 = l1 = 0;
- for (x = 0; x < imIn->xsize; x++) {
- /* pick closest colour */
- l = CLIP8(in[x] + (l + errors[x + 1]) / 16);
- out[x] = (l > 128) ? 255 : 0;
- /* propagate errors */
- l -= (int)out[x];
- l2 = l;
- d2 = l + l;
- l += d2;
- errors[x] = l + l0;
- l += d2;
- l0 = l + l1;
- l1 = l2;
- l += d2;
- }
- errors[x] = l0;
- }
- ImagingSectionLeave(&cookie);
- } else {
- /* map each pixel to black or white, using error diffusion */
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- int l, l0, l1, l2, d2;
- UINT8 *in = (UINT8 *)imIn->image[y];
- UINT8 *out = imOut->image8[y];
- l = l0 = l1 = 0;
- for (x = 0; x < imIn->xsize; x++, in += 4) {
- /* pick closest colour */
- l = CLIP8(L(in) / 1000 + (l + errors[x + 1]) / 16);
- out[x] = (l > 128) ? 255 : 0;
- /* propagate errors */
- l -= (int)out[x];
- l2 = l;
- d2 = l + l;
- l += d2;
- errors[x] = l + l0;
- l += d2;
- l0 = l + l1;
- l1 = l2;
- l += d2;
- }
- errors[x] = l0;
- }
- ImagingSectionLeave(&cookie);
- }
- free(errors);
- return imOut;
- }
- #if defined(_MSC_VER)
- #pragma optimize("", on)
- #endif
- static Imaging
- convert(
- Imaging imOut, Imaging imIn, const char *mode, ImagingPalette palette, int dither) {
- ImagingSectionCookie cookie;
- ImagingShuffler convert;
- int y;
- if (!imIn) {
- return (Imaging)ImagingError_ModeError();
- }
- if (!mode) {
- /* Map palette image to full depth */
- if (!imIn->palette) {
- return (Imaging)ImagingError_ModeError();
- }
- mode = imIn->palette->mode;
- } else {
- /* Same mode? */
- if (!strcmp(imIn->mode, mode)) {
- return ImagingCopy2(imOut, imIn);
- }
- }
- /* test for special conversions */
- if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "PA") == 0) {
- return frompalette(imOut, imIn, mode);
- }
- if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
- return topalette(imOut, imIn, mode, palette, dither);
- }
- if (dither && strcmp(mode, "1") == 0) {
- return tobilevel(imOut, imIn);
- }
- /* standard conversion machinery */
- convert = NULL;
- for (y = 0; converters[y].from; y++) {
- if (!strcmp(imIn->mode, converters[y].from) &&
- !strcmp(mode, converters[y].to)) {
- convert = converters[y].convert;
- break;
- }
- }
- if (!convert) {
- #ifdef notdef
- return (Imaging)ImagingError_ValueError("conversion not supported");
- #else
- static char buf[100];
- snprintf(buf, 100, "conversion from %.10s to %.10s not supported", imIn->mode, mode);
- return (Imaging)ImagingError_ValueError(buf);
- #endif
- }
- imOut = ImagingNew2Dirty(mode, imOut, imIn);
- if (!imOut) {
- return NULL;
- }
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
- }
- ImagingSectionLeave(&cookie);
- return imOut;
- }
- Imaging
- ImagingConvert(Imaging imIn, const char *mode, ImagingPalette palette, int dither) {
- return convert(NULL, imIn, mode, palette, dither);
- }
- Imaging
- ImagingConvert2(Imaging imOut, Imaging imIn) {
- return convert(imOut, imIn, imOut->mode, NULL, 0);
- }
- Imaging
- ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
- ImagingSectionCookie cookie;
- ImagingShuffler convert;
- Imaging imOut = NULL;
- int y;
- if (!imIn) {
- return (Imaging)ImagingError_ModeError();
- }
- if (strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0) {
- convert = rgb2rgba;
- } else if ((strcmp(imIn->mode, "1") == 0 ||
- strcmp(imIn->mode, "I") == 0 ||
- strcmp(imIn->mode, "L") == 0
- ) && (
- strcmp(mode, "RGBA") == 0 ||
- strcmp(mode, "LA") == 0
- )) {
- if (strcmp(imIn->mode, "1") == 0) {
- convert = bit2rgb;
- } else if (strcmp(imIn->mode, "I") == 0) {
- convert = i2rgb;
- } else {
- convert = l2rgb;
- }
- g = b = r;
- } else {
- static char buf[100];
- snprintf(
- buf,
- 100,
- "conversion from %.10s to %.10s not supported in convert_transparent",
- imIn->mode,
- mode);
- return (Imaging)ImagingError_ValueError(buf);
- }
- imOut = ImagingNew2Dirty(mode, imOut, imIn);
- if (!imOut) {
- return NULL;
- }
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
- rgbT2rgba((UINT8 *)imOut->image[y], imIn->xsize, r, g, b);
- }
- ImagingSectionLeave(&cookie);
- return imOut;
- }
- Imaging
- ImagingConvertInPlace(Imaging imIn, const char *mode) {
- ImagingSectionCookie cookie;
- ImagingShuffler convert;
- int y;
- /* limited support for inplace conversion */
- if (strcmp(imIn->mode, "L") == 0 && strcmp(mode, "1") == 0) {
- convert = l2bit;
- } else if (strcmp(imIn->mode, "1") == 0 && strcmp(mode, "L") == 0) {
- convert = bit2l;
- } else {
- return ImagingError_ModeError();
- }
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++) {
- (*convert)((UINT8 *)imIn->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
- }
- ImagingSectionLeave(&cookie);
- return imIn;
- }
|