libkdepim

kxface.cpp

00001 /*
00002   This file is part of libkdepim.
00003 
00004   Original compface:
00005   Copyright (c) James Ashton - Sydney University - June 1990.
00006 
00007   Additions for KDE:
00008   Copyright (c) 2004 Jakob Schröter <js@camaya.net>
00009 
00010   This library is free software; you can redistribute it and/or
00011   modify it under the terms of the GNU Library General Public
00012   License as published by the Free Software Foundation; either
00013   version 2 of the License, or (at your option) any later version.
00014 
00015   This library is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY; without even the implied warranty of
00017   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018   Library General Public License for more details.
00019 
00020   You should have received a copy of the GNU Library General Public License
00021   along with this library; see the file COPYING.LIB.  If not, write to
00022   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00023   Boston, MA 02110-1301, USA.
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 /* compressed output uses the full range of printable characters.
00048  * in ascii these are in a contiguous block so we just need to know
00049  * the first and last.  The total number of printables is needed too */
00050 #define FIRSTPRINT '!'
00051 #define LASTPRINT '~'
00052 #define NUMPRINTS (LASTPRINT - FIRSTPRINT + 1)
00053 
00054 /* output line length for compressed data */
00055 #define MAXLINELEN 78
00056 
00057 /* Portable, very large unsigned integer arithmetic is needed.
00058  * Implementation uses arrays of WORDs.  COMPs must have at least
00059  * twice as many bits as WORDs to handle intermediate results */
00060 #define COMP unsigned long
00061 #define WORDCARRY (1 << BITSPERWORD)
00062 #define WORDMASK (WORDCARRY - 1)
00063 
00064 #define ERR_OK      0   /* successful completion */
00065 #define ERR_EXCESS  1   /* completed OK but some input was ignored */
00066 #define ERR_INSUFF  -1  /* insufficient input.  Bad face format? */
00067 #define ERR_INTERNAL    -2  /* Arithmetic overflow or buffer overflow */
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 );/* compress otherwise */
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 // more or less original compface 1.4 source
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 /* Divide B by a storing the result in B and the remainder in the word
00213  * pointer to by r
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)   /* treat this as a == WORDCARRY */
00228   {         /* and just shift everything right a WORD (unsigned char)*/
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 /* Multiply a by B storing the result in B
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)   /* treat this as a == WORDCARRY */
00267   {         /* and just shift everything left a WORD (unsigned char) */
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 /* Add to a to B storing the result in B
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;    // leave room for the field name on the first line
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 // static
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         /* i runs from 0 to WIDTH-1, so case can never occur. I leave the code in
00587            because it appears exactly like this in the original compface code.
00588         case WIDTH :
00589           switch (j)
00590           {
00591             case 1 : GEN(g_32);
00592             case 2 : GEN(g_31);
00593             default : GEN(g_30);
00594           }
00595           break;
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"
KDE Home | KDE Accessibility Home | Description of Access Keys