/* $Xorg: dfaxg42d.c,v 1.3 2000/08/17 19:46:40 cpqbld Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992 Sam Leffler * Copyright (c) 1991, 1992 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ /* $XFree86: xc/lib/lbxutil/image/dfaxg42d.c,v 1.5 2001/01/17 19:43:35 dawes Exp $ */ #include #include #include #include #include "g3states.h" #include "lbxfax.h" #include /* * ------------------------------------------------------------------------- * FAX G42D decoding for 1 bit images * ------------------------------------------------------------------------- */ static short sp_data, sp_bit; /* * Fetch a byte from the input stream */ static unsigned char fetchByte (unsigned char **inbuf) { unsigned char byte = **inbuf; (*inbuf)++; return (byte); } /* * Decode a run of white. */ static int decode_white_run (unsigned char **inbuf) { short state = sp_bit; short action; int runlen = 0; for (;;) { if (sp_bit == 0) { nextbyte: sp_data = fetchByte (inbuf); } action = TIFFFax1DAction[state][sp_data]; state = TIFFFax1DNextState[state][sp_data]; if (action == ACT_INCOMP) goto nextbyte; if (action == ACT_INVALID) return (G3CODE_INVALID); if (action == ACT_EOL) return (G3CODE_EOL); sp_bit = state; action = RUNLENGTH(action - ACT_WRUNT); runlen += action; if (action < 64) return (runlen); } } /* * Decode a run of black. */ static int decode_black_run (unsigned char **inbuf) { short state = sp_bit + 8; short action; int runlen = 0; for (;;) { if (sp_bit == 0) { nextbyte: sp_data = fetchByte (inbuf); } action = TIFFFax1DAction[state][sp_data]; state = TIFFFax1DNextState[state][sp_data]; if (action == ACT_INCOMP) goto nextbyte; if (action == ACT_INVALID) return (G3CODE_INVALID); if (action == ACT_EOL) return (G3CODE_EOL); sp_bit = state; action = RUNLENGTH(action - ACT_BRUNT); runlen += action; if (action < 64) return (runlen); state += 8; } } /* * Return the next uncompressed mode code word. */ static int decode_uncomp_code (unsigned char **inbuf) { short code; do { if (sp_bit == 0 || sp_bit > 7) sp_data = fetchByte (inbuf); code = TIFFFaxUncompAction[sp_bit][sp_data]; sp_bit = TIFFFaxUncompNextState[sp_bit][sp_data]; } while (code == ACT_INCOMP); return (code); } /* * Fill a span with ones. */ static void fillspan (char *cp, int x, int count) { static unsigned char masks[] = { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; if (count <= 0) return; cp += x>>3; if (x &= 7) { /* align to byte boundary */ if (count < 8 - x) { *cp++ |= masks[count] >> x; return; } *cp++ |= 0xff >> x; count -= 8 - x; } while (count >= 8) { *cp++ = (char)0xff; count -= 8; } *cp |= masks[count]; } /* * Return the next bit in the input stream. This is * used to extract 2D tag values and the color tag * at the end of a terminating uncompressed data code. */ static int nextbit (unsigned char **inbuf) { static unsigned char bitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; int bit; if (sp_bit == 0) sp_data = fetchByte (inbuf); bit = sp_data & bitMask[sp_bit]; if (++(sp_bit) > 7) sp_bit = 0; return (bit); } static int DecodeFaxG42D (unsigned char **inbuf, unsigned char *refline, int pixels_per_line, unsigned char *outbuf) { int a0 = -1; int b1, b2; int run1, run2; /* for horizontal mode */ short mode; short color = 1; do { if (sp_bit == 0 || sp_bit > 7) sp_data = fetchByte (inbuf); mode = TIFFFax2DMode[sp_bit][sp_data]; sp_bit = TIFFFax2DNextState[sp_bit][sp_data]; switch (mode) { case MODE_NULL: break; case MODE_PASS: b2 = LbxImageFindDiff (refline, a0, pixels_per_line, !color); b1 = LbxImageFindDiff (refline, b2, pixels_per_line, color); b2 = LbxImageFindDiff (refline, b1, pixels_per_line, !color); if (color) { if (a0 < 0) a0 = 0; fillspan ((char *) outbuf, a0, b2 - a0); } a0 = b2; break; case MODE_HORIZ: if (color == 1) { run1 = decode_white_run (inbuf); run2 = decode_black_run (inbuf); } else { run1 = decode_black_run (inbuf); run2 = decode_white_run (inbuf); } /* * Do the appropriate fill. Note that we exit this logic with * the same color that we enter with since we do 2 fills. This * explains the somewhat obscure logic below. */ if (a0 < 0) a0 = 0; if (a0 + run1 > pixels_per_line) run1 = pixels_per_line - a0; if (color) fillspan ((char *) outbuf, a0, run1); a0 += run1; if (a0 + run2 > pixels_per_line) run2 = pixels_per_line - a0; if (!color) fillspan ((char *) outbuf, a0, run2); a0 += run2; break; case MODE_VERT_V0: case MODE_VERT_VR1: case MODE_VERT_VR2: case MODE_VERT_VR3: case MODE_VERT_VL1: case MODE_VERT_VL2: case MODE_VERT_VL3: b2 = LbxImageFindDiff (refline, a0, pixels_per_line, !color); b1 = LbxImageFindDiff (refline, b2, pixels_per_line, color); b1 += mode - MODE_VERT_V0; if (color) { if (a0 < 0) a0 = 0; fillspan ((char *) outbuf, a0, b1 - a0); } color = !color; a0 = b1; break; case MODE_UNCOMP: /* * Uncompressed mode: select from the special set of code words. */ if (a0 < 0) a0 = 0; do { mode = decode_uncomp_code (inbuf); switch (mode) { case UNCOMP_RUN1: case UNCOMP_RUN2: case UNCOMP_RUN3: case UNCOMP_RUN4: case UNCOMP_RUN5: run1 = mode - UNCOMP_RUN0; fillspan ((char *) outbuf, a0+run1-1, 1); a0 += run1; break; case UNCOMP_RUN6: a0 += 5; break; case UNCOMP_TRUN0: case UNCOMP_TRUN1: case UNCOMP_TRUN2: case UNCOMP_TRUN3: case UNCOMP_TRUN4: run1 = mode - UNCOMP_TRUN0; a0 += run1; color = nextbit (inbuf) ? 0 : 1; break; case UNCOMP_INVALID: goto bad; case UNCOMP_EOF: return (0); } } while (mode < UNCOMP_EXIT); break; case MODE_ERROR_1: /* fall thru... */ case MODE_ERROR: goto bad; default: return (0); } } while (a0 < pixels_per_line); bad: return (a0 >= pixels_per_line); } int LbxImageDecodeFaxG42D (unsigned char *inbuf, unsigned char *outbuf, int image_bytes, int pixels_per_line, int padded_bytes_per_scanline, int reverse_bits) { int bytes_per_scanline = ROUNDUP8 (pixels_per_line); unsigned char *refline, *refptr; unsigned char *outbuf_start = outbuf; int bytes_left = image_bytes; int i; refline = (unsigned char *) malloc (bytes_per_scanline + 1); refptr = refline + 1; for (i = 0; i < bytes_per_scanline + 1; i++) refline[i] = 0xff; bzero (outbuf, image_bytes); sp_bit = 0; sp_data = 0; while (bytes_left > 0) { if (!DecodeFaxG42D (&inbuf, refptr, pixels_per_line, outbuf)) return (0); memcpy (refptr, outbuf, bytes_per_scanline); outbuf += padded_bytes_per_scanline; bytes_left -= padded_bytes_per_scanline; } free ((char *) refline); if (reverse_bits) LbxReverseBits (outbuf_start, image_bytes); return (outbuf - outbuf_start); }