00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "kxface.h"
00027
00028 #include <kdebug.h>
00029
00030 #include <qbuffer.h>
00031 #include <qcstring.h>
00032 #include <qimage.h>
00033 #include <qregexp.h>
00034 #include <qstring.h>
00035 #include <qpainter.h>
00036
00037 #include <stdlib.h>
00038 #include <string.h>
00039
00040 #define GEN(g) F[h] ^= G.g[k]; break
00041
00042 #define BITSPERDIG 4
00043 #define DIGITS (PIXELS / BITSPERDIG)
00044 #define DIGSPERWORD 4
00045 #define WORDSPERLINE (WIDTH / DIGSPERWORD / BITSPERDIG)
00046
00047
00048
00049
00050 #define FIRSTPRINT '!'
00051 #define LASTPRINT '~'
00052 #define NUMPRINTS (LASTPRINT - FIRSTPRINT + 1)
00053
00054
00055 #define MAXLINELEN 78
00056
00057
00058
00059
00060 #define COMP unsigned long
00061 #define WORDCARRY (1 << BITSPERWORD)
00062 #define WORDMASK (WORDCARRY - 1)
00063
00064 #define ERR_OK 0
00065 #define ERR_EXCESS 1
00066 #define ERR_INSUFF -1
00067 #define ERR_INTERNAL -2
00068
00069 #define BLACK 0
00070 #define GREY 1
00071 #define WHITE 2
00072
00073 #define MAX_XFACE_LENGTH 2048
00074
00075 using namespace KPIM;
00076
00077 KXFace::KXFace()
00078 {
00079 NumProbs = 0;
00080 }
00081
00082 KXFace::~KXFace()
00083 {
00084 }
00085
00086 QString KXFace::fromImage( const QImage &image )
00087 {
00088 if( image.isNull() )
00089 return QString::null;
00090
00091 QImage scaledImg = image.smoothScale( 48, 48 );
00092 QByteArray ba;
00093 QBuffer buffer( ba );
00094 buffer.open( IO_WriteOnly );
00095 scaledImg.save( &buffer, "XBM" );
00096 QString xbm( ba );
00097 xbm.remove( 0, xbm.find( "{" ) + 1 );
00098 xbm.truncate( xbm.find( "}" ) );
00099 xbm.remove( " " );
00100 xbm.remove( "," );
00101 xbm.remove( "0x" );
00102 xbm.remove( "\n" );
00103 xbm.truncate( 576 );
00104 QCString tmp = QCString( xbm.latin1() );
00105 uint len = tmp.length();
00106 for( uint i=0; i<len; ++i )
00107 {
00108 switch( tmp[i] )
00109 {
00110 case '1': tmp[i] = '8'; break;
00111 case '2': tmp[i] = '4'; break;
00112 case '3': tmp[i] = 'c'; break;
00113 case '4': tmp[i] = '2'; break;
00114 case '5': tmp[i] = 'a'; break;
00115 case '7': tmp[i] = 'e'; break;
00116 case '8': tmp[i] = '1'; break;
00117 case 'A':
00118 case 'a': tmp[i] = '5'; break;
00119 case 'B':
00120 case 'b': tmp[i] = 'd'; break;
00121 case 'C':
00122 case 'c': tmp[i] = '3'; break;
00123 case 'D':
00124 case 'd': tmp[i] = 'b'; break;
00125 case 'E':
00126 case 'e': tmp[i] = '7'; break;
00127 }
00128 if ( i % 2 )
00129 {
00130 char t = tmp[i];
00131 tmp[i] = tmp[i-1];
00132 tmp[i-1] = t;
00133 }
00134 }
00135 tmp.replace( QRegExp( "(\\w{12})" ), "\\1\n" );
00136 tmp.replace( QRegExp( "(\\w{4})" ), "0x\\1," );
00137 len = tmp.length();
00138 char *fbuf = (char *)malloc( len + 1 );
00139 strncpy( fbuf, (const char *)tmp, len );
00140 fbuf[len] = '\0';
00141 if ( !( status = setjmp( comp_env ) ) )
00142 {
00143 ReadFace( fbuf );
00144 GenFace();
00145 CompAll( fbuf );
00146 }
00147 QString ret( fbuf );
00148 free( fbuf );
00149
00150 return ret;
00151 }
00152
00153 QImage KXFace::toImage(const QString &xface)
00154 {
00155 if ( xface.length() > MAX_XFACE_LENGTH )
00156 return QImage();
00157
00158 char *fbuf = (char *)malloc( MAX_XFACE_LENGTH );
00159 memset( fbuf, '\0', MAX_XFACE_LENGTH );
00160 strncpy( fbuf, xface.latin1(), xface.length() );
00161 QCString img;
00162 if ( !( status = setjmp( comp_env ) ) )
00163 {
00164 UnCompAll( fbuf );
00165 UnGenFace();
00166 img = WriteFace();
00167 }
00168 free( fbuf );
00169 QImage p;
00170 p.loadFromData( img, "XBM" );
00171
00172 return p;
00173 }
00174
00175
00176
00177
00178 void KXFace::RevPush(const Prob *p)
00179 {
00180 if (NumProbs >= PIXELS * 2 - 1)
00181 longjmp(comp_env, ERR_INTERNAL);
00182 ProbBuf[NumProbs++] = (Prob *) p;
00183 }
00184
00185 void KXFace::BigPush(Prob *p)
00186 {
00187 static unsigned char tmp;
00188
00189 BigDiv(p->p_range, &tmp);
00190 BigMul(0);
00191 BigAdd(tmp + p->p_offset);
00192 }
00193
00194 int KXFace::BigPop(register const Prob *p)
00195 {
00196 static unsigned char tmp;
00197 register int i;
00198
00199 BigDiv(0, &tmp);
00200 i = 0;
00201 while ((tmp < p->p_offset) || (tmp >= p->p_range + p->p_offset))
00202 {
00203 p++;
00204 i++;
00205 }
00206 BigMul(p->p_range);
00207 BigAdd(tmp - p->p_offset);
00208 return i;
00209 }
00210
00211
00212
00213
00214
00215 void KXFace::BigDiv(register unsigned char a, register unsigned char *r)
00216 {
00217 register int i;
00218 register unsigned char *w;
00219 register COMP c, d;
00220
00221 a &= WORDMASK;
00222 if ((a == 1) || (B.b_words == 0))
00223 {
00224 *r = 0;
00225 return;
00226 }
00227 if (a == 0)
00228 {
00229 i = --B.b_words;
00230 w = B.b_word;
00231 *r = *w;
00232 while (i--)
00233 {
00234 *w = *(w + 1);
00235 w++;
00236 }
00237 *w = 0;
00238 return;
00239 }
00240 w = B.b_word + (i = B.b_words);
00241 c = 0;
00242 while (i--)
00243 {
00244 c <<= BITSPERWORD;
00245 c += (COMP)*--w;
00246 d = c / (COMP)a;
00247 c = c % (COMP)a;
00248 *w = (unsigned char)(d & WORDMASK);
00249 }
00250 *r = c;
00251 if (B.b_word[B.b_words - 1] == 0)
00252 B.b_words--;
00253 }
00254
00255
00256
00257 void KXFace::BigMul(register unsigned char a)
00258 {
00259 register int i;
00260 register unsigned char *w;
00261 register COMP c;
00262
00263 a &= WORDMASK;
00264 if ((a == 1) || (B.b_words == 0))
00265 return;
00266 if (a == 0)
00267 {
00268 if ((i = B.b_words++) >= MAXWORDS - 1)
00269 longjmp(comp_env, ERR_INTERNAL);
00270 w = B.b_word + i;
00271 while (i--)
00272 {
00273 *w = *(w - 1);
00274 w--;
00275 }
00276 *w = 0;
00277 return;
00278 }
00279 i = B.b_words;
00280 w = B.b_word;
00281 c = 0;
00282 while (i--)
00283 {
00284 c += (COMP)*w * (COMP)a;
00285 *(w++) = (unsigned char)(c & WORDMASK);
00286 c >>= BITSPERWORD;
00287 }
00288 if (c)
00289 {
00290 if (B.b_words++ >= MAXWORDS)
00291 longjmp(comp_env, ERR_INTERNAL);
00292 *w = (COMP)(c & WORDMASK);
00293 }
00294 }
00295
00296
00297
00298 void KXFace::BigAdd(unsigned char a)
00299 {
00300 register int i;
00301 register unsigned char *w;
00302 register COMP c;
00303
00304 a &= WORDMASK;
00305 if (a == 0)
00306 return;
00307 i = 0;
00308 w = B.b_word;
00309 c = a;
00310 while ((i < B.b_words) && c)
00311 {
00312 c += (COMP)*w;
00313 *w++ = (unsigned char)(c & WORDMASK);
00314 c >>= BITSPERWORD;
00315 i++;
00316 }
00317 if ((i == B.b_words) && c)
00318 {
00319 if (B.b_words++ >= MAXWORDS)
00320 longjmp(comp_env, ERR_INTERNAL);
00321 *w = (COMP)(c & WORDMASK);
00322 }
00323 }
00324
00325 void KXFace::BigClear()
00326 {
00327 B.b_words = 0;
00328 }
00329
00330 QCString KXFace::WriteFace()
00331 {
00332 register char *s;
00333 register int i, j, bits, digits, words;
00334 int digsperword = DIGSPERWORD;
00335 int wordsperline = WORDSPERLINE;
00336 QCString t( "#define noname_width 48\n#define noname_height 48\nstatic char noname_bits[] = {\n " );
00337 j = t.length() - 1;
00338
00339 s = F;
00340 bits = digits = words = i = 0;
00341 t.resize( MAX_XFACE_LENGTH );
00342 digsperword = 2;
00343 wordsperline = 15;
00344 while ( s < F + PIXELS )
00345 {
00346 if ( ( bits == 0 ) && ( digits == 0 ) )
00347 {
00348 t[j++] = '0';
00349 t[j++] = 'x';
00350 }
00351 if ( *(s++) )
00352 i = ( i >> 1 ) | 0x8;
00353 else
00354 i >>= 1;
00355 if ( ++bits == BITSPERDIG )
00356 {
00357 j++;
00358 t[j-( ( digits & 1 ) * 2 )] = *(i + HexDigits);
00359 bits = i = 0;
00360 if ( ++digits == digsperword )
00361 {
00362 if ( s >= F + PIXELS )
00363 break;
00364 t[j++] = ',';
00365 digits = 0;
00366 if ( ++words == wordsperline )
00367 {
00368 t[j++] = '\n';
00369 t[j++] = ' ';
00370 words = 0;
00371 }
00372 }
00373 }
00374 }
00375 t.resize( j + 1 );
00376 t += "};\n";
00377 return t;
00378 }
00379
00380 void KXFace::UnCompAll(char *fbuf)
00381 {
00382 register char *p;
00383
00384 BigClear();
00385 BigRead(fbuf);
00386 p = F;
00387 while (p < F + PIXELS)
00388 *(p++) = 0;
00389 UnCompress(F, 16, 16, 0);
00390 UnCompress(F + 16, 16, 16, 0);
00391 UnCompress(F + 32, 16, 16, 0);
00392 UnCompress(F + WIDTH * 16, 16, 16, 0);
00393 UnCompress(F + WIDTH * 16 + 16, 16, 16, 0);
00394 UnCompress(F + WIDTH * 16 + 32, 16, 16, 0);
00395 UnCompress(F + WIDTH * 32, 16, 16, 0);
00396 UnCompress(F + WIDTH * 32 + 16, 16, 16, 0);
00397 UnCompress(F + WIDTH * 32 + 32, 16, 16, 0);
00398 }
00399
00400 void KXFace::UnCompress(char *f, int wid, int hei, int lev)
00401 {
00402 switch (BigPop(&levels[lev][0]))
00403 {
00404 case WHITE :
00405 return;
00406 case BLACK :
00407 PopGreys(f, wid, hei);
00408 return;
00409 default :
00410 wid /= 2;
00411 hei /= 2;
00412 lev++;
00413 UnCompress(f, wid, hei, lev);
00414 UnCompress(f + wid, wid, hei, lev);
00415 UnCompress(f + hei * WIDTH, wid, hei, lev);
00416 UnCompress(f + wid + hei * WIDTH, wid, hei, lev);
00417 return;
00418 }
00419 }
00420
00421 void KXFace::BigWrite(register char *fbuf)
00422 {
00423 static unsigned char tmp;
00424 static char buf[DIGITS];
00425 register char *s;
00426 register int i;
00427
00428 s = buf;
00429 while (B.b_words > 0)
00430 {
00431 BigDiv(NUMPRINTS, &tmp);
00432 *(s++) = tmp + FIRSTPRINT;
00433 }
00434 i = 7;
00435 *(fbuf++) = ' ';
00436 while (s-- > buf)
00437 {
00438 if (i == 0)
00439 *(fbuf++) = ' ';
00440 *(fbuf++) = *s;
00441 if (++i >= MAXLINELEN)
00442 {
00443 *(fbuf++) = '\n';
00444 i = 0;
00445 }
00446 }
00447 if (i > 0)
00448 *(fbuf++) = '\n';
00449 *(fbuf++) = '\0';
00450 }
00451
00452 void KXFace::BigRead(register char *fbuf)
00453 {
00454 register int c;
00455
00456 while (*fbuf != '\0')
00457 {
00458 c = *(fbuf++);
00459 if ((c < FIRSTPRINT) || (c > LASTPRINT))
00460 continue;
00461 BigMul(NUMPRINTS);
00462 BigAdd((unsigned char)(c - FIRSTPRINT));
00463 }
00464 }
00465
00466 void KXFace::ReadFace(char *fbuf)
00467 {
00468 register int c, i;
00469 register char *s, *t;
00470
00471 t = s = fbuf;
00472 for(i = strlen(s); i > 0; i--)
00473 {
00474 c = (int)*(s++);
00475 if ((c >= '0') && (c <= '9'))
00476 {
00477 if (t >= fbuf + DIGITS)
00478 {
00479 status = ERR_EXCESS;
00480 break;
00481 }
00482 *(t++) = c - '0';
00483 }
00484 else if ((c >= 'A') && (c <= 'F'))
00485 {
00486 if (t >= fbuf + DIGITS)
00487 {
00488 status = ERR_EXCESS;
00489 break;
00490 }
00491 *(t++) = c - 'A' + 10;
00492 }
00493 else if ((c >= 'a') && (c <= 'f'))
00494 {
00495 if (t >= fbuf + DIGITS)
00496 {
00497 status = ERR_EXCESS;
00498 break;
00499 }
00500 *(t++) = c - 'a' + 10;
00501 }
00502 else if (((c == 'x') || (c == 'X')) && (t > fbuf) && (*(t-1) == 0))
00503 t--;
00504 }
00505 if (t < fbuf + DIGITS)
00506 longjmp(comp_env, ERR_INSUFF);
00507 s = fbuf;
00508 t = F;
00509 c = 1 << (BITSPERDIG - 1);
00510 while (t < F + PIXELS)
00511 {
00512 *(t++) = (*s & c) ? 1 : 0;
00513 if ((c >>= 1) == 0)
00514 {
00515 s++;
00516 c = 1 << (BITSPERDIG - 1);
00517 }
00518 }
00519 }
00520
00521 void KXFace::GenFace()
00522 {
00523 static char newp[PIXELS];
00524 register char *f1;
00525 register char *f2;
00526 register int i;
00527
00528 f1 = newp;
00529 f2 = F;
00530 i = PIXELS;
00531 while (i-- > 0)
00532 *(f1++) = *(f2++);
00533 Gen(newp);
00534 }
00535
00536 void KXFace::UnGenFace()
00537 {
00538 Gen(F);
00539 }
00540
00541
00542 void KXFace::Gen(register char *f)
00543 {
00544 register int m, l, k, j, i, h;
00545
00546 for (j = 0; j < HEIGHT; j++)
00547 {
00548 for (i = 0; i < WIDTH; i++)
00549 {
00550 h = i + j * WIDTH;
00551 k = 0;
00552 for (l = i - 2; l <= i + 2; l++)
00553 for (m = j - 2; m <= j; m++)
00554 {
00555 if ((l >= i) && (m == j))
00556 continue;
00557 if ((l > 0) && (l <= WIDTH) && (m > 0))
00558 k = *(f + l + m * WIDTH) ? k * 2 + 1 : k * 2;
00559 }
00560 switch (i)
00561 {
00562 case 1 :
00563 switch (j)
00564 {
00565 case 1 : GEN(g_22);
00566 case 2 : GEN(g_21);
00567 default : GEN(g_20);
00568 }
00569 break;
00570 case 2 :
00571 switch (j)
00572 {
00573 case 1 : GEN(g_12);
00574 case 2 : GEN(g_11);
00575 default : GEN(g_10);
00576 }
00577 break;
00578 case WIDTH - 1 :
00579 switch (j)
00580 {
00581 case 1 : GEN(g_42);
00582 case 2 : GEN(g_41);
00583 default : GEN(g_40);
00584 }
00585 break;
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 default :
00598 switch (j)
00599 {
00600 case 1 : GEN(g_02);
00601 case 2 : GEN(g_01);
00602 default : GEN(g_00);
00603 }
00604 break;
00605 }
00606 }
00607 }
00608 }
00609
00610 void KXFace::PopGreys(char *f, int wid, int hei)
00611 {
00612 if (wid > 3)
00613 {
00614 wid /= 2;
00615 hei /= 2;
00616 PopGreys(f, wid, hei);
00617 PopGreys(f + wid, wid, hei);
00618 PopGreys(f + WIDTH * hei, wid, hei);
00619 PopGreys(f + WIDTH * hei + wid, wid, hei);
00620 }
00621 else
00622 {
00623 wid = BigPop(freqs);
00624 if (wid & 1)
00625 *f = 1;
00626 if (wid & 2)
00627 *(f + 1) = 1;
00628 if (wid & 4)
00629 *(f + WIDTH) = 1;
00630 if (wid & 8)
00631 *(f + WIDTH + 1) = 1;
00632 }
00633 }
00634
00635 void KXFace::CompAll(char *fbuf)
00636 {
00637 Compress(F, 16, 16, 0);
00638 Compress(F + 16, 16, 16, 0);
00639 Compress(F + 32, 16, 16, 0);
00640 Compress(F + WIDTH * 16, 16, 16, 0);
00641 Compress(F + WIDTH * 16 + 16, 16, 16, 0);
00642 Compress(F + WIDTH * 16 + 32, 16, 16, 0);
00643 Compress(F + WIDTH * 32, 16, 16, 0);
00644 Compress(F + WIDTH * 32 + 16, 16, 16, 0);
00645 Compress(F + WIDTH * 32 + 32, 16, 16, 0);
00646 BigClear();
00647 while (NumProbs > 0)
00648 BigPush(ProbBuf[--NumProbs]);
00649 BigWrite(fbuf);
00650 }
00651
00652 void KXFace::Compress(register char *f, register int wid, register int hei, register int lev)
00653 {
00654 if (AllWhite(f, wid, hei))
00655 {
00656 RevPush(&levels[lev][WHITE]);
00657 return;
00658 }
00659 if (AllBlack(f, wid, hei))
00660 {
00661 RevPush(&levels[lev][BLACK]);
00662 PushGreys(f, wid, hei);
00663 return;
00664 }
00665 RevPush(&levels[lev][GREY]);
00666 wid /= 2;
00667 hei /= 2;
00668 lev++;
00669 Compress(f, wid, hei, lev);
00670 Compress(f + wid, wid, hei, lev);
00671 Compress(f + hei * WIDTH, wid, hei, lev);
00672 Compress(f + wid + hei * WIDTH, wid, hei, lev);
00673 }
00674
00675 int KXFace::AllWhite(char *f, int wid, int hei)
00676 {
00677 return ((*f == 0) && Same(f, wid, hei));
00678 }
00679
00680 int KXFace::AllBlack(char *f, int wid, int hei)
00681 {
00682 if (wid > 3)
00683 {
00684 wid /= 2;
00685 hei /= 2;
00686 return (AllBlack(f, wid, hei) && AllBlack(f + wid, wid, hei) &&
00687 AllBlack(f + WIDTH * hei, wid, hei) &&
00688 AllBlack(f + WIDTH * hei + wid, wid, hei));
00689 }
00690 else
00691 return (*f || *(f + 1) || *(f + WIDTH) || *(f + WIDTH + 1));
00692 }
00693
00694 int KXFace::Same(register char *f, register int wid, register int hei)
00695 {
00696 register char val, *row;
00697 register int x;
00698
00699 val = *f;
00700 while (hei--)
00701 {
00702 row = f;
00703 x = wid;
00704 while (x--)
00705 if (*(row++) != val)
00706 return(0);
00707 f += WIDTH;
00708 }
00709 return 1;
00710 }
00711
00712 void KXFace::PushGreys(char *f, int wid, int hei)
00713 {
00714 if (wid > 3)
00715 {
00716 wid /= 2;
00717 hei /= 2;
00718 PushGreys(f, wid, hei);
00719 PushGreys(f + wid, wid, hei);
00720 PushGreys(f + WIDTH * hei, wid, hei);
00721 PushGreys(f + WIDTH * hei + wid, wid, hei);
00722 }
00723 else
00724 RevPush(freqs + *f + 2 * *(f + 1) + 4 * *(f + WIDTH) +
00725 8 * *(f + WIDTH + 1));
00726 }
00727
00728
00729 #include "kxface.moc"