source: trunk/third/tiff/libtiff/tif_packbits.c @ 18174

Revision 18174, 7.5 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18173, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tiff/libtiff/tif_packbits.c,v 1.1.1.1 2002-12-26 02:39:07 ghudson Exp $ */
2
3/*
4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27#include "tiffiop.h"
28#ifdef PACKBITS_SUPPORT
29/*
30 * TIFF Library.
31 *
32 * PackBits Compression Algorithm Support
33 */
34#include <assert.h>
35#include <stdio.h>
36
37static int
38PackBitsPreEncode(TIFF* tif, tsample_t s)
39{
40        (void) s;
41        /*
42         * Calculate the scanline/tile-width size in bytes.
43         */
44        if (isTiled(tif))
45                tif->tif_data = (tidata_t) TIFFTileRowSize(tif);
46        else
47                tif->tif_data = (tidata_t) TIFFScanlineSize(tif);
48        return (1);
49}
50
51/*
52 * NB: tidata is the type representing *(tidata_t);
53 *     if tidata_t is made signed then this type must
54 *     be adjusted accordingly.
55 */
56typedef unsigned char tidata;
57
58/*
59 * Encode a run of pixels.
60 */
61static int
62PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
63{
64        u_char* bp = (u_char*) buf;
65        tidata_t op, ep, lastliteral;
66        long n, slop;
67        int b;
68        enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
69
70        (void) s;
71        op = tif->tif_rawcp;
72        ep = tif->tif_rawdata + tif->tif_rawdatasize;
73        state = BASE;
74        lastliteral = 0;
75        while (cc > 0) {
76                /*
77                 * Find the longest string of identical bytes.
78                 */
79                b = *bp++, cc--, n = 1;
80                for (; cc > 0 && b == *bp; cc--, bp++)
81                        n++;
82        again:
83                if (op + 2 >= ep) {             /* insure space for new data */
84                        /*
85                         * Be careful about writing the last
86                         * literal.  Must write up to that point
87                         * and then copy the remainder to the
88                         * front of the buffer.
89                         */
90                        if (state == LITERAL || state == LITERAL_RUN) {
91                                slop = op - lastliteral;
92                                tif->tif_rawcc += lastliteral - tif->tif_rawcp;
93                                if (!TIFFFlushData1(tif))
94                                        return (-1);
95                                op = tif->tif_rawcp;
96                                while (slop-- > 0)
97                                        *op++ = *lastliteral++;
98                                lastliteral = tif->tif_rawcp;
99                        } else {
100                                tif->tif_rawcc += op - tif->tif_rawcp;
101                                if (!TIFFFlushData1(tif))
102                                        return (-1);
103                                op = tif->tif_rawcp;
104                        }
105                }
106                switch (state) {
107                case BASE:              /* initial state, set run/literal */
108                        if (n > 1) {
109                                state = RUN;
110                                if (n > 128) {
111                                        *op++ = (tidata) -127;
112                                        *op++ = b;
113                                        n -= 128;
114                                        goto again;
115                                }
116                                *op++ = (tidataval_t)(-(n-1));
117                                *op++ = b;
118                        } else {
119                                lastliteral = op;
120                                *op++ = 0;
121                                *op++ = b;
122                                state = LITERAL;
123                        }
124                        break;
125                case LITERAL:           /* last object was literal string */
126                        if (n > 1) {
127                                state = LITERAL_RUN;
128                                if (n > 128) {
129                                        *op++ = (tidata) -127;
130                                        *op++ = b;
131                                        n -= 128;
132                                        goto again;
133                                }
134                                *op++ = (tidataval_t)(-(n-1));  /* encode run */
135                                *op++ = b;
136                        } else {                        /* extend literal */
137                                if (++(*lastliteral) == 127)
138                                        state = BASE;
139                                *op++ = b;
140                        }
141                        break;
142                case RUN:               /* last object was run */
143                        if (n > 1) {
144                                if (n > 128) {
145                                        *op++ = (tidata) -127;
146                                        *op++ = b;
147                                        n -= 128;
148                                        goto again;
149                                }
150                                *op++ = (tidataval_t)(-(n-1));
151                                *op++ = b;
152                        } else {
153                                lastliteral = op;
154                                *op++ = 0;
155                                *op++ = b;
156                                state = LITERAL;
157                        }
158                        break;
159                case LITERAL_RUN:       /* literal followed by a run */
160                        /*
161                         * Check to see if previous run should
162                         * be converted to a literal, in which
163                         * case we convert literal-run-literal
164                         * to a single literal.
165                         */
166                        if (n == 1 && op[-2] == (tidata) -1 &&
167                            *lastliteral < 126) {
168                                state = (((*lastliteral) += 2) == 127 ?
169                                    BASE : LITERAL);
170                                op[-2] = op[-1];        /* replicate */
171                        } else
172                                state = RUN;
173                        goto again;
174                }
175        }
176        tif->tif_rawcc += op - tif->tif_rawcp;
177        tif->tif_rawcp = op;
178        return (1);
179}
180
181/*
182 * Encode a rectangular chunk of pixels.  We break it up
183 * into row-sized pieces to insure that encoded runs do
184 * not span rows.  Otherwise, there can be problems with
185 * the decoder if data is read, for example, by scanlines
186 * when it was encoded by strips.
187 */
188static int
189PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
190{
191    tsize_t rowsize = (tsize_t) tif->tif_data;
192
193    assert(rowsize > 0);
194   
195#ifdef YCBCR_SUPPORT
196    /*
197     * YCBCR data isn't really separable into rows, so we
198     * might as well encode the whole tile/strip as one chunk.
199     */
200    if( tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR )
201        rowsize = (tsize_t) tif->tif_data;
202#endif
203
204    while ((long)cc > 0) {
205        int     chunk = rowsize;
206       
207        if( cc < chunk )
208            chunk = cc;
209
210        if (PackBitsEncode(tif, bp, chunk, s) < 0)
211            return (-1);
212        bp += chunk;
213        cc -= chunk;
214    }
215    return (1);
216}
217
218static int
219PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
220{
221        char *bp;
222        tsize_t cc;
223        long n;
224        int b;
225
226        (void) s;
227        bp = (char*) tif->tif_rawcp;
228        cc = tif->tif_rawcc;
229        while (cc > 0 && (long)occ > 0) {
230                n = (long) *bp++, cc--;
231                /*
232                 * Watch out for compilers that
233                 * don't sign extend chars...
234                 */
235                if (n >= 128)
236                        n -= 256;
237                if (n < 0) {            /* replicate next byte -n+1 times */
238                        if (n == -128)  /* nop */
239                                continue;
240                        n = -n + 1;
241                        if( occ < n )
242                        {
243                            TIFFWarning(tif->tif_name,
244                                        "PackBitsDecode: discarding %d bytes "
245                                        "to avoid buffer overrun",
246                                        n - occ);
247                            n = occ;
248                        }
249                        occ -= n;
250                        b = *bp++, cc--;
251                        while (n-- > 0)
252                                *op++ = b;
253                } else {                /* copy next n+1 bytes literally */
254                        if (occ < n + 1)
255                        {
256                            TIFFWarning(tif->tif_name,
257                                        "PackBitsDecode: discarding %d bytes "
258                                        "to avoid buffer overrun",
259                                        n - occ + 1);
260                            n = occ - 1;
261                        }
262                        _TIFFmemcpy(op, bp, ++n);
263                        op += n; occ -= n;
264                        bp += n; cc -= n;
265                }
266        }
267        tif->tif_rawcp = (tidata_t) bp;
268        tif->tif_rawcc = cc;
269        if (occ > 0) {
270                TIFFError(tif->tif_name,
271                    "PackBitsDecode: Not enough data for scanline %ld",
272                    (long) tif->tif_row);
273                return (0);
274        }
275        return (1);
276}
277
278int
279TIFFInitPackBits(TIFF* tif, int scheme)
280{
281        (void) scheme;
282        tif->tif_decoderow = PackBitsDecode;
283        tif->tif_decodestrip = PackBitsDecode;
284        tif->tif_decodetile = PackBitsDecode;
285        tif->tif_preencode = PackBitsPreEncode;
286        tif->tif_encoderow = PackBitsEncode;
287        tif->tif_encodestrip = PackBitsEncodeChunk;
288        tif->tif_encodetile = PackBitsEncodeChunk;
289        return (1);
290}
291#endif /* PACKBITS_SUPPORT */
Note: See TracBrowser for help on using the repository browser.