OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tk/] [generic/] [tkImgGIF.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkImgGIF.c --
3
 *
4
 *      A photo image file handler for GIF files. Reads 87a and 89a GIF
5
 *      files. At present there is no write function.  GIF images may be
6
 *      read using the -data option of the photo image.  The data may be
7
 *      given as a binary string in a Tcl_Obj or by representing
8
 *      the data as BASE64 encoded ascii.  Derived from the giftoppm code
9
 *      found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
10
 *      distribution.
11
 *
12
 * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
13
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
14
 * Copyright (c) 1997 Australian National University
15
 *
16
 * See the file "license.terms" for information on usage and redistribution
17
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18
 *
19
 * This file also contains code from the giftoppm program, which is
20
 * copyrighted as follows:
21
 *
22
 * +-------------------------------------------------------------------+
23
 * | Copyright 1990, David Koblas.                                     |
24
 * |   Permission to use, copy, modify, and distribute this software   |
25
 * |   and its documentation for any purpose and without fee is hereby |
26
 * |   granted, provided that the above copyright notice appear in all |
27
 * |   copies and that both that copyright notice and this permission  |
28
 * |   notice appear in supporting documentation.  This software is    |
29
 * |   provided "as is" without express or implied warranty.           |
30
 * +-------------------------------------------------------------------+
31
 *
32
 * RCS: @(#) $Id: tkImgGIF.c,v 1.1.1.1 2002-01-16 10:25:52 markom Exp $
33
 */
34
 
35
/*
36
 * GIF's are represented as data in base64 format.
37
 * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes.
38
 * A-Z, a-z, 0-9, + and / represent the 64 values (in order).
39
 * '=' is a trailing padding char when the un-encoded data is not a
40
 * multiple of 3 bytes.  We'll ignore white space when encountered.
41
 * Any other invalid character is treated as an EOF
42
 */
43
 
44
#define GIF_SPECIAL      (256)
45
#define GIF_PAD         (GIF_SPECIAL+1)
46
#define GIF_SPACE       (GIF_SPECIAL+2)
47
#define GIF_BAD         (GIF_SPECIAL+3)
48
#define GIF_DONE        (GIF_SPECIAL+4)
49
 
50
/*
51
 * structure to "mimic" FILE for Mread, so we can look like fread.
52
 * The decoder state keeps track of which byte we are about to read,
53
 * or EOF.
54
 */
55
 
56
typedef struct mFile {
57
    unsigned char *data;        /* mmencoded source string */
58
    int c;                      /* bits left over from previous character */
59
    int state;                  /* decoder state (0-4 or GIF_DONE) */
60
} MFile;
61
 
62
#include "tkInt.h"
63
#include "tkPort.h"
64
 
65
/*
66
 * The format record for the GIF file format:
67
 */
68
 
69
static int      FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName,
70
                    char *formatString, int *widthPtr, int *heightPtr));
71
static int      FileReadGIF  _ANSI_ARGS_((Tcl_Interp *interp,
72
                    Tcl_Channel chan, char *fileName, char *formatString,
73
                    Tk_PhotoHandle imageHandle, int destX, int destY,
74
                    int width, int height, int srcX, int srcY));
75
static int      StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj,
76
                    char *formatString, int *widthPtr, int *heightPtr));
77
static int      StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj,
78
                    char *formatString, Tk_PhotoHandle imageHandle,
79
                    int destX, int destY, int width, int height,
80
                    int srcX, int srcY));
81
 
82
Tk_PhotoImageFormat tkImgFmtGIF = {
83
        "GIF",                  /* name */
84
        FileMatchGIF,   /* fileMatchProc */
85
        StringMatchGIF, /* stringMatchProc */
86
        FileReadGIF,    /* fileReadProc */
87
        StringReadGIF,  /* stringReadProc */
88
        NULL,           /* fileWriteProc */
89
        NULL,           /* stringWriteProc */
90
};
91
 
92
#define INTERLACE               0x40
93
#define LOCALCOLORMAP           0x80
94
#define BitSet(byte, bit)       (((byte) & (bit)) == (bit))
95
#define MAXCOLORMAPSIZE         256
96
#define CM_RED                  0
97
#define CM_GREEN                1
98
#define CM_BLUE                 2
99
#define CM_ALPHA                3
100
#define MAX_LWZ_BITS            12
101
#define LM_to_uint(a,b)         (((b)<<8)|(a))
102
#define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)
103
 
104
/*
105
 *                       HACK ALERT!!  HACK ALERT!!  HACK ALERT!!
106
 * This code is hard-wired for reading from files.  In order to read
107
 * from a data stream, we'll trick fread so we can reuse the same code.
108
 * 0==from file; 1==from base64 encoded data; 2==from binary data
109
 */
110
 
111
static int fromData=0;
112
 
113
/*
114
 * Prototypes for local procedures defined in this file:
115
 */
116
 
117
static int              DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label,
118
                            int *transparent));
119
static int              GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size,
120
                            int flag));
121
static int              GetDataBlock _ANSI_ARGS_((Tcl_Channel chan,
122
                            unsigned char *buf));
123
static int              LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag,
124
                            int input_code_size));
125
static int              ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number,
126
                            unsigned char buffer[MAXCOLORMAPSIZE][4]));
127
static int              ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan,
128
                            int *widthPtr, int *heightPtr));
129
static int              ReadImage _ANSI_ARGS_((Tcl_Interp *interp,
130
                            char *imagePtr, Tcl_Channel chan,
131
                            int len, int rows,
132
                            unsigned char cmap[MAXCOLORMAPSIZE][4],
133
                            int width, int height, int srcX, int srcY,
134
                            int interlace, int transparent));
135
 
136
/*
137
 * these are for the BASE64 image reader code only
138
 */
139
 
140
static int              Fread _ANSI_ARGS_((unsigned char *dst, size_t size,
141
                            size_t count, Tcl_Channel chan));
142
static int              Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
143
                            size_t count, MFile *handle));
144
static int              Mgetc _ANSI_ARGS_((MFile *handle));
145
static int              char64 _ANSI_ARGS_((int c));
146
static void             mInit _ANSI_ARGS_((unsigned char *string,
147
                            MFile *handle));
148
 
149
/*
150
 *----------------------------------------------------------------------
151
 *
152
 * FileMatchGIF --
153
 *
154
 *      This procedure is invoked by the photo image type to see if
155
 *      a file contains image data in GIF format.
156
 *
157
 * Results:
158
 *      The return value is 1 if the first characters in file f look
159
 *      like GIF data, and 0 otherwise.
160
 *
161
 * Side effects:
162
 *      The access position in f may change.
163
 *
164
 *----------------------------------------------------------------------
165
 */
166
 
167
static int
168
FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr)
169
    Tcl_Channel chan;           /* The image file, open for reading. */
170
    char *fileName;             /* The name of the image file. */
171
    char *formatString;         /* User-specified format string, or NULL. */
172
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
173
                                 * returned here if the file is a valid
174
                                 * raw GIF file. */
175
{
176
        return ReadGIFHeader(chan, widthPtr, heightPtr);
177
}
178
 
179
/*
180
 *----------------------------------------------------------------------
181
 *
182
 * FileReadGIF --
183
 *
184
 *      This procedure is called by the photo image type to read
185
 *      GIF format data from a file and write it into a given
186
 *      photo image.
187
 *
188
 * Results:
189
 *      A standard TCL completion code.  If TCL_ERROR is returned
190
 *      then an error message is left in interp->result.
191
 *
192
 * Side effects:
193
 *      The access position in file f is changed, and new data is
194
 *      added to the image given by imageHandle.
195
 *
196
 *----------------------------------------------------------------------
197
 */
198
 
199
static int
200
FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY,
201
        width, height, srcX, srcY)
202
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
203
    Tcl_Channel chan;           /* The image file, open for reading. */
204
    char *fileName;             /* The name of the image file. */
205
    char *formatString;         /* User-specified format string, or NULL. */
206
    Tk_PhotoHandle imageHandle; /* The photo image to write into. */
207
    int destX, destY;           /* Coordinates of top-left pixel in
208
                                 * photo image to be written to. */
209
    int width, height;          /* Dimensions of block of photo image to
210
                                 * be written to. */
211
    int srcX, srcY;             /* Coordinates of top-left pixel to be used
212
                                 * in image being read. */
213
{
214
    int fileWidth, fileHeight;
215
    int nBytes;
216
    Tk_PhotoImageBlock block;
217
    unsigned char buf[100];
218
    int bitPixel;
219
    unsigned char colorMap[MAXCOLORMAPSIZE][4];
220
    int transparent = -1;
221
 
222
    if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) {
223
        Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
224
                fileName, "\"", NULL);
225
        return TCL_ERROR;
226
    }
227
    if ((fileWidth <= 0) || (fileHeight <= 0)) {
228
        Tcl_AppendResult(interp, "GIF image file \"", fileName,
229
                "\" has dimension(s) <= 0", (char *) NULL);
230
        return TCL_ERROR;
231
    }
232
 
233
    if (Fread(buf, 1, 3, chan) != 3) {
234
        return TCL_OK;
235
    }
236
    bitPixel = 2<<(buf[0]&0x07);
237
 
238
    if (BitSet(buf[0], LOCALCOLORMAP)) {    /* Global Colormap */
239
        if (!ReadColorMap(chan, bitPixel, colorMap)) {
240
            Tcl_AppendResult(interp, "error reading color map",
241
                    (char *) NULL);
242
            return TCL_ERROR;
243
        }
244
    }
245
 
246
    if ((srcX + width) > fileWidth) {
247
        width = fileWidth - srcX;
248
    }
249
    if ((srcY + height) > fileHeight) {
250
        height = fileHeight - srcY;
251
    }
252
    if ((width <= 0) || (height <= 0)
253
            || (srcX >= fileWidth) || (srcY >= fileHeight)) {
254
        return TCL_OK;
255
    }
256
 
257
    Tk_PhotoExpand(imageHandle, destX + width, destY + height);
258
 
259
    block.width = width;
260
    block.height = height;
261
    block.pixelSize = 4;
262
    block.pitch = block.pixelSize * block.width;
263
    block.offset[0] = 0;
264
    block.offset[1] = 1;
265
    block.offset[2] = 2;
266
    nBytes = height * block.pitch;
267
    block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
268
 
269
    while (1) {
270
        if (Fread(buf, 1, 1, chan) != 1) {
271
            /*
272
             * Premature end of image.  We should really notify
273
             * the user, but for now just show garbage.
274
             */
275
 
276
            break;
277
        }
278
 
279
        if (buf[0] == ';') {
280
            /*
281
             * GIF terminator.
282
             */
283
 
284
            break;
285
        }
286
 
287
        if (buf[0] == '!') {
288
            /*
289
             * This is a GIF extension.
290
             */
291
 
292
            if (Fread(buf, 1, 1, chan) != 1) {
293
                interp->result =
294
                        "error reading extension function code in GIF image";
295
                goto error;
296
            }
297
            if (DoExtension(chan, buf[0], &transparent) < 0) {
298
                interp->result = "error reading extension in GIF image";
299
                goto error;
300
            }
301
            continue;
302
        }
303
 
304
        if (buf[0] != ',') {
305
            /*
306
             * Not a valid start character; ignore it.
307
             */
308
            continue;
309
        }
310
 
311
        if (Fread(buf, 1, 9, chan) != 9) {
312
            interp->result = "couldn't read left/top/width/height in GIF image";
313
            goto error;
314
        }
315
 
316
        bitPixel = 1<<((buf[8]&0x07)+1);
317
 
318
        if (BitSet(buf[8], LOCALCOLORMAP)) {
319
            if (!ReadColorMap(chan, bitPixel, colorMap)) {
320
                    Tcl_AppendResult(interp, "error reading color map",
321
                            (char *) NULL);
322
                    goto error;
323
            }
324
        }
325
        if (ReadImage(interp, (char *) block.pixelPtr, chan, width,
326
                height, colorMap, fileWidth, fileHeight, srcX, srcY,
327
                BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
328
            goto error;
329
        }
330
        break;
331
   }
332
 
333
    if (transparent == -1) {
334
        Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height);
335
    } else {
336
        int x, y, end;
337
        unsigned char *imagePtr, *rowPtr, *pixelPtr;
338
 
339
        imagePtr = rowPtr = block.pixelPtr;
340
        for (y = 0; y < height; y++) {
341
            x = 0;
342
            pixelPtr = rowPtr;
343
            while(x < width) {
344
                /* search for first non-transparent pixel */
345
                while ((x < width) && !(pixelPtr[CM_ALPHA])) {
346
                    x++; pixelPtr += 4;
347
                }
348
                end = x;
349
                /* search for first transparent pixel */
350
                while ((end < width) && pixelPtr[CM_ALPHA]) {
351
                    end++; pixelPtr += 4;
352
                }
353
                if (end > x) {
354
                    block.pixelPtr = rowPtr + 4 * x;
355
                    Tk_PhotoPutBlock(imageHandle, &block, destX+x,
356
                            destY+y, end-x, 1);
357
                }
358
                x = end;
359
            }
360
            rowPtr += block.pitch;
361
        }
362
        block.pixelPtr = imagePtr;
363
    }
364
    ckfree((char *) block.pixelPtr);
365
    return TCL_OK;
366
 
367
    error:
368
    ckfree((char *) block.pixelPtr);
369
    return TCL_ERROR;
370
 
371
}
372
 
373
/*
374
 *----------------------------------------------------------------------
375
 *
376
 * StringMatchGIF --
377
 *
378
 *  This procedure is invoked by the photo image type to see if
379
 *  an object contains image data in GIF format.
380
 *
381
 * Results:
382
 *  The return value is 1 if the first characters in the data are
383
 *  like GIF data, and 0 otherwise.
384
 *
385
 * Side effects:
386
 *  the size of the image is placed in widthPre and heightPtr.
387
 *
388
 *----------------------------------------------------------------------
389
 */
390
 
391
static int
392
StringMatchGIF(dataObj, formatString, widthPtr, heightPtr)
393
    Tcl_Obj *dataObj;           /* the object containing the image data */
394
    char *formatString;         /* the image format string */
395
    int *widthPtr;              /* where to put the string width */
396
    int *heightPtr;             /* where to put the string height */
397
{
398
    unsigned char *data, header[10];
399
    int got, length;
400
    MFile handle;
401
 
402
    data = Tcl_GetStringFromObj(dataObj, &length);
403
 
404
    /* Header is a minimum of 10 bytes */
405
    if (length < 10) {
406
      return 0;
407
    }
408
 
409
    /* Check whether the data is Base64 encoded */
410
 
411
    if ((strncmp("GIF87a", data, 6) != 0) &&
412
        (strncmp("GIF89a", data, 6) != 0)) {
413
      /* Try interpreting the data as Base64 encoded */
414
      mInit((unsigned char *) data, &handle);
415
      got = Mread(header, 10, 1, &handle);
416
      if (got != 10
417
              || ((strncmp("GIF87a", (char *) header, 6) != 0)
418
              && (strncmp("GIF89a", (char *) header, 6) != 0))) {
419
          return 0;
420
      }
421
    } else {
422
      memcpy((VOID *) header, (VOID *) data, 10);
423
    }
424
    *widthPtr = LM_to_uint(header[6],header[7]);
425
    *heightPtr = LM_to_uint(header[8],header[9]);
426
    return 1;
427
}
428
 
429
/*
430
 *----------------------------------------------------------------------
431
 *
432
 * StringReadGif -- --
433
 *
434
 *      This procedure is called by the photo image type to read
435
 *      GIF format data from an object, optionally base64 encoded,
436
 *      and give it to the photo image.
437
 *
438
 * Results:
439
 *      A standard TCL completion code.  If TCL_ERROR is returned
440
 *      then an error message is left in interp->result.
441
 *
442
 * Side effects:
443
 *      new data is added to the image given by imageHandle.  This
444
 *      procedure calls FileReadGif by redefining the operation of
445
 *      fprintf temporarily.
446
 *
447
 *----------------------------------------------------------------------
448
 */
449
 
450
static int
451
StringReadGIF(interp,dataObj,formatString,imageHandle,
452
        destX, destY, width, height, srcX, srcY)
453
    Tcl_Interp *interp;         /* interpreter for reporting errors in */
454
    Tcl_Obj *dataObj;           /* object containing the image */
455
    char *formatString;         /* format string if any */
456
    Tk_PhotoHandle imageHandle; /* the image to write this data into */
457
    int destX, destY;           /* The rectangular region of the  */
458
    int  width, height;         /*   image to copy */
459
    int srcX, srcY;
460
{
461
        int result;
462
        MFile handle;
463
        Tcl_Channel dataSrc;
464
        char *data;
465
        /* Check whether the data is Base64 encoded */
466
        data = Tcl_GetStringFromObj(dataObj, NULL);
467
        if ((strncmp("GIF87a", data, 6) != 0) &&
468
            (strncmp("GIF89a", data, 6) != 0)) {
469
          mInit((unsigned char *)data,&handle);
470
          fromData = 1;
471
          dataSrc = (Tcl_Channel) &handle;
472
        } else {
473
          fromData = 2;
474
          mInit((unsigned char *)data,&handle);
475
          dataSrc = (Tcl_Channel) &handle;
476
        }
477
        result = FileReadGIF(interp, dataSrc, "inline data",
478
                formatString, imageHandle, destX, destY, width, height,
479
                srcX, srcY);
480
        fromData = 0;
481
        return(result);
482
}
483
 
484
/*
485
 *----------------------------------------------------------------------
486
 *
487
 * ReadGIFHeader --
488
 *
489
 *      This procedure reads the GIF header from the beginning of a
490
 *      GIF file and returns the dimensions of the image.
491
 *
492
 * Results:
493
 *      The return value is 1 if file "f" appears to start with
494
 *      a valid GIF header, 0 otherwise.  If the header is valid,
495
 *      then *widthPtr and *heightPtr are modified to hold the
496
 *      dimensions of the image.
497
 *
498
 * Side effects:
499
 *      The access position in f advances.
500
 *
501
 *----------------------------------------------------------------------
502
 */
503
 
504
static int
505
ReadGIFHeader(chan, widthPtr, heightPtr)
506
    Tcl_Channel chan;           /* Image file to read the header from */
507
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
508
                                 * returned here. */
509
{
510
    unsigned char buf[7];
511
 
512
    if ((Fread(buf, 1, 6, chan) != 6)
513
            || ((strncmp("GIF87a", (char *) buf, 6) != 0)
514
            && (strncmp("GIF89a", (char *) buf, 6) != 0))) {
515
        return 0;
516
    }
517
 
518
    if (Fread(buf, 1, 4, chan) != 4) {
519
        return 0;
520
    }
521
 
522
    *widthPtr = LM_to_uint(buf[0],buf[1]);
523
    *heightPtr = LM_to_uint(buf[2],buf[3]);
524
    return 1;
525
}
526
 
527
/*
528
 *-----------------------------------------------------------------
529
 * The code below is copied from the giftoppm program and modified
530
 * just slightly.
531
 *-----------------------------------------------------------------
532
 */
533
 
534
static int
535
ReadColorMap(chan, number, buffer)
536
     Tcl_Channel chan;
537
     int number;
538
     unsigned char buffer[MAXCOLORMAPSIZE][4];
539
{
540
        int i;
541
        unsigned char rgb[3];
542
 
543
        for (i = 0; i < number; ++i) {
544
            if (! ReadOK(chan, rgb, sizeof(rgb))) {
545
                return 0;
546
            }
547
 
548
            buffer[i][CM_RED] = rgb[0] ;
549
            buffer[i][CM_GREEN] = rgb[1] ;
550
            buffer[i][CM_BLUE] = rgb[2] ;
551
            buffer[i][CM_ALPHA] = 255 ;
552
        }
553
        return 1;
554
}
555
 
556
 
557
 
558
static int
559
DoExtension(chan, label, transparent)
560
     Tcl_Channel chan;
561
     int label;
562
     int *transparent;
563
{
564
    static unsigned char buf[256];
565
    int count;
566
 
567
    switch (label) {
568
        case 0x01:      /* Plain Text Extension */
569
            break;
570
 
571
        case 0xff:      /* Application Extension */
572
            break;
573
 
574
        case 0xfe:      /* Comment Extension */
575
            do {
576
                count = GetDataBlock(chan, (unsigned char*) buf);
577
            } while (count > 0);
578
            return count;
579
 
580
        case 0xf9:      /* Graphic Control Extension */
581
            count = GetDataBlock(chan, (unsigned char*) buf);
582
            if (count < 0) {
583
                return 1;
584
            }
585
            if ((buf[0] & 0x1) != 0) {
586
                *transparent = buf[3];
587
            }
588
 
589
            do {
590
                count = GetDataBlock(chan, (unsigned char*) buf);
591
            } while (count > 0);
592
            return count;
593
    }
594
 
595
    do {
596
        count = GetDataBlock(chan, (unsigned char*) buf);
597
    } while (count > 0);
598
    return count;
599
}
600
 
601
static int ZeroDataBlock = 0;
602
 
603
static int
604
GetDataBlock(chan, buf)
605
     Tcl_Channel chan;
606
     unsigned char *buf;
607
{
608
    unsigned char count;
609
 
610
    if (! ReadOK(chan, &count,1)) {
611
        return -1;
612
    }
613
 
614
    ZeroDataBlock = count == 0;
615
 
616
    if ((count != 0) && (! ReadOK(chan, buf, count))) {
617
        return -1;
618
    }
619
 
620
    return count;
621
}
622
 
623
 
624
static int
625
ReadImage(interp, imagePtr, chan, len, rows, cmap,
626
        width, height, srcX, srcY, interlace, transparent)
627
     Tcl_Interp *interp;
628
     char *imagePtr;
629
     Tcl_Channel chan;
630
     int len, rows;
631
     unsigned char cmap[MAXCOLORMAPSIZE][4];
632
     int width, height;
633
     int srcX, srcY;
634
     int interlace;
635
     int transparent;
636
{
637
    unsigned char c;
638
    int v;
639
    int xpos = 0, ypos = 0, pass = 0;
640
    char *pixelPtr;
641
 
642
 
643
    /*
644
     *  Initialize the Compression routines
645
     */
646
    if (! ReadOK(chan, &c, 1))  {
647
        Tcl_AppendResult(interp, "error reading GIF image: ",
648
                Tcl_PosixError(interp), (char *) NULL);
649
        return TCL_ERROR;
650
    }
651
 
652
    if (LWZReadByte(chan, 1, c) < 0) {
653
        interp->result = "format error in GIF image";
654
        return TCL_ERROR;
655
    }
656
 
657
    if (transparent!=-1) {
658
        cmap[transparent][CM_RED] = 0;
659
        cmap[transparent][CM_GREEN] = 0;
660
        cmap[transparent][CM_BLUE] = 0;
661
        cmap[transparent][CM_ALPHA] = 0;
662
    }
663
 
664
    pixelPtr = imagePtr;
665
    while ((v = LWZReadByte(chan, 0, c)) >= 0 ) {
666
 
667
        if ((xpos>=srcX) && (xpos<srcX+len) &&
668
                (ypos>=srcY) && (ypos<srcY+rows)) {
669
            *pixelPtr++ = cmap[v][CM_RED];
670
            *pixelPtr++ = cmap[v][CM_GREEN];
671
            *pixelPtr++ = cmap[v][CM_BLUE];
672
            *pixelPtr++ = cmap[v][CM_ALPHA];
673
        }
674
 
675
        ++xpos;
676
        if (xpos == width) {
677
            xpos = 0;
678
            if (interlace) {
679
                switch (pass) {
680
                    case 0:
681
                    case 1:
682
                        ypos += 8; break;
683
                    case 2:
684
                        ypos += 4; break;
685
                    case 3:
686
                        ypos += 2; break;
687
                }
688
 
689
                while (ypos >= height) {
690
                    ++pass;
691
                    switch (pass) {
692
                        case 1:
693
                            ypos = 4; break;
694
                        case 2:
695
                            ypos = 2; break;
696
                        case 3:
697
                            ypos = 1; break;
698
                        default:
699
                            return TCL_OK;
700
                    }
701
                }
702
            } else {
703
                ++ypos;
704
            }
705
            pixelPtr = imagePtr + (ypos-srcY) * len * 4;
706
        }
707
        if (ypos >= height)
708
            break;
709
    }
710
    return TCL_OK;
711
}
712
 
713
static int
714
LWZReadByte(chan, flag, input_code_size)
715
     Tcl_Channel chan;
716
     int flag;
717
     int input_code_size;
718
{
719
    static int  fresh = 0;
720
    int code, incode;
721
    static int code_size, set_code_size;
722
    static int max_code, max_code_size;
723
    static int firstcode, oldcode;
724
    static int clear_code, end_code;
725
    static int table[2][(1<< MAX_LWZ_BITS)];
726
    static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
727
    register int    i;
728
 
729
    if (flag) {
730
        set_code_size = input_code_size;
731
        code_size = set_code_size+1;
732
        clear_code = 1 << set_code_size ;
733
        end_code = clear_code + 1;
734
        max_code_size = 2*clear_code;
735
        max_code = clear_code+2;
736
 
737
        GetCode(chan, 0, 1);
738
 
739
        fresh = 1;
740
 
741
        for (i = 0; i < clear_code; ++i) {
742
            table[0][i] = 0;
743
            table[1][i] = i;
744
        }
745
        for (; i < (1<<MAX_LWZ_BITS); ++i) {
746
            table[0][i] = table[1][0] = 0;
747
        }
748
 
749
        sp = stack;
750
 
751
        return 0;
752
    } else if (fresh) {
753
        fresh = 0;
754
        do {
755
            firstcode = oldcode = GetCode(chan, code_size, 0);
756
        } while (firstcode == clear_code);
757
        return firstcode;
758
    }
759
 
760
    if (sp > stack) {
761
        return *--sp;
762
    }
763
 
764
    while ((code = GetCode(chan, code_size, 0)) >= 0) {
765
        if (code == clear_code) {
766
            for (i = 0; i < clear_code; ++i) {
767
                table[0][i] = 0;
768
                table[1][i] = i;
769
            }
770
 
771
            for (; i < (1<<MAX_LWZ_BITS); ++i) {
772
                table[0][i] = table[1][i] = 0;
773
            }
774
 
775
            code_size = set_code_size+1;
776
            max_code_size = 2*clear_code;
777
            max_code = clear_code+2;
778
            sp = stack;
779
            firstcode = oldcode = GetCode(chan, code_size, 0);
780
            return firstcode;
781
 
782
        } else if (code == end_code) {
783
            int count;
784
            unsigned char buf[260];
785
 
786
            if (ZeroDataBlock) {
787
                return -2;
788
            }
789
 
790
            while ((count = GetDataBlock(chan, buf)) > 0)
791
                /* Empty body */;
792
 
793
            if (count != 0) {
794
                return -2;
795
            }
796
        }
797
 
798
        incode = code;
799
 
800
        if (code >= max_code) {
801
            *sp++ = firstcode;
802
            code = oldcode;
803
        }
804
 
805
        while (code >= clear_code) {
806
            *sp++ = table[1][code];
807
            if (code == table[0][code]) {
808
                return -2;
809
 
810
                /*
811
                 * Used to be this instead, Steve Ball suggested
812
                 * the change to just return.
813
                 printf("circular table entry BIG ERROR\n");
814
                 */
815
            }
816
            code = table[0][code];
817
        }
818
 
819
        *sp++ = firstcode = table[1][code];
820
 
821
        if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
822
            table[0][code] = oldcode;
823
            table[1][code] = firstcode;
824
            ++max_code;
825
            if ((max_code>=max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) {
826
                max_code_size *= 2;
827
                ++code_size;
828
            }
829
        }
830
 
831
        oldcode = incode;
832
 
833
        if (sp > stack)
834
            return *--sp;
835
        }
836
        return code;
837
}
838
 
839
 
840
static int
841
GetCode(chan, code_size, flag)
842
     Tcl_Channel chan;
843
     int code_size;
844
     int flag;
845
{
846
    static unsigned char buf[280];
847
    static int curbit, lastbit, done, last_byte;
848
    int i, j, ret;
849
    unsigned char count;
850
 
851
    if (flag) {
852
        curbit = 0;
853
        lastbit = 0;
854
        done = 0;
855
        return 0;
856
    }
857
 
858
 
859
    if ( (curbit+code_size) >= lastbit) {
860
        if (done) {
861
            /* ran off the end of my bits */
862
            return -1;
863
        }
864
        if (last_byte >= 2) {
865
            buf[0] = buf[last_byte-2];
866
        }
867
        if (last_byte >= 1) {
868
            buf[1] = buf[last_byte-1];
869
        }
870
 
871
        if ((count = GetDataBlock(chan, &buf[2])) == 0) {
872
            done = 1;
873
        }
874
 
875
        last_byte = 2 + count;
876
        curbit = (curbit - lastbit) + 16;
877
        lastbit = (2+count)*8 ;
878
    }
879
 
880
    ret = 0;
881
    for (i = curbit, j = 0; j < code_size; ++i, ++j) {
882
        ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
883
    }
884
 
885
    curbit += code_size;
886
 
887
    return ret;
888
}
889
 
890
/*
891
 *----------------------------------------------------------------------
892
 *
893
 * Minit -- --
894
 *
895
 *  This procedure initializes a base64 decoder handle
896
 *
897
 * Results:
898
 *  none
899
 *
900
 * Side effects:
901
 *  the base64 handle is initialized
902
 *
903
 *----------------------------------------------------------------------
904
 */
905
 
906
static void
907
mInit(string, handle)
908
   unsigned char *string;       /* string containing initial mmencoded data */
909
   MFile *handle;               /* mmdecode "file" handle */
910
{
911
   handle->data = string;
912
   handle->state = 0;
913
   handle->c = 0;
914
}
915
 
916
/*
917
 *----------------------------------------------------------------------
918
 *
919
 * Mread --
920
 *
921
 *      This procedure is invoked by the GIF file reader as a
922
 *      temporary replacement for "fread", to get GIF data out
923
 *      of a string (using Mgetc).
924
 *
925
 * Results:
926
 *      The return value is the number of characters "read"
927
 *
928
 * Side effects:
929
 *      The base64 handle will change state.
930
 *
931
 *----------------------------------------------------------------------
932
 */
933
 
934
static int
935
Mread(dst, chunkSize, numChunks, handle)
936
   unsigned char *dst;  /* where to put the result */
937
   size_t chunkSize;    /* size of each transfer */
938
   size_t numChunks;    /* number of chunks */
939
   MFile *handle;       /* mmdecode "file" handle */
940
{
941
   register int i, c;
942
   int count = chunkSize * numChunks;
943
 
944
   for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
945
        *dst++ = c;
946
   }
947
   return i;
948
}
949
 
950
/*
951
 * get the next decoded character from an mmencode handle
952
 * This causes at least 1 character to be "read" from the encoded string
953
 */
954
 
955
/*
956
 *----------------------------------------------------------------------
957
 *
958
 * Mgetc --
959
 *
960
 *  This procedure decodes and returns the next byte from a base64
961
 *  encoded string.
962
 *
963
 * Results:
964
 *  The next byte (or GIF_DONE) is returned.
965
 *
966
 * Side effects:
967
 *  The base64 handle will change state.
968
 *
969
 *----------------------------------------------------------------------
970
 */
971
 
972
static int
973
Mgetc(handle)
974
   MFile *handle;               /* Handle containing decoder data and state. */
975
{
976
    int c;
977
    int result = 0;              /* Initialization needed only to prevent
978
                                 * gcc compiler warning. */
979
 
980
    if (handle->state == GIF_DONE) {
981
        return(GIF_DONE);
982
    }
983
 
984
    do {
985
        c = char64(*handle->data);
986
        handle->data++;
987
    } while (c==GIF_SPACE);
988
 
989
    if (c>GIF_SPECIAL) {
990
        handle->state = GIF_DONE;
991
        return(handle->state ? handle->c : GIF_DONE);
992
    }
993
 
994
    switch (handle->state++) {
995
        case 0:
996
           handle->c = c<<2;
997
           result = Mgetc(handle);
998
           break;
999
        case 1:
1000
           result = handle->c | (c>>4);
1001
           handle->c = (c&0xF)<<4;
1002
           break;
1003
        case 2:
1004
           result = handle->c | (c>>2);
1005
           handle->c = (c&0x3) << 6;
1006
           break;
1007
        case 3:
1008
           result = handle->c | c;
1009
           handle->state = 0;
1010
           break;
1011
    }
1012
    return(result);
1013
}
1014
 
1015
/*
1016
 *----------------------------------------------------------------------
1017
 *
1018
 * char64 --
1019
 *
1020
 *      This procedure converts a base64 ascii character into its binary
1021
 *      equivalent.  This code is a slightly modified version of the
1022
 *      char64 proc in N. Borenstein's metamail decoder.
1023
 *
1024
 * Results:
1025
 *      The binary value, or an error code.
1026
 *
1027
 * Side effects:
1028
 *      None.
1029
 *----------------------------------------------------------------------
1030
 */
1031
 
1032
static int
1033
char64(c)
1034
int c;
1035
{
1036
    switch(c) {
1037
        case 'A': return(0);  case 'B': return(1);  case 'C': return(2);
1038
        case 'D': return(3);  case 'E': return(4);  case 'F': return(5);
1039
        case 'G': return(6);  case 'H': return(7);  case 'I': return(8);
1040
        case 'J': return(9);  case 'K': return(10); case 'L': return(11);
1041
        case 'M': return(12); case 'N': return(13); case 'O': return(14);
1042
        case 'P': return(15); case 'Q': return(16); case 'R': return(17);
1043
        case 'S': return(18); case 'T': return(19); case 'U': return(20);
1044
        case 'V': return(21); case 'W': return(22); case 'X': return(23);
1045
        case 'Y': return(24); case 'Z': return(25); case 'a': return(26);
1046
        case 'b': return(27); case 'c': return(28); case 'd': return(29);
1047
        case 'e': return(30); case 'f': return(31); case 'g': return(32);
1048
        case 'h': return(33); case 'i': return(34); case 'j': return(35);
1049
        case 'k': return(36); case 'l': return(37); case 'm': return(38);
1050
        case 'n': return(39); case 'o': return(40); case 'p': return(41);
1051
        case 'q': return(42); case 'r': return(43); case 's': return(44);
1052
        case 't': return(45); case 'u': return(46); case 'v': return(47);
1053
        case 'w': return(48); case 'x': return(49); case 'y': return(50);
1054
        case 'z': return(51); case '0': return(52); case '1': return(53);
1055
        case '2': return(54); case '3': return(55); case '4': return(56);
1056
        case '5': return(57); case '6': return(58); case '7': return(59);
1057
        case '8': return(60); case '9': return(61); case '+': return(62);
1058
        case '/': return(63);
1059
 
1060
        case ' ': case '\t': case '\n': case '\r': case '\f': return(GIF_SPACE);
1061
        case '=':  return(GIF_PAD);
1062
        case '\0': return(GIF_DONE);
1063
        default: return(GIF_BAD);
1064
    }
1065
}
1066
 
1067
/*
1068
 *----------------------------------------------------------------------
1069
 *
1070
 * Fread --
1071
 *
1072
 *  This procedure calls either fread or Mread to read data
1073
 *  from a file or a base64 encoded string.
1074
 *
1075
 * Results: - same as fread
1076
 *
1077
 *----------------------------------------------------------------------
1078
 */
1079
 
1080
static int
1081
Fread(dst, hunk, count, chan)
1082
    unsigned char *dst;         /* where to put the result */
1083
    size_t hunk,count;          /* how many */
1084
    Tcl_Channel chan;
1085
{
1086
  MFile *handle;
1087
    switch (fromData) {
1088
      case 0:
1089
        return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
1090
      case 1:
1091
        return(Mread(dst, hunk, count, (MFile *) chan));
1092
      case 2:
1093
        handle = (MFile *) chan;
1094
        memcpy((VOID *)dst, (VOID *) handle->data, (int) (hunk * count));
1095
        handle->data += hunk * count;
1096
        return((int) (hunk * count));
1097
    }
1098
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.