//--------------------------------------------------------// // // // File: WRTBMP.CPP // // // // Desc: Code to output a BMP file from a // // a VGA Display or a Memory Bitmap // // // //--------------------------------------------------------// #include "stdlib.h" #include "stdio.h" #include "string.h" #include "display.hpp" #include "imgstore.hpp" #include "bmp.hpp" //..................Abort macro #define ABORT( f, r ) { fclose(f); return r; } //..................Write VGA screen to BMP file 'fn' int WriteBMP( VgaDisplay& vga, char *nomeArq, int xIni, int yIni, int xFim, int yFim ) { FILE *hBmp = fopen( nomeArq , "wb" ); if( hBmp == NULL ) ABORT( hBmp, xIOERROR ); // image metrics int nLinhas = yFim - yIni + 1; int nCols = xFim - xIni + 1; int nBits = vga.metric.nplanes * vga.metric.nbits; int nCores = ( nBits <= 8) ? 1 << nBits : 0; int rowbytes = ((nCols*nBits + 31) / 32) * 4; // write an empty file header as a place holder xBITMAPFILEHEADER header; if( fwrite( &header, sizeof(xBITMAPFILEHEADER), 1, hBmp ) != 1 ) ABORT( hBmp, xIOERROR ); // initialize and write the image header xBITMAPINFOHEADER ih; ih.biSize = sizeof(xBITMAPINFOHEADER); ih.biWidth = nCols; ih.biHeight = nLinhas; ih.biPlanes = 1; ih.biBitCount = nBits; ih.biSizeImage = ((long) nLinhas) * ((long) rowbytes); if( fwrite( &ih, sizeof(xBITMAPINFOHEADER), 1, hBmp ) != 1 ) ABORT( hBmp, xIOERROR ); // write the display's palette xRGBQUAD x; if( nCores > 2 ) { rgb *pal = new rgb[nCores]; if( pal == 0 ) ABORT( hBmp, xNOMEMORY ); vga.getpalette( pal, nCores ); for( int i=0; i < nCores ; i++ ) { x.set( pal[i].red, pal[i].grn, pal[i].blu ); if( fwrite( &x, sizeof(xRGBQUAD), 1, hBmp ) != 1 ) { delete [] pal; ABORT( hBmp, xIOERROR ); } } delete [] pal; } else if( nCores > 0 ) { x.set( 0, 0, 0 ); if( fwrite( &x, sizeof(xRGBQUAD), 1, hBmp ) != 1 ) ABORT( hBmp, xIOERROR ); x.set( 255, 255, 255 ); if( fwrite( &x, sizeof(xRGBQUAD), 1, hBmp ) != 1 ) ABORT( hBmp, xIOERROR ); } // save offset to start of bitmap long bmpOFF = ftell( hBmp ); // output the bitmap unsigned char *pxls = new unsigned char [nCols]; if( pxls == 0 ) ABORT( hBmp, xNOMEMORY ); BmpEncoder bmp( hBmp, nBits ); for( int i=yFim; i>=yIni; i-- ) { vga.getscanline( pxls, nCols, xIni, i ); bmp.encode( pxls, nCols ); if( bmp.status() != xOKAY ) { delete pxls; ABORT( hBmp, bmp.status() ); } } // save offset to end of file long fisiz = ftell( hBmp ); // update and rewrite file header header.bfSize = fisiz; header.bfOffBits = bmpOFF; fseek( hBmp, 0L, SEEK_SET ); if( fwrite( &header, sizeof(xBITMAPFILEHEADER), 1, hBmp ) != 1 ) ABORT( hBmp, xIOERROR ); fclose( hBmp ); return xOKAY; } //..................Write an ImgStore to BMP file 'fn' int WriteBMP( ImgStore& img, rgb *pal, char *fn ) { FILE *f = fopen( fn, "wb" ); if( f == 0 ) ABORT( f, xIOERROR ); // image metrics int nrows = img.height(); int ncols = img.width(); int nbits = img.depth(); int ncolors = (nbits <= 8) ? 1 << nbits : 0; int rowbytes = ((ncols*nbits + 31) / 32) * 4; // write an empty file header as a place holder xBITMAPFILEHEADER fh; if( fwrite( &fh, sizeof(xBITMAPFILEHEADER), 1, f ) != 1 ) ABORT( f, xIOERROR ); // initialize and write the image header xBITMAPINFOHEADER ih; ih.biSize = sizeof(xBITMAPINFOHEADER); ih.biWidth = ncols; ih.biHeight = nrows; ih.biPlanes = 1; ih.biBitCount = nbits; ih.biSizeImage = ((long) nrows) * ((long) rowbytes); if( fwrite( &ih, sizeof(xBITMAPINFOHEADER), 1, f ) != 1 ) ABORT( f, xIOERROR ); // write the palette xRGBQUAD x; if( ncolors > 2 ) { for( int i=0; i 0 ) { x.set( 0, 0, 0 ); if( fwrite( &x, sizeof(xRGBQUAD), 1, f ) != 1 ) ABORT( f, xIOERROR ); x.set( 255, 255, 255 ); if( fwrite( &x, sizeof(xRGBQUAD), 1, f ) != 1 ) ABORT( f, xIOERROR ); } // save offset to start of bitmap long bmofs = ftell( f ); // output the bitmap BmpEncoder bmp( f, nbits ); for( int i=nrows-1; i>=0; i-- ) { bmp.encode( img.get(i), ncols ); if( bmp.status() != xOKAY ) ABORT( f, bmp.status() ); } // save offset to end of file long fisiz = ftell( f ); // Atualiza e regrava o cabecalho do arquivo .BMP fh.bfSize = fisiz; fh.bfOffBits = bmofs; fseek( f, 0L, SEEK_SET ); if( fwrite( &fh, sizeof(xBITMAPFILEHEADER), 1, f ) != 1 ) ABORT( f, xIOERROR ); fclose( f ); return xOKAY; }