summaryrefslogtreecommitdiffstats
path: root/libkdepim/kxface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkdepim/kxface.cpp')
-rw-r--r--libkdepim/kxface.cpp729
1 files changed, 729 insertions, 0 deletions
diff --git a/libkdepim/kxface.cpp b/libkdepim/kxface.cpp
new file mode 100644
index 000000000..574a0aa9d
--- /dev/null
+++ b/libkdepim/kxface.cpp
@@ -0,0 +1,729 @@
+/*
+ This file is part of libkdepim.
+
+ Original compface:
+ Copyright (c) James Ashton - Sydney University - June 1990.
+
+ Additions for KDE:
+ Copyright (c) 2004 Jakob Schröter <js@camaya.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kxface.h"
+
+#include <kdebug.h>
+
+#include <qbuffer.h>
+#include <qcstring.h>
+#include <qimage.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qpainter.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#define GEN(g) F[h] ^= G.g[k]; break
+
+#define BITSPERDIG 4
+#define DIGITS (PIXELS / BITSPERDIG)
+#define DIGSPERWORD 4
+#define WORDSPERLINE (WIDTH / DIGSPERWORD / BITSPERDIG)
+
+/* compressed output uses the full range of printable characters.
+ * in ascii these are in a contiguous block so we just need to know
+ * the first and last. The total number of printables is needed too */
+#define FIRSTPRINT '!'
+#define LASTPRINT '~'
+#define NUMPRINTS (LASTPRINT - FIRSTPRINT + 1)
+
+/* output line length for compressed data */
+#define MAXLINELEN 78
+
+/* Portable, very large unsigned integer arithmetic is needed.
+ * Implementation uses arrays of WORDs. COMPs must have at least
+ * twice as many bits as WORDs to handle intermediate results */
+#define COMP unsigned long
+#define WORDCARRY (1 << BITSPERWORD)
+#define WORDMASK (WORDCARRY - 1)
+
+#define ERR_OK 0 /* successful completion */
+#define ERR_EXCESS 1 /* completed OK but some input was ignored */
+#define ERR_INSUFF -1 /* insufficient input. Bad face format? */
+#define ERR_INTERNAL -2 /* Arithmetic overflow or buffer overflow */
+
+#define BLACK 0
+#define GREY 1
+#define WHITE 2
+
+#define MAX_XFACE_LENGTH 2048
+
+using namespace KPIM;
+
+KXFace::KXFace()
+{
+ NumProbs = 0;
+}
+
+KXFace::~KXFace()
+{
+}
+
+QString KXFace::fromImage( const QImage &image )
+{
+ if( image.isNull() )
+ return QString::null;
+
+ QImage scaledImg = image.smoothScale( 48, 48 );
+ QByteArray ba;
+ QBuffer buffer( ba );
+ buffer.open( IO_WriteOnly );
+ scaledImg.save( &buffer, "XBM" );
+ QString xbm( ba );
+ xbm.remove( 0, xbm.find( "{" ) + 1 );
+ xbm.truncate( xbm.find( "}" ) );
+ xbm.remove( " " );
+ xbm.remove( "," );
+ xbm.remove( "0x" );
+ xbm.remove( "\n" );
+ xbm.truncate( 576 );
+ QCString tmp = QCString( xbm.latin1() );
+ uint len = tmp.length();
+ for( uint i=0; i<len; ++i )
+ {
+ switch( tmp[i] )
+ {
+ case '1': tmp[i] = '8'; break;
+ case '2': tmp[i] = '4'; break;
+ case '3': tmp[i] = 'c'; break;
+ case '4': tmp[i] = '2'; break;
+ case '5': tmp[i] = 'a'; break;
+ case '7': tmp[i] = 'e'; break;
+ case '8': tmp[i] = '1'; break;
+ case 'A':
+ case 'a': tmp[i] = '5'; break;
+ case 'B':
+ case 'b': tmp[i] = 'd'; break;
+ case 'C':
+ case 'c': tmp[i] = '3'; break;
+ case 'D':
+ case 'd': tmp[i] = 'b'; break;
+ case 'E':
+ case 'e': tmp[i] = '7'; break;
+ }
+ if ( i % 2 )
+ {
+ char t = tmp[i];
+ tmp[i] = tmp[i-1];
+ tmp[i-1] = t;
+ }
+ }
+ tmp.replace( QRegExp( "(\\w{12})" ), "\\1\n" );
+ tmp.replace( QRegExp( "(\\w{4})" ), "0x\\1," );
+ len = tmp.length();
+ char *fbuf = (char *)malloc( len + 1 );
+ strncpy( fbuf, (const char *)tmp, len );
+ fbuf[len] = '\0';
+ if ( !( status = setjmp( comp_env ) ) )
+ {
+ ReadFace( fbuf );
+ GenFace();
+ CompAll( fbuf );
+ }
+ QString ret( fbuf );
+ free( fbuf );
+
+ return ret;
+}
+
+QImage KXFace::toImage(const QString &xface)
+{
+ if ( xface.length() > MAX_XFACE_LENGTH )
+ return QImage();
+
+ char *fbuf = (char *)malloc( MAX_XFACE_LENGTH );
+ memset( fbuf, '\0', MAX_XFACE_LENGTH );
+ strncpy( fbuf, xface.latin1(), xface.length() );
+ QCString img;
+ if ( !( status = setjmp( comp_env ) ) )
+ {
+ UnCompAll( fbuf );/* compress otherwise */
+ UnGenFace();
+ img = WriteFace();
+ }
+ free( fbuf );
+ QImage p;
+ p.loadFromData( img, "XBM" );
+
+ return p;
+}
+
+//============================================================================
+// more or less original compface 1.4 source
+
+void KXFace::RevPush(const Prob *p)
+{
+ if (NumProbs >= PIXELS * 2 - 1)
+ longjmp(comp_env, ERR_INTERNAL);
+ ProbBuf[NumProbs++] = (Prob *) p;
+}
+
+void KXFace::BigPush(Prob *p)
+{
+ static unsigned char tmp;
+
+ BigDiv(p->p_range, &tmp);
+ BigMul(0);
+ BigAdd(tmp + p->p_offset);
+}
+
+int KXFace::BigPop(register const Prob *p)
+{
+ static unsigned char tmp;
+ register int i;
+
+ BigDiv(0, &tmp);
+ i = 0;
+ while ((tmp < p->p_offset) || (tmp >= p->p_range + p->p_offset))
+ {
+ p++;
+ i++;
+ }
+ BigMul(p->p_range);
+ BigAdd(tmp - p->p_offset);
+ return i;
+}
+
+
+/* Divide B by a storing the result in B and the remainder in the word
+ * pointer to by r
+ */
+void KXFace::BigDiv(register unsigned char a, register unsigned char *r)
+{
+ register int i;
+ register unsigned char *w;
+ register COMP c, d;
+
+ a &= WORDMASK;
+ if ((a == 1) || (B.b_words == 0))
+ {
+ *r = 0;
+ return;
+ }
+ if (a == 0) /* treat this as a == WORDCARRY */
+ { /* and just shift everything right a WORD (unsigned char)*/
+ i = --B.b_words;
+ w = B.b_word;
+ *r = *w;
+ while (i--)
+ {
+ *w = *(w + 1);
+ w++;
+ }
+ *w = 0;
+ return;
+ }
+ w = B.b_word + (i = B.b_words);
+ c = 0;
+ while (i--)
+ {
+ c <<= BITSPERWORD;
+ c += (COMP)*--w;
+ d = c / (COMP)a;
+ c = c % (COMP)a;
+ *w = (unsigned char)(d & WORDMASK);
+ }
+ *r = c;
+ if (B.b_word[B.b_words - 1] == 0)
+ B.b_words--;
+}
+
+/* Multiply a by B storing the result in B
+ */
+void KXFace::BigMul(register unsigned char a)
+{
+ register int i;
+ register unsigned char *w;
+ register COMP c;
+
+ a &= WORDMASK;
+ if ((a == 1) || (B.b_words == 0))
+ return;
+ if (a == 0) /* treat this as a == WORDCARRY */
+ { /* and just shift everything left a WORD (unsigned char) */
+ if ((i = B.b_words++) >= MAXWORDS - 1)
+ longjmp(comp_env, ERR_INTERNAL);
+ w = B.b_word + i;
+ while (i--)
+ {
+ *w = *(w - 1);
+ w--;
+ }
+ *w = 0;
+ return;
+ }
+ i = B.b_words;
+ w = B.b_word;
+ c = 0;
+ while (i--)
+ {
+ c += (COMP)*w * (COMP)a;
+ *(w++) = (unsigned char)(c & WORDMASK);
+ c >>= BITSPERWORD;
+ }
+ if (c)
+ {
+ if (B.b_words++ >= MAXWORDS)
+ longjmp(comp_env, ERR_INTERNAL);
+ *w = (COMP)(c & WORDMASK);
+ }
+}
+
+/* Add to a to B storing the result in B
+ */
+void KXFace::BigAdd(unsigned char a)
+{
+ register int i;
+ register unsigned char *w;
+ register COMP c;
+
+ a &= WORDMASK;
+ if (a == 0)
+ return;
+ i = 0;
+ w = B.b_word;
+ c = a;
+ while ((i < B.b_words) && c)
+ {
+ c += (COMP)*w;
+ *w++ = (unsigned char)(c & WORDMASK);
+ c >>= BITSPERWORD;
+ i++;
+ }
+ if ((i == B.b_words) && c)
+ {
+ if (B.b_words++ >= MAXWORDS)
+ longjmp(comp_env, ERR_INTERNAL);
+ *w = (COMP)(c & WORDMASK);
+ }
+}
+
+void KXFace::BigClear()
+{
+ B.b_words = 0;
+}
+
+QCString KXFace::WriteFace()
+{
+ register char *s;
+ register int i, j, bits, digits, words;
+ int digsperword = DIGSPERWORD;
+ int wordsperline = WORDSPERLINE;
+ QCString t( "#define noname_width 48\n#define noname_height 48\nstatic char noname_bits[] = {\n " );
+ j = t.length() - 1;
+
+ s = F;
+ bits = digits = words = i = 0;
+ t.resize( MAX_XFACE_LENGTH );
+ digsperword = 2;
+ wordsperline = 15;
+ while ( s < F + PIXELS )
+ {
+ if ( ( bits == 0 ) && ( digits == 0 ) )
+ {
+ t[j++] = '0';
+ t[j++] = 'x';
+ }
+ if ( *(s++) )
+ i = ( i >> 1 ) | 0x8;
+ else
+ i >>= 1;
+ if ( ++bits == BITSPERDIG )
+ {
+ j++;
+ t[j-( ( digits & 1 ) * 2 )] = *(i + HexDigits);
+ bits = i = 0;
+ if ( ++digits == digsperword )
+ {
+ if ( s >= F + PIXELS )
+ break;
+ t[j++] = ',';
+ digits = 0;
+ if ( ++words == wordsperline )
+ {
+ t[j++] = '\n';
+ t[j++] = ' ';
+ words = 0;
+ }
+ }
+ }
+ }
+ t.resize( j + 1 );
+ t += "};\n";
+ return t;
+}
+
+void KXFace::UnCompAll(char *fbuf)
+{
+ register char *p;
+
+ BigClear();
+ BigRead(fbuf);
+ p = F;
+ while (p < F + PIXELS)
+ *(p++) = 0;
+ UnCompress(F, 16, 16, 0);
+ UnCompress(F + 16, 16, 16, 0);
+ UnCompress(F + 32, 16, 16, 0);
+ UnCompress(F + WIDTH * 16, 16, 16, 0);
+ UnCompress(F + WIDTH * 16 + 16, 16, 16, 0);
+ UnCompress(F + WIDTH * 16 + 32, 16, 16, 0);
+ UnCompress(F + WIDTH * 32, 16, 16, 0);
+ UnCompress(F + WIDTH * 32 + 16, 16, 16, 0);
+ UnCompress(F + WIDTH * 32 + 32, 16, 16, 0);
+}
+
+void KXFace::UnCompress(char *f, int wid, int hei, int lev)
+{
+ switch (BigPop(&levels[lev][0]))
+ {
+ case WHITE :
+ return;
+ case BLACK :
+ PopGreys(f, wid, hei);
+ return;
+ default :
+ wid /= 2;
+ hei /= 2;
+ lev++;
+ UnCompress(f, wid, hei, lev);
+ UnCompress(f + wid, wid, hei, lev);
+ UnCompress(f + hei * WIDTH, wid, hei, lev);
+ UnCompress(f + wid + hei * WIDTH, wid, hei, lev);
+ return;
+ }
+}
+
+void KXFace::BigWrite(register char *fbuf)
+{
+ static unsigned char tmp;
+ static char buf[DIGITS];
+ register char *s;
+ register int i;
+
+ s = buf;
+ while (B.b_words > 0)
+ {
+ BigDiv(NUMPRINTS, &tmp);
+ *(s++) = tmp + FIRSTPRINT;
+ }
+ i = 7; // leave room for the field name on the first line
+ *(fbuf++) = ' ';
+ while (s-- > buf)
+ {
+ if (i == 0)
+ *(fbuf++) = ' ';
+ *(fbuf++) = *s;
+ if (++i >= MAXLINELEN)
+ {
+ *(fbuf++) = '\n';
+ i = 0;
+ }
+ }
+ if (i > 0)
+ *(fbuf++) = '\n';
+ *(fbuf++) = '\0';
+}
+
+void KXFace::BigRead(register char *fbuf)
+{
+ register int c;
+
+ while (*fbuf != '\0')
+ {
+ c = *(fbuf++);
+ if ((c < FIRSTPRINT) || (c > LASTPRINT))
+ continue;
+ BigMul(NUMPRINTS);
+ BigAdd((unsigned char)(c - FIRSTPRINT));
+ }
+}
+
+void KXFace::ReadFace(char *fbuf)
+{
+ register int c, i;
+ register char *s, *t;
+
+ t = s = fbuf;
+ for(i = strlen(s); i > 0; i--)
+ {
+ c = (int)*(s++);
+ if ((c >= '0') && (c <= '9'))
+ {
+ if (t >= fbuf + DIGITS)
+ {
+ status = ERR_EXCESS;
+ break;
+ }
+ *(t++) = c - '0';
+ }
+ else if ((c >= 'A') && (c <= 'F'))
+ {
+ if (t >= fbuf + DIGITS)
+ {
+ status = ERR_EXCESS;
+ break;
+ }
+ *(t++) = c - 'A' + 10;
+ }
+ else if ((c >= 'a') && (c <= 'f'))
+ {
+ if (t >= fbuf + DIGITS)
+ {
+ status = ERR_EXCESS;
+ break;
+ }
+ *(t++) = c - 'a' + 10;
+ }
+ else if (((c == 'x') || (c == 'X')) && (t > fbuf) && (*(t-1) == 0))
+ t--;
+ }
+ if (t < fbuf + DIGITS)
+ longjmp(comp_env, ERR_INSUFF);
+ s = fbuf;
+ t = F;
+ c = 1 << (BITSPERDIG - 1);
+ while (t < F + PIXELS)
+ {
+ *(t++) = (*s & c) ? 1 : 0;
+ if ((c >>= 1) == 0)
+ {
+ s++;
+ c = 1 << (BITSPERDIG - 1);
+ }
+ }
+}
+
+void KXFace::GenFace()
+{
+ static char newp[PIXELS];
+ register char *f1;
+ register char *f2;
+ register int i;
+
+ f1 = newp;
+ f2 = F;
+ i = PIXELS;
+ while (i-- > 0)
+ *(f1++) = *(f2++);
+ Gen(newp);
+}
+
+void KXFace::UnGenFace()
+{
+ Gen(F);
+}
+
+// static
+void KXFace::Gen(register char *f)
+{
+ register int m, l, k, j, i, h;
+
+ for (j = 0; j < HEIGHT; j++)
+ {
+ for (i = 0; i < WIDTH; i++)
+ {
+ h = i + j * WIDTH;
+ k = 0;
+ for (l = i - 2; l <= i + 2; l++)
+ for (m = j - 2; m <= j; m++)
+ {
+ if ((l >= i) && (m == j))
+ continue;
+ if ((l > 0) && (l <= WIDTH) && (m > 0))
+ k = *(f + l + m * WIDTH) ? k * 2 + 1 : k * 2;
+ }
+ switch (i)
+ {
+ case 1 :
+ switch (j)
+ {
+ case 1 : GEN(g_22);
+ case 2 : GEN(g_21);
+ default : GEN(g_20);
+ }
+ break;
+ case 2 :
+ switch (j)
+ {
+ case 1 : GEN(g_12);
+ case 2 : GEN(g_11);
+ default : GEN(g_10);
+ }
+ break;
+ case WIDTH - 1 :
+ switch (j)
+ {
+ case 1 : GEN(g_42);
+ case 2 : GEN(g_41);
+ default : GEN(g_40);
+ }
+ break;
+ /* i runs from 0 to WIDTH-1, so case can never occur. I leave the code in
+ because it appears exactly like this in the original compface code.
+ case WIDTH :
+ switch (j)
+ {
+ case 1 : GEN(g_32);
+ case 2 : GEN(g_31);
+ default : GEN(g_30);
+ }
+ break;
+ */
+ default :
+ switch (j)
+ {
+ case 1 : GEN(g_02);
+ case 2 : GEN(g_01);
+ default : GEN(g_00);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void KXFace::PopGreys(char *f, int wid, int hei)
+{
+ if (wid > 3)
+ {
+ wid /= 2;
+ hei /= 2;
+ PopGreys(f, wid, hei);
+ PopGreys(f + wid, wid, hei);
+ PopGreys(f + WIDTH * hei, wid, hei);
+ PopGreys(f + WIDTH * hei + wid, wid, hei);
+ }
+ else
+ {
+ wid = BigPop(freqs);
+ if (wid & 1)
+ *f = 1;
+ if (wid & 2)
+ *(f + 1) = 1;
+ if (wid & 4)
+ *(f + WIDTH) = 1;
+ if (wid & 8)
+ *(f + WIDTH + 1) = 1;
+ }
+}
+
+void KXFace::CompAll(char *fbuf)
+{
+ Compress(F, 16, 16, 0);
+ Compress(F + 16, 16, 16, 0);
+ Compress(F + 32, 16, 16, 0);
+ Compress(F + WIDTH * 16, 16, 16, 0);
+ Compress(F + WIDTH * 16 + 16, 16, 16, 0);
+ Compress(F + WIDTH * 16 + 32, 16, 16, 0);
+ Compress(F + WIDTH * 32, 16, 16, 0);
+ Compress(F + WIDTH * 32 + 16, 16, 16, 0);
+ Compress(F + WIDTH * 32 + 32, 16, 16, 0);
+ BigClear();
+ while (NumProbs > 0)
+ BigPush(ProbBuf[--NumProbs]);
+ BigWrite(fbuf);
+}
+
+void KXFace::Compress(register char *f, register int wid, register int hei, register int lev)
+{
+ if (AllWhite(f, wid, hei))
+ {
+ RevPush(&levels[lev][WHITE]);
+ return;
+ }
+ if (AllBlack(f, wid, hei))
+ {
+ RevPush(&levels[lev][BLACK]);
+ PushGreys(f, wid, hei);
+ return;
+ }
+ RevPush(&levels[lev][GREY]);
+ wid /= 2;
+ hei /= 2;
+ lev++;
+ Compress(f, wid, hei, lev);
+ Compress(f + wid, wid, hei, lev);
+ Compress(f + hei * WIDTH, wid, hei, lev);
+ Compress(f + wid + hei * WIDTH, wid, hei, lev);
+}
+
+int KXFace::AllWhite(char *f, int wid, int hei)
+{
+ return ((*f == 0) && Same(f, wid, hei));
+}
+
+int KXFace::AllBlack(char *f, int wid, int hei)
+{
+ if (wid > 3)
+ {
+ wid /= 2;
+ hei /= 2;
+ return (AllBlack(f, wid, hei) && AllBlack(f + wid, wid, hei) &&
+ AllBlack(f + WIDTH * hei, wid, hei) &&
+ AllBlack(f + WIDTH * hei + wid, wid, hei));
+ }
+ else
+ return (*f || *(f + 1) || *(f + WIDTH) || *(f + WIDTH + 1));
+}
+
+int KXFace::Same(register char *f, register int wid, register int hei)
+{
+ register char val, *row;
+ register int x;
+
+ val = *f;
+ while (hei--)
+ {
+ row = f;
+ x = wid;
+ while (x--)
+ if (*(row++) != val)
+ return(0);
+ f += WIDTH;
+ }
+ return 1;
+}
+
+void KXFace::PushGreys(char *f, int wid, int hei)
+{
+ if (wid > 3)
+ {
+ wid /= 2;
+ hei /= 2;
+ PushGreys(f, wid, hei);
+ PushGreys(f + wid, wid, hei);
+ PushGreys(f + WIDTH * hei, wid, hei);
+ PushGreys(f + WIDTH * hei + wid, wid, hei);
+ }
+ else
+ RevPush(freqs + *f + 2 * *(f + 1) + 4 * *(f + WIDTH) +
+ 8 * *(f + WIDTH + 1));
+}
+
+
+#include "kxface.moc"