// This is ImageFileBMPWrite.cpp // // Copyright 1997, 1998 Mark Manca // #ifdef WIN32 #include #endif #include #include #include #include "ImageFile.h" #include "bmpFileHeader.h" #ifdef BIG_ENDIAN #include "byteSwap.h" #endif int ImageFile::_writeBMPFile() { bmpFileHeader fileHeader; bmpInfoHeader infoHeader; int status; int i, j; if (!__imageFile || !__isOpen) { return 0; } // // right now we will only support images that are bytes or unsigned // bytes. Otherwise, return 0. // if ((_imageDataType != GL_UNSIGNED_BYTE && _imageDataType != GL_BYTE) || (_colormapDataType != GL_UNSIGNED_BYTE && _colormapDataType != GL_BYTE)) { return 0; } // // get to the beginning of the file so we can write the // header out to the file // status = fseek(__imageFile, 0, SEEK_SET); if (status) { return 0; // an error occured } // // fill out the fileHeader // fileHeader.fileType[0] = 'B'; fileHeader.fileType[1] = 'M'; fileHeader.sizeOfFile = sizeof(bmpFileHeader) + sizeof(bmpInfoHeader); if (_imageType == GL_COLOR_INDEX) { fileHeader.sizeOfFile += 4 * _colormapSize; fileHeader.sizeOfFile += _width * _height; } else if (_imageType == GL_RGB) { fileHeader.sizeOfFile += 3 * _width * _height; } else if (_imageType == GL_RGBA) { fileHeader.sizeOfFile += 4 * _width * _height; } fileHeader.reserved1 = 0; fileHeader.reserved2 = 0; fileHeader.bitmapOffset = sizeof(bmpFileHeader) + sizeof(bmpInfoHeader); if (_imageType == GL_COLOR_INDEX) { fileHeader.bitmapOffset += 4 * _colormapSize; } // // fill out the infoHeader // infoHeader.sizeOfStruct = sizeof(bmpInfoHeader); infoHeader.width = _width; infoHeader.height = _height; infoHeader.planes = 1; if (_imageType == GL_COLOR_INDEX) { infoHeader.bitsPerPixel = 8; infoHeader.size = _width * _height; } else if (_imageType == GL_RGB) { infoHeader.bitsPerPixel = 24; infoHeader.size = 3 * _width * _height; } else if (_imageType == GL_RGBA) { infoHeader.bitsPerPixel = 32; infoHeader.size = 4 * _width * _height; } infoHeader.compression = 0; // not compressed infoHeader.xPixelsPerMeter = 2925; // ~72dpi infoHeader.yPixelsPerMeter = 2925; // ~72dpi if (_imageType == GL_COLOR_INDEX) { infoHeader.indicesUsed = _colormapSize; infoHeader.importantIndicies = 0; // all indices are important } else { infoHeader.indicesUsed = 0; infoHeader.importantIndicies = 0; } // // on machines with big endian byte order, we will have to swap things around. // #ifdef BIG_ENDIAN fileHeader.sizeOfFile = halfwordAndByteSwap(fileHeader->sizeOfFile); fileHeader.reserved1 = byteSwap(fileHeader->reserved1); fileHeader.reserved2 = byteSwap(fileHeader->reserved2); fileHeader.bitmapOffset = halfwordAndByteSwap(fileHeader->bitmapOffset); infoHeader.sizeOfStruct = halfwordAndByteSwap(infoHeader->sizeOfStruct); infoHeader.width = halfwordAndByteSwap(infoHeader->width); infoHeader.height = halfwordAndByteSwap(infoHeader->height); infoHeader.planes = byteSwap(infoHeader->planes); infoHeader.bitsPerPixel = byteSwap(infoHeader->bitsPerPixel); infoHeader.compression = halfwordAndByteSwap(infoHeader->compression); infoHeader.size = halfwordAndByteSwap(infoHeader->size); infoHeader.xPixelsPerMeter = halfwordAndByteSwap(infoHeader->xPixelsPerMeter); infoHeader.yPixelsPerMeter = halfwordAndByteSwap(infoHeader->yPixelsPerMeter); infoHeader.indicesUsed = halfwordAndByteSwap(infoHeader->indicesUsed); infoHeader.importantIndices = halfwordAndByteSwap(infoHeader->importantIndices); #endif // // now that the file header is set up, write it out to the file // status = fwrite((char*)&fileHeader, 1, sizeof(bmpFileHeader), __imageFile); if (status != sizeof(bmpFileHeader)) { return 0; } // // now that the file header is set up, write it out to the file // status = fwrite((char*)&infoHeader, 1, sizeof(bmpInfoHeader), __imageFile); if (status != sizeof(bmpInfoHeader)) { return 0; } // // if we have a color indexed image, write out the color table entries. // if (_imageType == GL_COLOR_INDEX) { int sizeOfColormapForDisk = _colormapSize * 4; rgbQuad* colormapForDisk = new rgbQuad[sizeOfColormapForDisk]; unsigned char* colormapPtr = (unsigned char*)_colormapData; rgbQuad* colormapForDiskPtr = colormapForDisk; for (i=_colormapSize; i > 0; i--) { colormapForDiskPtr->red = *colormapPtr++; colormapForDiskPtr->green = *colormapPtr++; colormapForDiskPtr->blue = *colormapPtr++; colormapForDiskPtr->reserved = 0; colormapForDiskPtr++; } // // now that the file header is set up, write it out to the file // status = fwrite((char*)colormapForDisk, 1, sizeOfColormapForDisk, __imageFile); if (status != sizeOfColormapForDisk) { delete colormapForDisk; return 0; } delete colormapForDisk; } // // now we are ready to write out the actual image. // unsigned char* imagePtr = (unsigned char*)_imageData; if (_imageType == GL_COLOR_INDEX) { for (i=_height; i > 0; i--) { // // write out a row at a time. // status = fwrite((char*)imagePtr, 1, _width, __imageFile); if (status != _width) { return 0; } imagePtr += _width; imagePtr += _extraRowWidth; } } else if (_imageType == GL_RGB) { int rgbRowSize = 3 * _width; unsigned char* rgbRow = new unsigned char[rgbRowSize]; unsigned char* rgbRowPtr; for (i=_height; i > 0; i--) { // // we have to rearrange the order of the rgb to bgr to conform // to the file format // rgbRowPtr = rgbRow; for (j=_width; j > 0; j--) { *rgbRowPtr++ = *(imagePtr + 2); *rgbRowPtr++ = *(imagePtr + 1); *rgbRowPtr++ = *imagePtr; imagePtr += 3; } // // I'm not sure why I have to do this, but it works. // //imagePtr -= 3; // // write out a row at a time. // status = fwrite((char*)rgbRow, 1, rgbRowSize, __imageFile); if (status != rgbRowSize) { delete rgbRow; return 0; } imagePtr += _extraRowWidth; } delete rgbRow; } else if (_imageType == GL_RGBA) { // // alpha is not supported yet in the bmp format although there is a // position for it in the 32 bit version of the bmp format. So, just // set it even though it will be ignored. // // // duplicate some code for efficiency purposes. // int rgbaRowSize = 4 * _width; unsigned char* rgbaRow = new unsigned char[rgbaRowSize]; unsigned char* rgbaRowPtr; for (i=_height; i > 0; i--) { // // we have to rearrange the order of the rgb to bgr to conform // to the file format // rgbaRowPtr = rgbaRow; for (j=_width; j > 0; j--) { *rgbaRowPtr++ = *(imagePtr + 2); *rgbaRowPtr++ = *(imagePtr + 1); *rgbaRowPtr++ = *imagePtr; *rgbaRowPtr++ = *(imagePtr + 3); imagePtr += 4; } // // write out a row at a time. // status = fwrite((char*)rgbaRow, 1, rgbaRowSize, __imageFile); if (status != rgbaRowSize) { delete rgbaRow; return 0; } imagePtr += _extraRowWidth; } delete rgbaRow; } // // if we've made it this far, we have successfully written out the // file, so return 1. // return 1; }