diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-01-08 21:04:08 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-01-08 21:04:08 (GMT) |
commit | 6dac183be1cdcc0a13966343e2c40c3ff56a3810 (patch) | |
tree | 802a6a87435da647463c945cf3571d52a84aad55 /tkimg/bmp/bmp.c | |
parent | dbbb38af9cefef9e9e1a03c97945ee59063aa782 (diff) | |
download | blt-6dac183be1cdcc0a13966343e2c40c3ff56a3810.zip blt-6dac183be1cdcc0a13966343e2c40c3ff56a3810.tar.gz blt-6dac183be1cdcc0a13966343e2c40c3ff56a3810.tar.bz2 |
update tkimg 1.4.7
Diffstat (limited to 'tkimg/bmp/bmp.c')
-rw-r--r-- | tkimg/bmp/bmp.c | 857 |
1 files changed, 857 insertions, 0 deletions
diff --git a/tkimg/bmp/bmp.c b/tkimg/bmp/bmp.c new file mode 100644 index 0000000..0babc16 --- /dev/null +++ b/tkimg/bmp/bmp.c @@ -0,0 +1,857 @@ +/* + * bmp.c -- + * + * BMP photo image type, Tcl/Tk package + * + * Copyright (c) 1997-2003 Jan Nijtmans <nijtmans@users.sourceforge.net> + * Copyright (c) 2002 Andreas Kupries <andreas_kupries@users.sourceforge.net> + * + * The following format options are available: + * + * Write BMP image: "ico -resolution <list>" + * + * -resolution <list>: Set the resolution property of the output file. + * The default is 74 dpi (no option) + * Possible forms for list: + * {xRes unit} : set x and y resolution to same value + * {xRes yRes} : set x to 74dpi and y to 74*YRes/XRes + * {xRes yRes unit} : set x and y resolution to given values + * xRes, yRes are floats >= 0. 0 is the "no value" value. + * unit is one of "c" cm, "m" mm, "i" inch or "p" inch/72. + */ + +/* + * Generic initialization code, parameterized via CPACKAGE and PACKAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "init.c" + +/* Compression types */ +#define BI_RGB 0 +#define BI_RLE8 1 +#define BI_RLE4 2 +#define BI_BITFIELDS 3 + +/* Structure for reading bit masks for compression type BI_BITFIELDS */ +typedef struct { + unsigned int mask; + unsigned int shiftin; + unsigned int shiftout; +} BitmapChannel; + +/* + * Now the implementation + */ +/* + * Prototypes for local procedures defined in this file: + */ + +static int CommonMatch(tkimg_MFile *handle, int *widthPtr, + int *heightPtr, unsigned char **colorMap, int *numBits, + int *numCols, int *comp, unsigned int *mask); + +static int CommonRead(Tcl_Interp *interp, tkimg_MFile *handle, + Tk_PhotoHandle imageHandle, int destX, int destY, int width, + int height, int srcX, int srcY); + +static int CommonWrite(Tcl_Interp *interp, Tcl_Obj *format, + tkimg_MFile *handle, + Tk_PhotoImageBlock *blockPtr); + +static void putint(tkimg_MFile *handle, int i); + +/* + * Entrypoints for the photo image type. + */ + +static int +ChnMatch( + Tcl_Channel chan, + const char *fileName, + Tcl_Obj *format, + int *widthPtr, + int *heightPtr, + Tcl_Interp *interp +) { + tkimg_MFile handle; + + handle.data = (char *) chan; + handle.state = IMG_CHAN; + + return CommonMatch(&handle, widthPtr, heightPtr, + NULL, NULL, NULL, NULL, NULL); +} + +static int +ObjMatch( + Tcl_Obj *data, + Tcl_Obj *format, + int *widthPtr, + int *heightPtr, + Tcl_Interp *interp +) { + tkimg_MFile handle; + + if (!tkimg_ReadInit(data, 'B', &handle)) { + return 0; + } + return CommonMatch(&handle, widthPtr, heightPtr, + NULL, NULL, NULL, NULL, NULL); +} + +static int +ChnRead(interp, chan, fileName, format, imageHandle, + destX, destY, width, height, srcX, srcY) + Tcl_Interp *interp; + Tcl_Channel chan; + const char *fileName; + Tcl_Obj *format; + Tk_PhotoHandle imageHandle; + int destX, destY; + int width, height; + int srcX, srcY; +{ + tkimg_MFile handle; + + handle.data = (char *) chan; + handle.state = IMG_CHAN; + + return CommonRead(interp, &handle, imageHandle, destX, destY, + width, height, srcX, srcY); +} + +static int +ObjRead(interp, data, format, imageHandle, + destX, destY, width, height, srcX, srcY) + Tcl_Interp *interp; + Tcl_Obj *data; + Tcl_Obj *format; + Tk_PhotoHandle imageHandle; + int destX, destY; + int width, height; + int srcX, srcY; +{ + tkimg_MFile handle; + + tkimg_ReadInit(data,'B',&handle); + return CommonRead(interp, &handle, imageHandle, destX, destY, + width, height, srcX, srcY); +} + +static int +ChnWrite(interp, filename, format, blockPtr) + Tcl_Interp *interp; + const char *filename; + Tcl_Obj *format; + Tk_PhotoImageBlock *blockPtr; +{ + Tcl_Channel chan; + tkimg_MFile handle; + int result; + + chan = tkimg_OpenFileChannel(interp, filename, 0644); + if (!chan) { + return TCL_ERROR; + } + + handle.data = (char *) chan; + handle.state = IMG_CHAN; + + result = CommonWrite(interp, format, &handle, blockPtr); + if (Tcl_Close(interp, chan) == TCL_ERROR) { + return TCL_ERROR; + } + return result; +} + +static int StringWrite( + Tcl_Interp *interp, + Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr +) { + tkimg_MFile handle; + int result; + Tcl_DString data; + + Tcl_DStringInit(&data); + tkimg_WriteInit(&data, &handle); + result = CommonWrite(interp, format, &handle, blockPtr); + tkimg_Putc(IMG_DONE, &handle); + + if (result == TCL_OK) { + Tcl_DStringResult(interp, &data); + } else { + Tcl_DStringFree(&data); + } + return result; +} + +static unsigned int +getUInt32(buf) + unsigned char *buf; +{ + return (buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); +} + +static unsigned int +getUInt16(buf) + unsigned char *buf; +{ + return (buf[0] | buf[1] << 8); +} + +static void +GetChannelMasks(intMask, masks) + unsigned int *intMask; + BitmapChannel *masks; +{ + unsigned int mask; + int i, nbits, offset, bit; + + for (i=0; i<3; i++) { + mask = getUInt32((unsigned char *) &intMask[i]); + masks[i].mask = mask; + nbits = 0; + offset = -1; + for (bit=0; bit<32; bit++) { + if (mask & 1) { + nbits++; + if (offset == -1) { + offset = bit; + } + } + mask = mask >> 1; + } + masks[i].shiftin = offset; + masks[i].shiftout = 8 - nbits; + } +} + +/* + * Helper functions for the entry points. Work horses. + */ + +static int +CommonMatch(handle, widthPtr, heightPtr, colorMap, numBits, numCols, comp, mask) + tkimg_MFile *handle; + int *widthPtr, *heightPtr; + unsigned char **colorMap; + int *numBits, *numCols, *comp; + unsigned int *mask; +{ + unsigned char buf[28]; + int c,i, compression, nBits, clrUsed, offBits; + + if ((tkimg_Read(handle, (char *) buf, 2) != 2) + || (strncmp("BM", (char *) buf, 2) != 0) + || (tkimg_Read(handle, (char *) buf, 24) != 24) + || buf[13] || buf[14] || buf[15]) { + return 0; + } + + offBits = (buf[11]<<24) + (buf[10]<<16) + (buf[9]<<8) + buf[8]; + c = buf[12]; + if ((c == 40) || (c == 64)) { + *widthPtr = (buf[19]<<24) + (buf[18]<<16) + (buf[17]<<8) + buf[16]; + *heightPtr = (buf[23]<<24) + (buf[22]<<16) + (buf[21]<<8) + buf[20]; + if (tkimg_Read(handle, (char *) buf, 24) != 24) { + return 0; + } + nBits = buf[2]; + compression = buf[4]; + clrUsed = (buf[21]<<8) + buf[20]; + offBits -= c+14; + } else if (c == 12) { + *widthPtr = (buf[17]<<8) + buf[16]; + *heightPtr = (buf[19]<<8) + buf[18]; + nBits = buf[22]; + compression = BI_RGB; + clrUsed = 0; + } else { + return 0; + } + if (*widthPtr <= 0 || *heightPtr <= 0) + return 0; + + if (colorMap) { + if (c > 36) tkimg_Read(handle, (char *) buf, c - 36); + if (compression == BI_BITFIELDS) { + /* Read the channel masks. */ + tkimg_Read(handle, (char *) buf, 3*4); + if (mask) { + mask[0] = getUInt32((unsigned char *) &buf[0]); + mask[1] = getUInt32((unsigned char *) &buf[4]); + mask[2] = getUInt32((unsigned char *) &buf[8]); + } + offBits -= 3*4; + } + if (!clrUsed && nBits < 24) { + clrUsed = 1 << nBits; + } + if (nBits<16) { + unsigned char colbuf[4], *ptr; + offBits -= (3+(c!=12)) * clrUsed; + *colorMap = ptr = (unsigned char *) ckalloc(3*clrUsed); + for (i = 0; i < clrUsed; i++) { + tkimg_Read(handle, (char *) colbuf, 3+(c!=12)); + *ptr++ = colbuf[0]; *ptr++ = colbuf[1]; *ptr++ = colbuf[2]; + /*printf("color %d: %d %d %d\n", i, colbuf[2], colbuf[1], colbuf[0]);*/ + } + } + while (offBits>28) { + offBits -= 28; + tkimg_Read(handle, (char *) buf, 28); + } + if (offBits) tkimg_Read(handle, (char *) buf, offBits); + if (numCols) { + *numCols = clrUsed; + } + } + if (numBits) { + *numBits = nBits; + } + if (comp) { + *comp = compression; + } + return 1; +} + +static int +CommonRead(interp, handle, imageHandle, destX, destY, + width, height, srcX, srcY) + Tcl_Interp *interp; + tkimg_MFile *handle; + Tk_PhotoHandle imageHandle; + int destX, destY; + int width, height; + int srcX, srcY; +{ + Tk_PhotoImageBlock block; + int numBits, bytesPerLine, numCols, comp, x, y; + int fileWidth, fileHeight; + unsigned char *colorMap = NULL; + unsigned int intMask[3]; + BitmapChannel masks[3]; + char buf[10]; + unsigned char *line = NULL, *expline = NULL; + unsigned short rgb; + + CommonMatch(handle, &fileWidth, &fileHeight, &colorMap, &numBits, + &numCols, &comp, intMask); + + if (numBits == 16) { + if (comp == BI_BITFIELDS) { + GetChannelMasks(intMask, masks); + } else { + masks[0].mask = 0x7c00; + masks[0].shiftin = 10; + masks[0].shiftout = 3; + masks[1].mask = 0x03e0; + masks[1].shiftin = 5; + masks[1].shiftout = 3; + masks[2].mask = 0x001f; + masks[2].shiftin = 0; + masks[2].shiftout = 3; + } + } + + /* printf("reading %d-bit BMP %dx%d\n", numBits, width, height); */ + if (comp == BI_RLE8 || comp == BI_RLE4) { + tkimg_ReadBuffer(1); + } + + if (tkimg_PhotoExpand(interp, imageHandle, destX + width, destY + height) == TCL_ERROR) { + goto error; + } + + bytesPerLine = ((numBits * fileWidth + 31)/32)*4; + + /* printf("bytesPerLine = %d numBits=%d (%dx%d)\n", + * bytesPerLine, numBits, width, height); + */ + block.pixelSize = 3; + block.pitch = width * 3; + block.width = width; + block.height = 1; + block.offset[0] = 2; + block.offset[1] = 1; + block.offset[2] = 0; + block.offset[3] = block.offset[0]; + + if (comp == BI_RGB || comp == BI_BITFIELDS) { /* No compression */ + line = (unsigned char *) ckalloc(bytesPerLine); + for(y=srcY+height; y<fileHeight; y++) { + tkimg_Read(handle, (char *)line, bytesPerLine); + } + switch (numBits) { + case 32: + block.pixelPtr = expline = (unsigned char *) ckalloc(3*width); + for( y = height-1; y>=0; y--) { + tkimg_Read(handle, (char *)line, bytesPerLine); + for (x = srcX; x < (srcX+width); x++) { + *expline++ = line[x*4 + 0]; + *expline++ = line[x*4 + 1]; + *expline++ = line[x*4 + 2]; + } + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + expline = block.pixelPtr; + } + break; + case 24: + block.pixelPtr = line + srcX*3; + for( y = height-1; y>=0; y--) { + tkimg_Read(handle, (char *)line, bytesPerLine); + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + } + break; + case 16: + block.pixelPtr = expline = (unsigned char *) ckalloc(3*width); + for( y = height-1; y>=0; y--) { + tkimg_Read(handle, (char *)line, bytesPerLine); + for (x = srcX; x < (srcX+width); x++) { + rgb = getUInt16 (&line[x*2]); + *expline++ = ((rgb & masks[2].mask) >> masks[2].shiftin) << masks[2].shiftout; + *expline++ = ((rgb & masks[1].mask) >> masks[1].shiftin) << masks[1].shiftout; + *expline++ = ((rgb & masks[0].mask) >> masks[0].shiftin) << masks[0].shiftout; + } + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + expline = block.pixelPtr; + } + break; + case 8: + block.pixelPtr = expline = (unsigned char *) ckalloc(3*width); + for( y = height-1; y>=0; y--) { + tkimg_Read(handle, (char *)line, bytesPerLine); + for (x = srcX; x < (srcX+width); x++) { + memcpy(expline, colorMap+(3*line[x]),3); + expline += 3; + } + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + expline = block.pixelPtr; + } + break; + case 4: + block.pixelPtr = expline = (unsigned char *) ckalloc(3*width); + for( y = height-1; y>=0; y--) { + int c; + tkimg_Read(handle, (char *)line, bytesPerLine); + for (x = srcX; x < (srcX+width); x++) { + if (x&1) { + c = line[x/2] & 0x0f; + } else { + c = line[x/2] >> 4; + } + memcpy(expline, colorMap+(3*c),3); + expline += 3; + } + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + expline = block.pixelPtr; + } + break; + case 1: + block.pixelPtr = expline = (unsigned char *) ckalloc(3*width); + for( y = height-1; y>=0; y--) { + int c; + tkimg_Read(handle, (char *)line, bytesPerLine); + for (x = srcX; x < (srcX+width); x++) { + c = (line[x/8] >> (7-(x%8))) & 1; + memcpy(expline, colorMap+(3*c),3); + expline += 3; + } + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, + destX, destY+y, width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + expline = block.pixelPtr; + } + break; + default: + sprintf(buf, "%d", numBits); + Tcl_AppendResult(interp, buf, + "-bits BMP file not (yet) supported", (char *) NULL); + goto error; + } + } else { /* RLE Compression */ + int i, j, c; + unsigned char howMuch; + unsigned char rleBuf[2]; + unsigned char rleDelta[2]; + unsigned char val; + + x = srcX; + y = fileHeight - 1; + block.pixelPtr = expline = (unsigned char *) ckalloc (3*fileWidth); + + if (numBits != 4 && numBits != 8) { + sprintf (buf, "%d", numBits); + Tcl_AppendResult(interp, "RLE compression not supported for ", + buf, "-bit pixel values", (char *) NULL); + goto error; + } + + while (1) { + if (2 != tkimg_Read(handle, (char *)rleBuf, 2)) { + Tcl_AppendResult(interp, "Unexpected EOF", (char *) NULL); + goto error; + } + /* printf("In: (%d %X) --> \n", rleBuf[0], rleBuf[1]); */ + if (rleBuf[0] != 0) { + howMuch = rleBuf[0]; + switch (numBits) { + case 8: { + for (i=0; i<howMuch; i++, x++) { + memcpy (expline, colorMap + 3*rleBuf[1], 3); + expline += 3; + } + break; + } + case 4: { + for (i=0; i<howMuch; i++, x++) { + if (x&1) { + c = rleBuf[1] & 0x0f; + } else { + c = rleBuf[1] >> 4; + } + memcpy(expline, colorMap + 3*c, 3); + if (x>=srcX+width-1) { + break; + } + expline += 3; + } + break; + } + } + } else { + if (rleBuf[1]>2) { + /* uncompressed record */ + howMuch = rleBuf[1]; + /* printf ("Uncompressed: %d\n", howMuch); fflush (stdout); */ + switch (numBits) { + case 8: { + for (i=0; i<howMuch; i++, x++) { + if (1 != tkimg_Read(handle, (char *)&val, 1)) { + Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL); + goto error; + } + memcpy(expline, colorMap + 3*val, 3); + expline += 3; + } + break; + } + case 4: { + for (i=0; i<howMuch; i+=2) { + if (1 != tkimg_Read(handle, (char *)&val, 1)) { + Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL); + goto error; + } + for (j=0; j<2; j++, x++) { + if (x&1) { + c = val & 0x0f; + } else { + c = val >> 4; + } + memcpy(expline, colorMap + 3*c, 3); + if (x>=srcX+width-1) { + break; + } + expline += 3; + } + } + break; + } + } + + if ((howMuch % 2) && (numBits==4)) { + howMuch++; + } + + if ((howMuch / (8 / numBits)) % 2) { + if (1 != tkimg_Read(handle, (char *)&val, 1)) { + Tcl_AppendResult(interp, "Unexpected EOF", (char *)NULL); + goto error; + } + } + } else if (rleBuf[1]==0) { + /* End of line */ + /* printf("New line: y=%d x=%d\n", y, x); fflush(stdout); */ + if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, destY+y, + width, 1, TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { + goto error; + } + y--; + x = srcX; + expline = block.pixelPtr; + } else if (rleBuf[1]==1) { + /* End of bitmap */ + break; + } else if (rleBuf[1]==2) { + /* Deltarecord */ + /* printf("Deltarecord\n"); fflush(stdout); */ + if (2 != tkimg_Read(handle, (char *) rleDelta, 2)) { + Tcl_AppendResult(interp, "Unexpected EOF", (char *) NULL); + goto error; + } + x += rleDelta[0]; + y += rleDelta[1]; + } + } + } + } + tkimg_ReadBuffer(0); + + if (colorMap) { + ckfree((char *) colorMap); + } + if (line) { + ckfree((char *) line); + } + if (expline) { + ckfree((char *) block.pixelPtr); + } + return TCL_OK ; + +error: + tkimg_ReadBuffer(0); + if (colorMap) { + ckfree((char *) colorMap); + } + if (line) { + ckfree((char *) line); + } + if (expline) { + ckfree((char *) block.pixelPtr); + } + return TCL_ERROR; +} + +static int +CommonWrite(interp, format, handle, blockPtr) + Tcl_Interp *interp; + Tcl_Obj *format; + tkimg_MFile *handle; + Tk_PhotoImageBlock *blockPtr; +{ + int bperline, nbytes, ncolors, i, x, y, greenOffset, blueOffset, alphaOffset; + unsigned char *imagePtr, *pixelPtr; + unsigned char buf[4]; + int colors[256]; + int resX=75*39, resY=75*39; + int objc = 0; + Tcl_Obj **objv = NULL; + + /* Decode resolution parameter -resolution List */ + if (tkimg_ListObjGetElements(interp, format, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + /* List parameter given ? */ + if (objc > 1) { + Tcl_Obj *objList; + int nBytes; + double fResX = -1, fResY = -1, fFactor = 0; + char unit = '\0'; + char *c = Tcl_GetStringFromObj(objv[1], &nBytes); + if ((objc > 3) || ((objc == 3) && ((c[0] != '-') || + (c[1] != 'r') || strncmp(c, "-resolution", strlen(c))))) { + Tcl_AppendResult(interp, "invalid format: \"", + tkimg_GetStringFromObj(format, NULL), "\"", (char *) NULL); + return TCL_ERROR; + } + objList = objv[objc-1]; + if (tkimg_ListObjGetElements(interp, objList, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + if (!objc || objc > 3) { + Tcl_AppendResult(interp, "Wrong resolution parameters: \"", + tkimg_GetStringFromObj(objList, NULL), "\"", (char *) NULL); + return TCL_ERROR; + } + if (Tcl_GetDoubleFromObj(interp, objv[0], &fResX) != TCL_OK) { + return TCL_ERROR; + } + if ( fResX < 0 || fResX > 1e20 ) { + Tcl_AppendResult(interp, "Wrong resolution: \"", + tkimg_GetStringFromObj(objv[0], NULL), "\"", (char *) NULL); + return TCL_ERROR; + } + /* more than xRes value given ? */ + if (objc > 1) { + /* check last for unit */ + c = Tcl_GetStringFromObj(objv[objc-1], &nBytes); + if ( nBytes == 1 && ( c[0] == 'c' || c[0] == 'i' || c[0] == 'm' || c[0] == 'p') ) { + unit = c[0]; + objc--; + } + if (objc > 2) { + Tcl_AppendResult(interp, "Wrong unit: \"", + tkimg_GetStringFromObj(objv[objc-1], NULL), "\"", (char *) NULL); + return TCL_ERROR; + } + if (objc > 1) { + if (Tcl_GetDoubleFromObj(interp, objv[1], &fResY) != TCL_OK) { + return TCL_ERROR; + } + if ( fResY < 0 || fResY > 1e20 ) { + Tcl_AppendResult(interp, "Wrong resolution: \"", + tkimg_GetStringFromObj(objv[0], NULL), "\"", (char *) NULL); + return TCL_ERROR; + } + } + } + /* Process unit and eventually get factor value */ + switch (unit) { + case 'c': /* centimeter */ + fFactor = 100.0; + break; + case 'i': /* inches */ + fFactor = 1.0/0.0254; + break; + case 'm': /* millimeter */ + fFactor = 1000.0; + break; + case 'p': /* printer points (1/72 inch) */ + fFactor = 72.0/0.0254; + break; + default: /* no unit given - 75*39 as X resolution */ + if (fResX == 0) { + resX = 0; + resY = 0; + } else { + if (fResY != -1) { + resY = (int) ( fResY * 75.0*39.0 / fResX + 0.5); + } + } + break; + } + if (fFactor != 0) { + resX = (int) ( fResX * fFactor + 0.5); + if (fResY == -1) { + resY = resX; + } else { + resY = (int) ( fResY * fFactor + 0.5); + } + } + } + + greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; + blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; + alphaOffset = blockPtr->offset[0]; + if (alphaOffset < blockPtr->offset[2]) { + alphaOffset = blockPtr->offset[2]; + } + if (++alphaOffset < blockPtr->pixelSize) { + alphaOffset -= blockPtr->offset[0]; + } else { + alphaOffset = 0; + } + ncolors = 0; + for (y = 0; ncolors <= 256 && y < blockPtr->height; y++) { + pixelPtr = blockPtr->pixelPtr + y*blockPtr->pitch + blockPtr->offset[0]; + for (x=0; ncolors <= 256 && x<blockPtr->width; x++) { + int pixel; + if (alphaOffset && (pixelPtr[alphaOffset] == 0)) + pixel = 0xd9d9d9; + else + pixel = (pixelPtr[0]<<16) | (pixelPtr[greenOffset]<<8) | pixelPtr[blueOffset]; + for (i = 0; i < ncolors && pixel != colors[i]; i++); + if (i == ncolors) { + if (ncolors < 256) { + colors[ncolors] = pixel; + } + ncolors++; + } + pixelPtr += blockPtr->pixelSize; + } + } + if (ncolors <= 256 && (blockPtr->width * blockPtr->height >= 512)) { + while (ncolors < 256) { + colors[ncolors++] = 0; + } + nbytes = 1; + } else { + nbytes = 3; + ncolors = 0; + } + + bperline = ((blockPtr->width * nbytes + 3) / 4) * 4; + + tkimg_Write(handle,"BM", 2); + putint(handle, 54 + (ncolors*4) + bperline * blockPtr->height); + putint(handle, 0); + putint(handle, 54 + (ncolors*4)); + putint(handle, 40); + putint(handle, blockPtr->width); + putint(handle, blockPtr->height); + putint(handle, 1 + (nbytes<<19)); + putint(handle, 0); + putint(handle, bperline * blockPtr->height); + putint(handle, resX); + putint(handle, resY); + putint(handle, ncolors); + putint(handle, ncolors); + + for (i = 0; i < ncolors ; i++) { + putint(handle, colors[i]); + } + + bperline -= blockPtr->width * nbytes; + + imagePtr = blockPtr->pixelPtr + blockPtr->offset[0] + + blockPtr->height * blockPtr->pitch; + for (y = 0; y < blockPtr->height; y++) { + pixelPtr = imagePtr -= blockPtr->pitch; + for (x=0; x<blockPtr->width; x++) { + if (ncolors) { + int pixel; + if (alphaOffset && (pixelPtr[alphaOffset] == 0)) + pixel = 0xd9d9d9; + else + pixel = (pixelPtr[0]<<16)|(pixelPtr[greenOffset]<<8)|pixelPtr[blueOffset]; + for (i = 0; i < ncolors && pixel != colors[i]; i += 1); + buf[0] = i; + } else if (alphaOffset && (pixelPtr[alphaOffset] == 0)) { + buf[0] = buf[1] = buf[2] = 0xd9; + } else { + buf[0] = pixelPtr[blueOffset]; + buf[1] = pixelPtr[greenOffset]; + buf[2] = pixelPtr[0]; + } + tkimg_Write(handle, (char *) buf, nbytes); + pixelPtr += blockPtr->pixelSize; + } + if (bperline) { + tkimg_Write(handle, "\0\0\0", bperline); + } + } + return(TCL_OK); +} + +static void +putint(handle, i) + tkimg_MFile *handle; + int i; +{ + unsigned char buf[4]; + buf[0] = i; + buf[1] = i>>8; + buf[2] = i>>16; + buf[3] = i>>24; + tkimg_Write(handle, (char *) buf, 4); +} |