123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737 |
- /*
- * 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) <= -32768 ? -32768 : (v) >= 32767 ? 32767 : (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)
- /* ------------------- */
- /* 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];
- }
- }
- /*
- * 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++;
- }
- }
- static 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 },
- { "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 },
- { "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, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++)
- *out++ = (L(&palette[in[x]*4]) >= 128000) ? 255 : 0;
- }
- static void
- pa2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++, in += 4)
- *out++ = (L(&palette[in[0]*4]) >= 128000) ? 255 : 0;
- }
- static void
- p2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++)
- *out++ = L(&palette[in[x]*4]) / 1000;
- }
- static void
- pa2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++, in += 4)
- *out++ = L(&palette[in[0]*4]) / 1000;
- }
- static void
- p2pa(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, in++) {
- const UINT8* rgba = &palette[in[0]];
- *out++ = in[0];
- *out++ = in[0];
- *out++ = in[0];
- *out++ = rgba[3];
- }
- }
- static void
- p2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++, out+=4) {
- const UINT8* rgba = &palette[*in++ * 4];
- out[0] = out[1] = out[2] = L(rgba) / 1000;
- out[3] = rgba[3];
- }
- }
- static void
- pa2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- /* FIXME: precalculate greyscale palette? */
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- out[0] = out[1] = out[2] = L(&palette[in[0]*4]) / 1000;
- out[3] = in[3];
- }
- }
- static void
- p2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- INT32 v = L(&palette[in[x]*4]) / 1000;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- pa2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- INT32* out = (INT32*) out_;
- for (x = 0; x < xsize; x++, in += 4)
- *out++ = L(&palette[in[0]*4]) / 1000;
- }
- static void
- p2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, out_ += 4) {
- FLOAT32 v = L(&palette[in[x]*4]) / 1000.0F;
- memcpy(out_, &v, sizeof(v));
- }
- }
- static void
- pa2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- FLOAT32* out = (FLOAT32*) out_;
- for (x = 0; x < xsize; x++, in += 4)
- *out++ = (float) L(&palette[in[0]*4]) / 1000.0F;
- }
- static void
- p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++) {
- const UINT8* rgb = &palette[*in++ * 4];
- *out++ = rgb[0];
- *out++ = rgb[1];
- *out++ = rgb[2];
- *out++ = 255;
- }
- }
- static void
- pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- const UINT8* rgb = &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, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, out += 4) {
- const UINT8* rgb = &palette[*in++ * 4];
- rgb2hsv_row(out, rgb);
- out[3] = 255;
- }
- }
- static void
- pa2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, in += 4, out += 4) {
- const UINT8* rgb = &palette[in[0] * 4];
- rgb2hsv_row(out, rgb);
- out[3] = 255;
- }
- }
- static void
- p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++) {
- const UINT8* rgba = &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, const UINT8* palette)
- {
- int x;
- for (x = 0; x < xsize; x++, in += 4) {
- const UINT8* rgb = &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, const UINT8* palette)
- {
- p2rgb(out, in, xsize, palette);
- rgb2cmyk(out, out, xsize);
- }
- static void
- pa2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- pa2rgb(out, in, xsize, palette);
- rgb2cmyk(out, out, xsize);
- }
- static void
- p2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
- {
- p2rgb(out, in, xsize, palette);
- ImagingConvertRGB2YCbCr(out, out, xsize);
- }
- static void
- pa2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* 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, const UINT8*);
- /* 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, "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)
- convert = alpha ? pa2rgba : p2rgba;
- else if (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;
- ImagingSectionEnter(&cookie);
- for (y = 0; y < imIn->ysize; y++)
- (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y],
- imIn->xsize, imIn->palette->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"); /* Initialised to grey ramp */
- 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) {
- /* greyscale image */
- /* Greyscale 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, int dither)
- {
- 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, dither);
- /* 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[256];
- /* FIXME: may overflow if mode is too large */
- sprintf(buf, "conversion from %s to %s 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(imIn->mode, "1") == 0 ||
- strcmp(imIn->mode, "I") == 0 ||
- strcmp(imIn->mode, "L") == 0)
- && strcmp(mode, "RGBA") == 0))
- #ifdef notdef
- {
- return (Imaging) ImagingError_ValueError("conversion not supported");
- }
- #else
- {
- static char buf[256];
- /* FIXME: may overflow if mode is too large */
- sprintf(buf, "conversion from %s to %s not supported in convert_transparent", imIn->mode, mode);
- return (Imaging) ImagingError_ValueError(buf);
- }
- #endif
- if (strcmp(imIn->mode, "RGB") == 0) {
- convert = rgb2rgba;
- } else {
- if (strcmp(imIn->mode, "1") == 0) {
- convert = bit2rgb;
- } else if (strcmp(imIn->mode, "I") == 0) {
- convert = i2rgb;
- } else {
- convert = l2rgb;
- }
- g = b = r;
- }
- 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;
- }
|