📄 jbig.c
字号:
/* * Portable Free JBIG image compression library * * Markus Kuhn -- mkuhn@acm.org * * $Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $ * * This module implements a portable standard C encoder and decoder * using the JBIG lossless bi-level image compression algorithm as * specified in International Standard ISO 11544:1993 or equivalently * as specified in ITU-T Recommendation T.82. See the file jbig.doc * for usage instructions and application examples. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * If you want to use this program under different license conditions, * then contact the author for an arrangement. * * It is possible that certain products which can be built using this * software module might form inventions protected by patent rights in * some countries (e.g., by patents about arithmetic coding algorithms * owned by IBM and AT&T in the USA). Provision of this software by the * author does NOT include any licences for any patents. In those * countries where a patent licence is required for certain applications * of this software module, you will have to obtain such a licence * yourself. */#ifdef DEBUG#include <stdio.h>#endif#include <stdlib.h>#include <assert.h>#include "jbig.h"/* optional export of arithmetic coder functions for test purposes */#ifdef TEST_CODEC#define ARITH#define ARITH_INL#else#define ARITH static#ifdef __GNUC__#define ARITH_INL static __inline__#else#define ARITH_INL static#endif#endif#define MX_MAX 23 /* maximal supported mx offset for * adaptive template in the encoder */#define TPB2CX 0x195 /* contexts for TP special pixels */#define TPB3CX 0x0e5#define TPDCX 0xc3f/* marker codes */#define MARKER_STUFF 0x00#define MARKER_RESERVE 0x01#define MARKER_SDNORM 0x02#define MARKER_SDRST 0x03#define MARKER_ABORT 0x04#define MARKER_NEWLEN 0x05#define MARKER_ATMOVE 0x06#define MARKER_COMMENT 0x07#define MARKER_ESC 0xff/* loop array indices */#define STRIPE 0#define LAYER 1#define PLANE 2/* special jbg_buf pointers (instead of NULL) */#define SDE_DONE ((struct jbg_buf *) -1)#define SDE_TODO ((struct jbg_buf *) 0)/* object code version id */const char jbg_version[] = " JBIG-KIT " JBG_VERSION " -- Markus Kuhn -- ""$Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $ ";/* * the following array specifies for each combination of the 3 * ordering bits, which ii[] variable represents which dimension * of s->sde. */static const int index[8][3] = { { 2, 1, 0 }, /* no ordering bit set */ { -1, -1, -1}, /* SMID -> illegal combination */ { 2, 0, 1 }, /* ILEAVE */ { 1, 0, 2 }, /* SMID + ILEAVE */ { 0, 2, 1 }, /* SEQ */ { 1, 2, 0 }, /* SEQ + SMID */ { 0, 1, 2 }, /* SEQ + ILEAVE */ { -1, -1, -1 } /* SEQ + SMID + ILEAVE -> illegal combination */};/* * Array [language][message] with text string error messages that correspond * to return values from public functions in this library. */#define NEMSG 9 /* number of error codes */#define NEMSG_LANG 3 /* number of supported languages */static const char *errmsg[NEMSG_LANG][NEMSG] = { /* English (JBG_EN) */ { "Everything is ok", /* JBG_EOK */ "Reached specified maximum size", /* JBG_EOK_INTR */ "Unexpected end of data", /* JBG_EAGAIN */ "Not enough memory available", /* JBG_ENOMEM */ "ABORT marker found", /* JBG_EABORT */ "Unknown marker segment encountered", /* JBG_EMARKER */ "Incremental BIE does not fit to previous one", /* JBG_ENOCONT */ "Invalid data encountered", /* JBG_EINVAL */ "Unimplemented features used" /* JBG_EIMPL */ }, /* German (JBG_DE_8859_1) */ { "Kein Problem aufgetreten", /* JBG_EOK */ "Angegebene maximale Bildgr\366\337e erreicht", /* JBG_EOK_INTR */ "Unerwartetes Ende der Daten", /* JBG_EAGAIN */ "Nicht gen\374gend Speicher vorhanden", /* JBG_ENOMEM */ "Es wurde eine Abbruch-Sequenz gefunden", /* JBG_EABORT */ "Eine unbekannte Markierungssequenz wurde gefunden", /* JBG_EMARKER */ "Neue Daten passen nicht zu vorangegangenen Daten", /* JBG_ENOCONT */ "Es wurden ung\374ltige Daten gefunden", /* JBG_EINVAL */ "Noch nicht implementierte Optionen wurden benutzt" /* JBG_EIMPL */ }, /* German (JBG_DE_UTF_8) */ { "Kein Problem aufgetreten", /* JBG_EOK */ "Angegebene maximale Bildgr\303\266\303\237e erreicht", /* JBG_EOK_INTR */ "Unerwartetes Ende der Daten", /* JBG_EAGAIN */ "Nicht gen\303\274gend Speicher vorhanden", /* JBG_ENOMEM */ "Es wurde eine Abbruch-Sequenz gefunden", /* JBG_EABORT */ "Eine unbekannte Markierungssequenz wurde gefunden", /* JBG_EMARKER */ "Neue Daten passen nicht zu vorangegangenen Daten", /* JBG_ENOCONT */ "Es wurden ung\303\274ltige Daten gefunden", /* JBG_EINVAL */ "Noch nicht implementierte Optionen wurden benutzt" /* JBG_EIMPL */ }};/* * The following three functions are the only places in this code, were * C library memory management functions are called. The whole JBIG * library has been designed in order to allow multi-threaded * execution. no static or global variables are used, so all fuctions * are fully reentrant. However if you want to use this multi-thread * capability and your malloc, realloc and free are not reentrant, * then simply add the necessary semaphores or mutex primitives below. */static void *checked_malloc(size_t size){ void *p; p = malloc(size); /* Full manual exception handling is ugly here for performance * reasons. If an adequate handling of lack of memory is required, * then use C++ and throw a C++ exception here. */ if (!p) abort();#if 0 fprintf(stderr, "%p = malloc(%ld)\n", p, (long) size);#endif return p;}static void *checked_realloc(void *ptr, size_t size){ void *p; p = realloc(ptr, size); /* Full manual exception handling is ugly here for performance * reasons. If an adequate handling of lack of memory is required, * then use C++ and throw a C++ exception here. */ if (!p) abort();#if 0 fprintf(stderr, "%p = realloc(%p, %ld)\n", p, ptr, (long) size);#endif return p;}static void checked_free(void *ptr){ free(ptr);#if 0 fprintf(stderr, "free(%p)\n", ptr);#endif}/* * The next functions implement the arithmedic encoder and decoder * required for JBIG. The same algorithm is also used in the arithmetic * variant of JPEG. */#ifdef DEBUGstatic long encoded_pixels = 0;#endifARITH void arith_encode_init(struct jbg_arenc_state *s, int reuse_st){ int i; if (!reuse_st) for (i = 0; i < 4096; s->st[i++] = 0); s->c = 0; s->a = 0x10000L; s->sc = 0; s->ct = 11; s->buffer = -1; /* empty */ return;}ARITH void arith_encode_flush(struct jbg_arenc_state *s){ unsigned long temp;#ifdef DEBUG fprintf(stderr, " encoded pixels = %ld, a = %05lx, c = %08lx\n", encoded_pixels, s->a, s->c);#endif /* find the s->c in the coding interval with the largest * number of trailing zero bits */ if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c) s->c = temp + 0x8000; else s->c = temp; /* send remaining bytes to output */ s->c <<= s->ct; if (s->c & 0xf8000000L) { /* one final overflow has to be handled */ if (s->buffer >= 0) { s->byte_out(s->buffer + 1, s->file); if (s->buffer + 1 == MARKER_ESC) s->byte_out(MARKER_STUFF, s->file); } /* output 0x00 bytes only when more non-0x00 will follow */ if (s->c & 0x7fff800L) for (; s->sc; --s->sc) s->byte_out(0x00, s->file); } else { if (s->buffer >= 0) s->byte_out(s->buffer, s->file); /* T.82 figure 30 says buffer+1 for the above line! Typo? */ for (; s->sc; --s->sc) { s->byte_out(0xff, s->file); s->byte_out(MARKER_STUFF, s->file); } } /* output final bytes only if they are not 0x00 */ if (s->c & 0x7fff800L) { s->byte_out((s->c >> 19) & 0xff, s->file); if (((s->c >> 19) & 0xff) == MARKER_ESC) s->byte_out(MARKER_STUFF, s->file); if (s->c & 0x7f800L) { s->byte_out((s->c >> 11) & 0xff, s->file); if (((s->c >> 11) & 0xff) == MARKER_ESC) s->byte_out(MARKER_STUFF, s->file); } } return;}ARITH_INL void arith_encode(struct jbg_arenc_state *s, int cx, int pix) { extern short jbg_lsz[]; extern unsigned char jbg_nmps[], jbg_nlps[]; register unsigned lsz, ss; register unsigned char *st; long temp;#ifdef DEBUG ++encoded_pixels;#endif assert(cx >= 0 && cx < 4096); st = s->st + cx; ss = *st & 0x7f; assert(ss < 113); lsz = jbg_lsz[ss];#if 0 fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, " "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n", pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct, s->buffer);#endif if (((pix << 7) ^ s->st[cx]) & 0x80) { /* encode the less probable symbol */ if ((s->a -= lsz) >= lsz) { /* If the interval size (lsz) for the less probable symbol (LPS) * is larger than the interval size for the MPS, then exchange * the two symbols for coding efficiency, otherwise code the LPS * as usual: */ s->c += s->a; s->a = lsz; } /* Check whether MPS/LPS exchange is necessary * and chose next probability estimator status */ *st &= 0x80; *st ^= jbg_nlps[ss]; } else { /* encode the more probable symbol */ if ((s->a -= lsz) & 0xffff8000L) return; /* A >= 0x8000 -> ready, no renormalization required */ if (s->a < lsz) { /* If the interval size (lsz) for the less probable symbol (LPS) * is larger than the interval size for the MPS, then exchange * the two symbols for coding efficiency: */ s->c += s->a; s->a = lsz; } /* chose next probability estimator status */ *st &= 0x80; *st |= jbg_nmps[ss]; } /* renormalization of coding interval */ do { s->a <<= 1; s->c <<= 1; --s->ct; if (s->ct == 0) { /* another byte is ready for output */ temp = s->c >> 19; if (temp & 0xffffff00L) { /* handle overflow over all buffered 0xff bytes */ if (s->buffer >= 0) { ++s->buffer; s->byte_out(s->buffer, s->file); if (s->buffer == MARKER_ESC) s->byte_out(MARKER_STUFF, s->file); } for (; s->sc; --s->sc) s->byte_out(0x00, s->file); s->buffer = temp & 0xff; /* new output byte, might overflow later */ assert(s->buffer != 0xff); /* can s->buffer really never become 0xff here? */ } else if (temp == 0xff) { /* buffer 0xff byte (which might overflow later) */ ++s->sc; } else { /* output all buffered 0xff bytes, they will not overflow any more */ if (s->buffer >= 0) s->byte_out(s->buffer, s->file); for (; s->sc; --s->sc) { s->byte_out(0xff, s->file); s->byte_out(MARKER_STUFF, s->file); } s->buffer = temp; /* buffer new output byte (can still overflow) */ } s->c &= 0x7ffffL; s->ct = 8; } } while (s->a < 0x8000); return;}ARITH void arith_decode_init(struct jbg_ardec_state *s, int reuse_st){ int i; if (!reuse_st) for (i = 0; i < 4096; s->st[i++] = 0); s->c = 0; s->a = 1; s->ct = 0; s->result = JBG_OK; s->startup = 1; return;}ARITH_INL int arith_decode(struct jbg_ardec_state *s, int cx){ extern short jbg_lsz[]; extern unsigned char jbg_nmps[], jbg_nlps[]; register unsigned lsz, ss; register unsigned char *st; int pix; /* renormalization */ while (s->a < 0x8000 || s->startup) { if (s->ct < 1 && s->result != JBG_READY) { /* first we have to move a new byte into s->c */ if (s->pscd_ptr >= s->pscd_end) { s->result = JBG_MORE; return -1; } if (*s->pscd_ptr == 0xff) if (s->pscd_ptr + 1 >= s->pscd_end) { s->result = JBG_MARKER; return -1; } else { if (*(s->pscd_ptr + 1) == MARKER_STUFF) { s->c |= 0xffL << (8 - s->ct); s->ct += 8; s->pscd_ptr += 2; s->result = JBG_OK; } else s->result = JBG_READY; } else { s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -