You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
730 lines
15 KiB
730 lines
15 KiB
/*
|
|
This file is part of libtdepim.
|
|
|
|
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 <tqbuffer.h>
|
|
#include <tqcstring.h>
|
|
#include <tqimage.h>
|
|
#include <tqregexp.h>
|
|
#include <tqstring.h>
|
|
#include <tqpainter.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()
|
|
{
|
|
}
|
|
|
|
TQString KXFace::fromImage( const TQImage &image )
|
|
{
|
|
if( image.isNull() )
|
|
return TQString();
|
|
|
|
TQImage scaledImg = image.smoothScale( 48, 48 );
|
|
TQByteArray ba;
|
|
TQBuffer buffer( ba );
|
|
buffer.open( IO_WriteOnly );
|
|
scaledImg.save( &buffer, "XBM" );
|
|
TQString 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 );
|
|
TQCString tmp = TQCString( 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( TQRegExp( "(\\w{12})" ), "\\1\n" );
|
|
tmp.replace( TQRegExp( "(\\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 );
|
|
}
|
|
TQString ret( fbuf );
|
|
free( fbuf );
|
|
|
|
return ret;
|
|
}
|
|
|
|
TQImage KXFace::toImage(const TQString &xface)
|
|
{
|
|
if ( xface.length() > MAX_XFACE_LENGTH )
|
|
return TQImage();
|
|
|
|
char *fbuf = (char *)malloc( MAX_XFACE_LENGTH );
|
|
memset( fbuf, '\0', MAX_XFACE_LENGTH );
|
|
strncpy( fbuf, xface.latin1(), xface.length() );
|
|
TQCString img;
|
|
if ( !( status = setjmp( comp_env ) ) )
|
|
{
|
|
UnCompAll( fbuf );/* compress otherwise */
|
|
UnGenFace();
|
|
img = WriteFace();
|
|
}
|
|
free( fbuf );
|
|
TQImage 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(const Prob *p)
|
|
{
|
|
static unsigned char tmp;
|
|
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(unsigned char a, unsigned char *r)
|
|
{
|
|
int i;
|
|
unsigned char *w;
|
|
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(unsigned char a)
|
|
{
|
|
int i;
|
|
unsigned char *w;
|
|
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)
|
|
{
|
|
int i;
|
|
unsigned char *w;
|
|
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;
|
|
}
|
|
|
|
TQCString KXFace::WriteFace()
|
|
{
|
|
char *s;
|
|
int i, j, bits, digits, words;
|
|
int digsperword = DIGSPERWORD;
|
|
int wordsperline = WORDSPERLINE;
|
|
TQCString 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)
|
|
{
|
|
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(char *fbuf)
|
|
{
|
|
static unsigned char tmp;
|
|
static char buf[DIGITS];
|
|
char *s;
|
|
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(char *fbuf)
|
|
{
|
|
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)
|
|
{
|
|
int c, i;
|
|
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];
|
|
char *f1;
|
|
char *f2;
|
|
int i;
|
|
|
|
f1 = newp;
|
|
f2 = F;
|
|
i = PIXELS;
|
|
while (i-- > 0)
|
|
*(f1++) = *(f2++);
|
|
Gen(newp);
|
|
}
|
|
|
|
void KXFace::UnGenFace()
|
|
{
|
|
Gen(F);
|
|
}
|
|
|
|
// static
|
|
void KXFace::Gen(char *f)
|
|
{
|
|
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(char *f, int wid, int hei, 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(char *f, int wid, int hei)
|
|
{
|
|
char val, *row;
|
|
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"
|