/* $Xorg: epackbits.c,v 1.4 2000/08/17 19:46:41 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. */ #include #include /* * ------------------------------------------------------------------------- * PackBits encoding for 8 bit color images * ------------------------------------------------------------------------- */ #define PutByte(byte,bufptr,bytesLeft) \ { \ if (*bytesLeft < 1) {\ *outbuf = outptr; \ return (0); \ } \ *bufptr++ = byte; \ (*bytesLeft)--; \ } static int EncodePackBits (char *inbuf, int numPixels, char **outbuf, int *bytesLeft) { register int pixelsLeft = numPixels; register char *outptr = *outbuf; register char *lastliteral; register int n, b; enum { BASE, LITERAL, RUN, LITERAL_RUN } state; state = BASE; lastliteral = 0; while (pixelsLeft > 0) { /* * Find the longest string of identical bytes. */ b = *inbuf++, pixelsLeft--, n = 1; for (; pixelsLeft > 0 && b == *inbuf; pixelsLeft--, inbuf++) n++; again: switch (state) { case BASE: /* initial state, set run/literal */ if (n > 1) { state = RUN; if (n > 128) { PutByte (-127, outptr, bytesLeft); PutByte (b, outptr, bytesLeft); n -= 128; goto again; } PutByte (-(n-1), outptr, bytesLeft); PutByte (b, outptr, bytesLeft); } else { lastliteral = outptr; PutByte (0, outptr, bytesLeft); PutByte (b, outptr, bytesLeft); state = LITERAL; } break; case LITERAL: /* last object was literal string */ if (n > 1) { state = LITERAL_RUN; if (n > 128) { PutByte (-127, outptr, bytesLeft); PutByte (b, outptr, bytesLeft); n -= 128; goto again; } PutByte (-(n-1), outptr, bytesLeft); /* encode run */ PutByte (b, outptr, bytesLeft); } else { /* extend literal */ if (++(*lastliteral) == 127) state = BASE; PutByte (b, outptr, bytesLeft); } break; case RUN: /* last object was run */ if (n > 1) { if (n > 128) { PutByte (-127, outptr, bytesLeft); PutByte (b, outptr, bytesLeft); n -= 128; goto again; } PutByte (-(n-1), outptr, bytesLeft); PutByte (b, outptr, bytesLeft); } else { lastliteral = outptr; PutByte (0, outptr, bytesLeft); PutByte (b, outptr, bytesLeft); state = LITERAL; } break; case LITERAL_RUN: /* literal followed by a run */ /* * Check to see if previous run should * be converted to a literal, in which * case we convert literal-run-literal * to a single literal. */ if (n == 1 && outptr[-2] == (char)-1 && *lastliteral < 126) { state = (((*lastliteral) += 2) == 127 ? BASE : LITERAL); outptr[-2] = outptr[-1]; /* replicate */ } else state = RUN; goto again; } } *outbuf = outptr; return (1); } int LbxImageEncodePackBits (char *inbuf, char *outbuf, int outbufSize, int format, int depth, int num_scan_lines, int scan_line_size, int *bytesCompressed) { char *outbuf_start = outbuf; int padded_scan_line_size = (scan_line_size % 4) ? scan_line_size + (4 - scan_line_size % 4) : scan_line_size; int bytesLeft = outbufSize; while (num_scan_lines > 0) { if (!EncodePackBits (inbuf, scan_line_size, &outbuf, &bytesLeft)) return (LBX_IMAGE_COMPRESS_NOT_WORTH_IT); inbuf += padded_scan_line_size; num_scan_lines--; } *bytesCompressed = outbuf - outbuf_start; return (LBX_IMAGE_COMPRESS_SUCCESS); }