17#include <QRegularExpression>
28#define DIGITS (PIXELS / BITSPERDIG)
30#define WORDSPERLINE (WIDTH / DIGSPERWORD / BITSPERDIG)
37#define NUMPRINTS (LASTPRINT - FIRSTPRINT + 1)
40static const int MAXLINELEN = 78;
45#define COMP unsigned long
46#define WORDCARRY (1 << BITSPERWORD)
47#define WORDMASK (WORDCARRY - 1)
52#define ERR_INTERNAL -2
58static const int MAX_XFACE_LENGTH = 2048;
60using namespace MessageViewer;
67KXFace::~KXFace() =
default;
79 scaledImg.
save(&buffer,
"XBM");
85 xbm.
remove(QStringLiteral(
"0x"));
90 for (
int i = 0; i < len; ++i) {
91 switch (tmp[i].toLatin1()) {
143 char *fbuf = (
char *)malloc(len + 1);
146 if (!(status = setjmp(comp_env))) {
159 if (xface.
length() > MAX_XFACE_LENGTH) {
163 char *fbuf = (
char *)malloc(MAX_XFACE_LENGTH);
164 memset(fbuf,
'\0', MAX_XFACE_LENGTH);
167 if (!(status = setjmp(comp_env))) {
182void KXFace::RevPush(
const Prob *p)
184 if (NumProbs >= PIXELS * 2 - 1) {
185 longjmp(comp_env, ERR_INTERNAL);
187 ProbBuf[NumProbs++] = (Prob *)p;
190void KXFace::BigPush(Prob *p)
192 static unsigned char tmp;
194 BigDiv(p->p_range, &tmp);
196 BigAdd(tmp + p->p_offset);
199int KXFace::BigPop(
const Prob *p)
201 static unsigned char tmp;
206 while ((tmp < p->p_offset) || (tmp >= p->p_range + p->p_offset)) {
211 BigAdd(tmp - p->p_offset);
218void KXFace::BigDiv(
unsigned char a,
unsigned char *r)
225 if ((a == 1) || (B.b_words == 0)) {
241 w = B.b_word + (i = B.b_words);
248 *w = (
unsigned char)(d & WORDMASK);
251 if (B.b_word[B.b_words - 1] == 0) {
258void KXFace::BigMul(
unsigned char a)
265 if ((a == 1) || (B.b_words == 0)) {
270 if ((i = B.b_words++) >= MAXWORDS - 1) {
271 longjmp(comp_env, ERR_INTERNAL);
285 c += (COMP)*w * (COMP)a;
286 *(w++) = (
unsigned char)(c & WORDMASK);
290 if (B.b_words++ >= MAXWORDS) {
291 longjmp(comp_env, ERR_INTERNAL);
293 *w = (COMP)(c & WORDMASK);
299void KXFace::BigAdd(
unsigned char a)
312 while ((i < B.b_words) && c) {
314 *w++ = (
unsigned char)(c & WORDMASK);
318 if ((i == B.b_words) && c) {
319 if (B.b_words++ >= MAXWORDS) {
320 longjmp(comp_env, ERR_INTERNAL);
322 *w = (COMP)(c & WORDMASK);
326void KXFace::BigClear()
341 QByteArray t(
"#define noname_width 48\n#define noname_height 48\nstatic char noname_bits[] = {\n ");
345 bits = digits = words = i = 0;
346 t.resize(MAX_XFACE_LENGTH);
348 int wordsperline = 15;
349 while (s < F + PIXELS) {
350 if ((bits == 0) && (digits == 0)) {
359 if (++bits == BITSPERDIG) {
361 t[j - ((digits & 1) * 2)] = *(i + HexDigits);
363 if (++digits == digsperword) {
364 if (s >= F + PIXELS) {
369 if (++words == wordsperline) {
382void KXFace::UnCompAll(
char *fbuf)
389 while (p < F + PIXELS) {
392 UnCompress(F, 16, 16, 0);
393 UnCompress(F + 16, 16, 16, 0);
394 UnCompress(F + 32, 16, 16, 0);
395 UnCompress(F + WIDTH * 16, 16, 16, 0);
396 UnCompress(F + WIDTH * 16 + 16, 16, 16, 0);
397 UnCompress(F + WIDTH * 16 + 32, 16, 16, 0);
398 UnCompress(F + WIDTH * 32, 16, 16, 0);
399 UnCompress(F + WIDTH * 32 + 16, 16, 16, 0);
400 UnCompress(F + WIDTH * 32 + 32, 16, 16, 0);
403void KXFace::UnCompress(
char *f,
int wid,
int hei,
int lev)
405 switch (BigPop(&levels[lev][0])) {
409 PopGreys(f, wid, hei);
415 UnCompress(f, wid, hei, lev);
416 UnCompress(f + wid, wid, hei, lev);
417 UnCompress(f + hei * WIDTH, wid, hei, lev);
418 UnCompress(f + wid + hei * WIDTH, wid, hei, lev);
423void KXFace::BigWrite(
char *fbuf)
425 static unsigned char tmp;
426 static char buf[DIGITS];
431 while (B.b_words > 0) {
432 BigDiv(NUMPRINTS, &tmp);
433 *(s++) = tmp + FIRSTPRINT;
442 if (++i >= MAXLINELEN) {
453void KXFace::BigRead(
char *fbuf)
457 while (*fbuf !=
'\0') {
459 if ((c < FIRSTPRINT) || (c > LASTPRINT)) {
463 BigAdd((
unsigned char)(c - FIRSTPRINT));
467void KXFace::ReadFace(
char *fbuf)
475 for (i = strlen(s); i > 0; --i) {
477 if ((c >=
'0') && (c <=
'9')) {
478 if (t >= fbuf + DIGITS) {
483 }
else if ((c >=
'A') && (c <=
'F')) {
484 if (t >= fbuf + DIGITS) {
488 *(t++) = c -
'A' + 10;
489 }
else if ((c >=
'a') && (c <=
'f')) {
490 if (t >= fbuf + DIGITS) {
494 *(t++) = c -
'a' + 10;
495 }
else if (((c ==
'x') || (c ==
'X')) && (t > fbuf) && (*(t - 1) == 0)) {
499 if (t < fbuf + DIGITS) {
500 longjmp(comp_env, ERR_INSUFF);
504 c = 1 << (BITSPERDIG - 1);
505 while (t < F + PIXELS) {
506 *(t++) = (*s & c) ? 1 : 0;
507 if ((c >>= 1) == 0) {
509 c = 1 << (BITSPERDIG - 1);
514void KXFace::GenFace()
516 static char newp[PIXELS];
530void KXFace::UnGenFace()
536void KXFace::Gen(
char *f)
545 for (j = 0; j < HEIGHT; ++j) {
546 for (i = 0; i < WIDTH; ++i) {
549 for (l = i - 2; l <= i + 2; ++l) {
550 for (m = j - 2; m <= j; ++m) {
551 if ((l >= i) && (m == j)) {
554 if ((l > 0) && (l <= WIDTH) && (m > 0)) {
555 k = *(f + l + m * WIDTH) ? k * 2 + 1 : k * 2;
616void KXFace::PopGreys(
char *f,
int wid,
int hei)
621 PopGreys(f, wid, hei);
622 PopGreys(f + wid, wid, hei);
623 PopGreys(f + WIDTH * hei, wid, hei);
624 PopGreys(f + WIDTH * hei + wid, wid, hei);
637 *(f + WIDTH + 1) = 1;
642void KXFace::CompAll(
char *fbuf)
644 Compress(F, 16, 16, 0);
645 Compress(F + 16, 16, 16, 0);
646 Compress(F + 32, 16, 16, 0);
647 Compress(F + WIDTH * 16, 16, 16, 0);
648 Compress(F + WIDTH * 16 + 16, 16, 16, 0);
649 Compress(F + WIDTH * 16 + 32, 16, 16, 0);
650 Compress(F + WIDTH * 32, 16, 16, 0);
651 Compress(F + WIDTH * 32 + 16, 16, 16, 0);
652 Compress(F + WIDTH * 32 + 32, 16, 16, 0);
654 while (NumProbs > 0) {
655 BigPush(ProbBuf[--NumProbs]);
660void KXFace::Compress(
char *f,
int wid,
int hei,
int lev)
662 if (AllWhite(f, wid, hei)) {
663 RevPush(&levels[lev][WHITE]);
666 if (AllBlack(f, wid, hei)) {
667 RevPush(&levels[lev][BLACK]);
668 PushGreys(f, wid, hei);
671 RevPush(&levels[lev][GREY]);
675 Compress(f, wid, hei, lev);
676 Compress(f + wid, wid, hei, lev);
677 Compress(f + hei * WIDTH, wid, hei, lev);
678 Compress(f + wid + hei * WIDTH, wid, hei, lev);
681int KXFace::AllWhite(
char *f,
int wid,
int hei)
683 return (*f == 0) && Same(f, wid, hei);
686int KXFace::AllBlack(
char *f,
int wid,
int hei)
691 return AllBlack(f, wid, hei) && AllBlack(f + wid, wid, hei) && AllBlack(f + WIDTH * hei, wid, hei) && AllBlack(f + WIDTH * hei + wid, wid, hei);
693 return *f || *(f + 1) || *(f + WIDTH) || *(f + WIDTH + 1);
697int KXFace::Same(
char *f,
int wid,
int hei)
708 if (*(row++) != val) {
717void KXFace::PushGreys(
char *f,
int wid,
int hei)
722 PushGreys(f, wid, hei);
723 PushGreys(f + wid, wid, hei);
724 PushGreys(f + WIDTH * hei, wid, hei);
725 PushGreys(f + WIDTH * hei + wid, wid, hei);
727 RevPush(freqs + *f + 2 * *(f + 1) + 4 * *(f + WIDTH) + 8 * *(f + WIDTH + 1));
731#include "moc_kxface.cpp"
QString fromImage(const QImage &image)
generates the xface string from image
QImage toImage(const QString &xface)
creates a pixmap from xface
virtual bool open(OpenMode flags) override
const char * constData() const const
bool isNull() const const
bool loadFromData(QByteArrayView data, const char *format)
bool save(QIODevice *device, const char *format, int quality) const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QString fromLatin1(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QByteArray toLatin1() const const
void truncate(qsizetype position)