1/*
2 * bmp.c --
3 *
4 *  BMP photo image type, Tcl/Tk package
5 *
6 * Copyright (c) 1997-2003 Jan Nijtmans    <nijtmans@users.sourceforge.net>
7 * Copyright (c) 2002      Andreas Kupries <andreas_kupries@users.sourceforge.net>
8 *
9 * $Id: bmp.c 233 2010-04-01 09:28:00Z nijtmans $
10 *
11 */
12
13/*
14 * Generic initialization code, parameterized via CPACKAGE and PACKAGE.
15 */
16
17#include <string.h>
18#include "init.c"
19
20/* Compression types */
21#define BI_RGB          0
22#define BI_RLE8         1
23#define BI_RLE4         2
24#define BI_BITFIELDS    3
25
26/* Structure for reading bit masks for compression type BI_BITFIELDS */
27typedef struct {
28  unsigned int mask;
29  unsigned int shiftin;
30  unsigned int shiftout;
31} BitmapChannel;
32
33/*
34 * Now the implementation
35 */
36/*
37 * Prototypes for local procedures defined in this file:
38 */
39
40static int CommonMatch(tkimg_MFile *handle, int *widthPtr,
41        int *heightPtr, unsigned char **colorMap, int *numBits,
42        int *numCols, int *comp, unsigned int *mask);
43
44static int CommonRead(Tcl_Interp *interp, tkimg_MFile *handle,
45        Tk_PhotoHandle imageHandle, int destX, int destY, int width,
46        int height, int srcX, int srcY);
47
48static int CommonWrite(Tcl_Interp *interp, tkimg_MFile *handle,
49        Tk_PhotoImageBlock *blockPtr);
50
51static void putint(tkimg_MFile *handle, int i);
52
53/*
54 * Entrypoints for the photo image type.
55 */
56
57static int
58ChnMatch(
59    Tcl_Channel chan,
60    const char *fileName,
61    Tcl_Obj *format,
62    int *widthPtr,
63    int *heightPtr,
64    Tcl_Interp *interp
65) {
66    tkimg_MFile handle;
67
68    handle.data = (char *) chan;
69    handle.state = IMG_CHAN;
70
71    return CommonMatch(&handle, widthPtr, heightPtr,
72                        NULL, NULL, NULL, NULL, NULL);
73}
74
75static int
76ObjMatch(
77    Tcl_Obj *data,
78    Tcl_Obj *format,
79    int *widthPtr,
80    int *heightPtr,
81    Tcl_Interp *interp
82) {
83    tkimg_MFile handle;
84
85    if (!tkimg_ReadInit(data, 'B', &handle)) {
86        return 0;
87    }
88    return CommonMatch(&handle, widthPtr, heightPtr,
89                        NULL, NULL, NULL, NULL, NULL);
90}
91
92static int
93ChnRead(interp, chan, fileName, format, imageHandle,
94        destX, destY, width, height, srcX, srcY)
95    Tcl_Interp *interp;
96    Tcl_Channel chan;
97    const char *fileName;
98    Tcl_Obj *format;
99    Tk_PhotoHandle imageHandle;
100    int destX, destY;
101    int width, height;
102    int srcX, srcY;
103{
104    tkimg_MFile handle;
105
106    handle.data = (char *) chan;
107    handle.state = IMG_CHAN;
108
109    return CommonRead(interp, &handle, imageHandle, destX, destY,
110            width, height, srcX, srcY);
111}
112
113static int
114ObjRead(interp, data, format, imageHandle,
115        destX, destY, width, height, srcX, srcY)
116    Tcl_Interp *interp;
117    Tcl_Obj *data;
118    Tcl_Obj *format;
119    Tk_PhotoHandle imageHandle;
120    int destX, destY;
121    int width, height;
122    int srcX, srcY;
123{
124    tkimg_MFile handle;
125
126    tkimg_ReadInit(data,'B',&handle);
127    return CommonRead(interp, &handle, imageHandle, destX, destY,
128            width, height, srcX, srcY);
129}
130
131static int
132ChnWrite(interp, filename, format, blockPtr)
133    Tcl_Interp *interp;
134    const char *filename;
135    Tcl_Obj *format;
136    Tk_PhotoImageBlock *blockPtr;
137{
138    Tcl_Channel chan;
139    tkimg_MFile handle;
140    int result;
141
142    chan = tkimg_OpenFileChannel(interp, filename, 0644);
143    if (!chan) {
144        return TCL_ERROR;
145    }
146
147    handle.data = (char *) chan;
148    handle.state = IMG_CHAN;
149
150    result = CommonWrite(interp, &handle, blockPtr);
151    if (Tcl_Close(interp, chan) == TCL_ERROR) {
152        return TCL_ERROR;
153    }
154    return result;
155}
156
157static int StringWrite(
158    Tcl_Interp *interp,
159    Tcl_Obj *format,
160    Tk_PhotoImageBlock *blockPtr
161) {
162    tkimg_MFile handle;
163    int result;
164    Tcl_DString data;
165
166    Tcl_DStringInit(&data);
167    tkimg_WriteInit(&data, &handle);
168    result = CommonWrite(interp, &handle, blockPtr);
169    tkimg_Putc(IMG_DONE, &handle);
170
171    if (result == TCL_OK) {
172	Tcl_DStringResult(interp, &data);
173    } else {
174	Tcl_DStringFree(&data);
175    }
176    return result;
177}
178
179static unsigned int
180getUInt32(buf)
181    unsigned char *buf;
182{
183    return (buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
184}
185
186static unsigned int
187getUInt16(buf)
188    unsigned char *buf;
189{
190    return (buf[0] | buf[1] << 8);
191}
192
193static void
194GetChannelMasks(intMask, masks)
195    unsigned int *intMask;
196    BitmapChannel *masks;
197{
198    unsigned int mask;
199    int i, nbits, offset, bit;
200
201    for (i=0; i<3; i++) {
202        mask = getUInt32((unsigned char *) &intMask[i]);
203        masks[i].mask = mask;
204        nbits = 0;
205        offset = -1;
206        for (bit=0; bit<32; bit++) {
207            if (mask & 1) {
208                nbits++;
209                if (offset == -1) {
210                  offset = bit;
211                }
212            }
213            mask = mask >> 1;
214        }
215        masks[i].shiftin = offset;
216        masks[i].shiftout = 8 - nbits;
217    }
218}
219
220/*
221 * Helper functions for the entry points. Work horses.
222 */
223
224static int
225CommonMatch(handle, widthPtr, heightPtr, colorMap, numBits, numCols, comp, mask)
226    tkimg_MFile *handle;
227    int *widthPtr, *heightPtr;
228    unsigned char **colorMap;
229    int *numBits, *numCols, *comp;
230    unsigned int *mask;
231{
232    unsigned char buf[28];
233    int c,i, compression, nBits, clrUsed, offBits;
234
235    if ((tkimg_Read(handle, (char *) buf, 2) != 2)
236            || (strncmp("BM", (char *) buf, 2) != 0)
237            || (tkimg_Read(handle, (char *) buf, 24) != 24)
238            || buf[13] || buf[14] || buf[15]) {
239        return 0;
240    }
241
242    offBits = (buf[11]<<24) + (buf[10]<<16) + (buf[9]<<8) + buf[8];
243    c = buf[12];
244    if ((c == 40) || (c == 64)) {
245        *widthPtr = (buf[19]<<24) + (buf[18]<<16) + (buf[17]<<8) + buf[16];
246        *heightPtr = (buf[23]<<24) + (buf[22]<<16) + (buf[21]<<8) + buf[20];
247        if (tkimg_Read(handle, (char *) buf, 24) != 24) {
248            return 0;
249        }
250        nBits = buf[2];
251        compression = buf[4];
252        clrUsed = (buf[21]<<8) + buf[20];
253        offBits -= c+14;
254    } else if (c == 12) {
255        *widthPtr = (buf[17]<<8) + buf[16];
256        *heightPtr = (buf[19]<<8) + buf[18];
257        nBits = buf[22];
258        compression = BI_RGB;
259        clrUsed = 0;
260    } else {
261        return 0;
262    }
263    if (*widthPtr <= 0 || *heightPtr <= 0)
264        return 0;
265
266    if (colorMap) {
267        if (c > 36) tkimg_Read(handle, (char *) buf, c - 36);
268        if (compression == BI_BITFIELDS) {
269            /* Read the channel masks. */
270            tkimg_Read(handle, (char *) buf, 3*4);
271            if (mask) {
272                mask[0] = getUInt32((unsigned char *) &buf[0]);
273                mask[1] = getUInt32((unsigned char *) &buf[4]);
274                mask[2] = getUInt32((unsigned char *) &buf[8]);
275            }
276            offBits -= 3*4;
277        }
278        if (!clrUsed && nBits < 24) {
279            clrUsed = 1 << nBits;
280        }
281        if (nBits<16) {
282            unsigned char colbuf[4], *ptr;
283            offBits -= (3+(c!=12)) * clrUsed;
284            *colorMap = ptr = (unsigned char *) ckalloc(3*clrUsed);
285            for (i = 0; i < clrUsed; i++) {
286                tkimg_Read(handle, (char *) colbuf, 3+(c!=12));
287                *ptr++ = colbuf[0]; *ptr++ = colbuf[1]; *ptr++ = colbuf[2];
288                /*printf("color %d: %d %d %d\n", i, colbuf[2], colbuf[1], colbuf[0]);*/
289            }
290        }
291        while (offBits>28) {
292            offBits -= 28;
293            tkimg_Read(handle, (char *) buf, 28);
294        }
295        if (offBits) tkimg_Read(handle, (char *) buf, offBits);
296        if (numCols) {
297            *numCols = clrUsed;
298        }
299    }
300    if (numBits) {
301        *numBits = nBits;
302    }
303    if (comp) {
304        *comp = compression;
305    }
306    return 1;
307}
308
309static int
310CommonRead(interp, handle, imageHandle, destX, destY,
311        width, height, srcX, srcY)
312    Tcl_Interp *interp;
313    tkimg_MFile *handle;
314    Tk_PhotoHandle imageHandle;
315    int destX, destY;
316    int width, height;
317    int srcX, srcY;
318{
319    Tk_PhotoImageBlock block;
320    int numBits, bytesPerLine, numCols, comp, x, y;
321    int fileWidth, fileHeight;
322    unsigned char *colorMap = NULL;
323    unsigned int intMask[3];
324    BitmapChannel masks[3];
325    char buf[10];
326    unsigned char *line = NULL, *expline = NULL;
327    unsigned short rgb;
328
329    CommonMatch(handle, &fileWidth, &fileHeight, &colorMap, &numBits,
330                 &numCols, &comp, intMask);
331
332    if (numBits == 16) {
333        if (comp == BI_BITFIELDS) {
334            GetChannelMasks(intMask, masks);
335        } else {
336            masks[0].mask     = 0x7c00;
337            masks[0].shiftin  = 10;
338            masks[0].shiftout = 3;
339            masks[1].mask     = 0x03e0;
340            masks[1].shiftin  = 5;
341            masks[1].shiftout = 3;
342            masks[2].mask     = 0x001f;
343            masks[2].shiftin  = 0;
344            masks[2].shiftout = 3;
345        }
346    }
347
348    /* printf("reading %d-bit BMP %dx%d\n", numBits, width, height); */
349    if (comp == BI_RLE8 || comp == BI_RLE4) {
350        tkimg_ReadBuffer(1);
351    }
352
353    if (tkimg_PhotoExpand(interp, imageHandle, destX + width, destY + height) == TCL_ERROR) {
354        goto error;
355    }
356
357    bytesPerLine = ((numBits * fileWidth + 31)/32)*4;
358
359    /* printf("bytesPerLine = %d numBits=%d (%dx%d)\n",
360     *        bytesPerLine, numBits, width, height);
361     */
362    block.pixelSize = 3;
363    block.pitch = width * 3;
364    block.width = width;
365    block.height = 1;
366    block.offset[0] = 2;
367    block.offset[1] = 1;
368    block.offset[2] = 0;
369    block.offset[3] = block.offset[0];
370
371    if (comp == BI_RGB || comp == BI_BITFIELDS) {       /* No compression */
372        line = (unsigned char *) ckalloc(bytesPerLine);
373        for(y=srcY+height; y<fileHeight; y++) {
374            tkimg_Read(handle, (char *)line, bytesPerLine);
375        }
376        switch (numBits) {
377            case 32:
378                block.pixelPtr = expline = (unsigned char *) ckalloc(3*width);
379                for( y = height-1; y>=0; y--) {
380                    tkimg_Read(handle, (char *)line, bytesPerLine);
381                    for (x = srcX; x < (srcX+width); x++) {
382                        *expline++ = line[x*4 + 0];
383                        *expline++ = line[x*4 + 1];
384                        *expline++ = line[x*4 + 2];
385                    }
386                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
387                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
388                        goto error;
389                    }
390                    expline = block.pixelPtr;
391                }
392                break;
393            case 24:
394                block.pixelPtr = line + srcX*3;
395                for( y = height-1; y>=0; y--) {
396                    tkimg_Read(handle, (char *)line, bytesPerLine);
397                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
398                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
399                        goto error;
400                    }
401                }
402                break;
403            case 16:
404                block.pixelPtr = expline = (unsigned char *) ckalloc(3*width);
405                for( y = height-1; y>=0; y--) {
406                    tkimg_Read(handle, (char *)line, bytesPerLine);
407                    for (x = srcX; x < (srcX+width); x++) {
408                        rgb = getUInt16 (&line[x*2]);
409                        *expline++ = ((rgb & masks[2].mask) >> masks[2].shiftin) << masks[2].shiftout;
410                        *expline++ = ((rgb & masks[1].mask) >> masks[1].shiftin) << masks[1].shiftout;
411                        *expline++ = ((rgb & masks[0].mask) >> masks[0].shiftin) << masks[0].shiftout;
412                    }
413                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
414                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
415                        goto error;
416                    }
417                    expline = block.pixelPtr;
418                }
419                break;
420            case 8:
421                block.pixelPtr = expline = (unsigned char *) ckalloc(3*width);
422                for( y = height-1; y>=0; y--) {
423                    tkimg_Read(handle, (char *)line, bytesPerLine);
424                    for (x = srcX; x < (srcX+width); x++) {
425                        memcpy(expline, colorMap+(3*line[x]),3);
426                        expline += 3;
427                    }
428                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
429                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
430                        goto error;
431                    }
432                    expline = block.pixelPtr;
433                }
434                break;
435            case 4:
436                block.pixelPtr = expline = (unsigned char *) ckalloc(3*width);
437                for( y = height-1; y>=0; y--) {
438                    int c;
439                    tkimg_Read(handle, (char *)line, bytesPerLine);
440                    for (x = srcX; x < (srcX+width); x++) {
441                        if (x&1) {
442                            c = line[x/2] & 0x0f;
443                        } else {
444                            c = line[x/2] >> 4;
445                        }
446                        memcpy(expline, colorMap+(3*c),3);
447                        expline += 3;
448                    }
449                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
450                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
451                        goto error;
452                    }
453                    expline = block.pixelPtr;
454                }
455                break;
456            case 1:
457                block.pixelPtr = expline = (unsigned char *) ckalloc(3*width);
458                for( y = height-1; y>=0; y--) {
459                    int c;
460                    tkimg_Read(handle, (char *)line, bytesPerLine);
461                    for (x = srcX; x < (srcX+width); x++) {
462                        c = (line[x/8] >> (7-(x%8))) & 1;
463                        memcpy(expline, colorMap+(3*c),3);
464                        expline += 3;
465                    }
466                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block,
467                            destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
468                        goto error;
469                    }
470                    expline = block.pixelPtr;
471                }
472                break;
473            default:
474                sprintf(buf,"%d", numBits);
475                Tcl_AppendResult(interp, buf,
476                        "-bits BMP file not (yet) supported", (char *) NULL);
477                goto error;
478        }
479    } else {            /* RLE Compression */
480        int i, j, c;
481        unsigned char howMuch;
482        unsigned char rleBuf[2];
483        unsigned char rleDelta[2];
484        unsigned char val;
485
486        x = srcX;
487        y = fileHeight - 1;
488        block.pixelPtr = expline = (unsigned char *) ckalloc (3*fileWidth);
489
490        if (numBits != 4 && numBits != 8) {
491            sprintf (buf, "%d", numBits);
492            Tcl_AppendResult(interp, "RLE compression not supported for ",
493                              buf, "-bit pixel values", (char *) NULL);
494            goto error;
495        }
496
497        while (1) {
498            if (2 != tkimg_Read(handle, (char *)rleBuf, 2)) {
499                Tcl_AppendResult(interp, "Unexpected EOF", (char *) NULL);
500                goto error;
501            }
502            /* printf("In: (%d %X) --> \n", rleBuf[0], rleBuf[1]); */
503            if (rleBuf[0] != 0) {
504                howMuch = rleBuf[0];
505                switch (numBits) {
506                    case 8: {
507                        for (i=0; i<howMuch; i++, x++) {
508                            memcpy (expline, colorMap + 3*rleBuf[1], 3);
509                            expline += 3;
510                        }
511                        break;
512                    }
513                    case 4: {
514                        for (i=0; i<howMuch; i++, x++) {
515                            if (x&1) {
516                                c = rleBuf[1] & 0x0f;
517                            } else {
518                                c = rleBuf[1] >> 4;
519                            }
520                            memcpy(expline, colorMap + 3*c, 3);
521                            if (x>=srcX+width-1) {
522                                break;
523                            }
524                            expline += 3;
525                        }
526                        break;
527                    }
528                }
529            } else {
530                if (rleBuf[1]>2) {
531                    /* uncompressed record */
532                    howMuch = rleBuf[1];
533                    /* printf ("Uncompressed: %d\n", howMuch); fflush (stdout); */
534                    switch (numBits) {
535                        case 8: {
536                            for (i=0; i<howMuch; i++, x++) {
537                                if (1 != tkimg_Read(handle, (char *)&val, 1)) {
538                                    Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL);
539                                    goto error;
540                                }
541                                memcpy(expline, colorMap + 3*val, 3);
542                                expline += 3;
543                            }
544                            break;
545                        }
546                        case 4: {
547                            for (i=0; i<howMuch; i+=2) {
548                                if (1 != tkimg_Read(handle, (char *)&val, 1)) {
549                                    Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL);
550                                    goto error;
551                                }
552                                for (j=0; j<2; j++, x++) {
553                                    if (x&1) {
554                                        c = val & 0x0f;
555                                    } else {
556                                        c = val >> 4;
557                                    }
558                                    memcpy(expline, colorMap + 3*c, 3);
559                                    if (x>=srcX+width-1) {
560                                        break;
561                                    }
562                                    expline += 3;
563                                }
564                            }
565                            break;
566                        }
567                    }
568
569                    if ((howMuch % 2) && (numBits==4)) {
570                        howMuch++;
571                    }
572
573                    if ((howMuch / (8 / numBits)) % 2) {
574                        if (1 != tkimg_Read(handle, (char *)&val, 1)) {
575                            Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL);
576                            goto error;
577                        }
578                    }
579                } else if (rleBuf[1]==0) {
580                    /* End of line */
581                    /* printf("New line: y=%d x=%d\n", y, x); fflush(stdout); */
582                    if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, destY+y,
583                            width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
584                        goto error;
585                    }
586                    y--;
587                    x = srcX;
588                    expline = block.pixelPtr;
589                } else if (rleBuf[1]==1) {
590                    /* End of bitmap */
591                    break;
592                } else if (rleBuf[1]==2) {
593                    /* Deltarecord */
594                    /* printf("Deltarecord\n"); fflush(stdout); */
595                    if (2 != tkimg_Read(handle, (char *) rleDelta, 2)) {
596                        Tcl_AppendResult(interp, "Unexpected EOF", (char *) NULL);
597                        goto error;
598                    }
599                    x += rleDelta[0];
600                    y += rleDelta[1];
601                }
602            }
603        }
604    }
605    tkimg_ReadBuffer(0);
606
607    if (colorMap) {
608        ckfree((char *) colorMap);
609    }
610    if (line) {
611        ckfree((char *) line);
612    }
613    if (expline) {
614        ckfree((char *) block.pixelPtr);
615    }
616    return TCL_OK ;
617
618error:
619    tkimg_ReadBuffer(0);
620    if (colorMap) {
621        ckfree((char *) colorMap);
622    }
623    if (line) {
624        ckfree((char *) line);
625    }
626    if (expline) {
627        ckfree((char *) block.pixelPtr);
628    }
629    return TCL_ERROR;
630}
631
632static int
633CommonWrite(interp, handle, blockPtr)
634    Tcl_Interp *interp;
635    tkimg_MFile *handle;
636    Tk_PhotoImageBlock *blockPtr;
637{
638    int bperline, nbytes, ncolors, i, x, y, greenOffset, blueOffset, alphaOffset;
639    unsigned char *imagePtr, *pixelPtr;
640    unsigned char buf[4];
641    int colors[256];
642
643    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
644    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
645    alphaOffset = blockPtr->offset[0];
646    if (alphaOffset < blockPtr->offset[2]) {
647        alphaOffset = blockPtr->offset[2];
648    }
649    if (++alphaOffset < blockPtr->pixelSize) {
650        alphaOffset -= blockPtr->offset[0];
651    } else {
652        alphaOffset = 0;
653    }
654    ncolors = 0;
655    if (greenOffset || blueOffset) {
656        for (y = 0; ncolors <= 256 && y < blockPtr->height; y++) {
657            pixelPtr = blockPtr->pixelPtr + y*blockPtr->pitch + blockPtr->offset[0];
658            for (x=0; ncolors <= 256 && x<blockPtr->width; x++) {
659                int pixel;
660                if (alphaOffset && (pixelPtr[alphaOffset] == 0))
661                    pixel = 0xd9d9d9;
662                else
663                    pixel = (pixelPtr[0]<<16) | (pixelPtr[greenOffset]<<8) | pixelPtr[blueOffset];
664                for (i = 0; i < ncolors && pixel != colors[i]; i++);
665                if (i == ncolors) {
666                    if (ncolors < 256) {
667                        colors[ncolors] = pixel;
668                    }
669                    ncolors++;
670                }
671                pixelPtr += blockPtr->pixelSize;
672            }
673        }
674        if (ncolors <= 256 && (blockPtr->width * blockPtr->height >= 512)) {
675            while (ncolors < 256) {
676                colors[ncolors++] = 0;
677            }
678            nbytes = 1;
679        } else {
680            nbytes = 3;
681            ncolors = 0;
682        }
683    } else {
684        nbytes = 1;
685    }
686
687    bperline = ((blockPtr->width  * nbytes + 3) / 4) * 4;
688
689    tkimg_Write(handle,"BM", 2);
690    putint(handle, 54 + (ncolors*4) + bperline * blockPtr->height);
691    putint(handle, 0);
692    putint(handle, 54 + (ncolors*4));
693    putint(handle, 40);
694    putint(handle, blockPtr->width);
695    putint(handle, blockPtr->height);
696    putint(handle, 1 + (nbytes<<19));
697    putint(handle, 0);
698    putint(handle, bperline * blockPtr->height);
699    putint(handle, 75*39);
700    putint(handle, 75*39);
701    putint(handle, ncolors);
702    putint(handle, ncolors);
703
704    for (i = 0; i < ncolors ; i++) {
705        putint(handle, colors[i]);
706    }
707
708    bperline -= blockPtr->width * nbytes;
709
710    imagePtr =  blockPtr->pixelPtr + blockPtr->offset[0]
711            + blockPtr->height * blockPtr->pitch;
712    for (y = 0; y < blockPtr->height; y++) {
713        pixelPtr = imagePtr -= blockPtr->pitch;
714        for (x=0; x<blockPtr->width; x++) {
715            if (ncolors) {
716                int pixel;
717                if (alphaOffset && (pixelPtr[alphaOffset] == 0))
718                    pixel = 0xd9d9d9;
719                else
720                    pixel = (pixelPtr[0]<<16)|(pixelPtr[greenOffset]<<8)|pixelPtr[blueOffset];
721                for (i = 0; i < ncolors && pixel != colors[i]; i += 1);
722                buf[0] = i;
723            } else if (alphaOffset && (pixelPtr[alphaOffset] == 0)) {
724                buf[0] = buf[1] = buf[2] = 0xd9;
725            } else {
726                buf[0] = pixelPtr[blueOffset];
727                buf[1] = pixelPtr[greenOffset];
728                buf[2] = pixelPtr[0];
729            }
730            tkimg_Write(handle, (char *) buf, nbytes);
731            pixelPtr += blockPtr->pixelSize;
732        }
733        if (bperline) {
734            tkimg_Write(handle, "\0\0\0", bperline);
735        }
736    }
737    return(TCL_OK);
738}
739
740static void
741putint(handle, i)
742    tkimg_MFile *handle;
743    int i;
744{
745    unsigned char buf[4];
746    buf[0] = i;
747    buf[1] = i>>8;
748    buf[2] = i>>16;
749    buf[3] = i>>24;
750    tkimg_Write(handle, (char *) buf, 4);
751}
752