From 5208c1aa1e7ec74b8dab040c95bb7a658037ccba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Sat, 17 Jun 2000 16:31:10 +0000 Subject: [PATCH] added new platform-independent BMP writing git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_2_BRANCH@7580 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/imagbmp.h | 7 +- src/common/imagbmp.cpp | 251 ++++++++++++++++------------------------- 2 files changed, 102 insertions(+), 156 deletions(-) diff --git a/include/wx/imagbmp.h b/include/wx/imagbmp.h index 92086f76f6..ea5f4657ff 100644 --- a/include/wx/imagbmp.h +++ b/include/wx/imagbmp.h @@ -31,12 +31,9 @@ public: m_mime = _T("image/bmp"); }; - // saving bitmaps is Windows-only -#ifdef __WIN32__ - virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=TRUE ); -#endif // __WIN32__ - #if wxUSE_STREAMS + virtual bool SaveFile( wxImage *image, wxOutputStream& stream, bool verbose=TRUE ); + virtual bool LoadFile( wxImage *image, wxInputStream& stream, bool verbose=TRUE, int index=0 ); virtual bool DoCanRead( wxInputStream& stream ); #endif // wxUSE_STREAMS diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 71a6665ec4..512acd2907 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -47,173 +47,121 @@ IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) -#ifdef __WIN32__ -#include +#if wxUSE_STREAMS -static void OutOfMemory(size_t nBytesNeeded) -{ - wxLogError(_("Failed to allocate %u bytes of memory."), nBytesNeeded); -} -// VZ: I'm not an expert in bitmaps, this is a quick and dirty C function I -// wrote some time ago and it probably doesn't deal properly with all -// bitmaps - any corrections/improvements are more than welcome. bool wxBMPHandler::SaveFile(wxImage *image, wxOutputStream& stream, bool verbose) { - // get HBITMAP first wxCHECK_MSG( image, FALSE, _T("invalid pointer in wxBMPHandler::SaveFile") ); - wxBitmap bitmap = image->ConvertToBitmap(); - HBITMAP hBmp = GetHbitmapOf(bitmap); - wxCHECK_MSG( hBmp, FALSE, _T("can't save invalid bitmap") ); - - // actual C code starts here - BITMAPFILEHEADER hdr; - BITMAPINFOHEADER *pbih; - BITMAP bmp; - WORD nClrBits; - size_t sizeOfBmi, sizeColTable; - BITMAPINFO *pbmi = NULL; - void *bmpData = NULL; - HDC hdc = NULL; - int rc = 0; - - /* - create and initialize BITMAPINFO - */ - - /* get the number of bitmap colours and its size */ - if ( !GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp) ) { - wxLogLastError(_T("GetObject")); - - goto cleanup; - } - - /* calc the number of colour bits needed */ - nClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); - if ( nClrBits == 1 ) nClrBits = 1; - else if ( nClrBits <= 4 ) nClrBits = 4; - else if ( nClrBits <= 8 ) nClrBits = 8; - else if ( nClrBits <= 16 ) nClrBits = 16; - else if ( nClrBits <= 24 ) nClrBits = 24; - else nClrBits = 32; - - /* alloc memory knowing that all bitmaps except 24bpp need extra RGBQUAD - * table */ - sizeOfBmi = sizeof(BITMAPINFOHEADER); - if ( nClrBits != 24 ) - sizeOfBmi += sizeof(RGBQUAD) * ( 1 << nClrBits); - - pbmi = (BITMAPINFO *)calloc(sizeOfBmi, 1); - if ( !pbmi ) { - OutOfMemory(sizeOfBmi); - - goto cleanup; - } - - /* initialize the fields in the BITMAPINFO structure */ - pbih = (BITMAPINFOHEADER *)pbmi; - pbih->biSize = sizeof(BITMAPINFOHEADER); - pbih->biWidth = bmp.bmWidth; - pbih->biHeight = bmp.bmHeight; - pbih->biPlanes = bmp.bmPlanes; - pbih->biBitCount = bmp.bmBitsPixel; - if ( nClrBits < 24 ) - pbih->biClrUsed = 1 << nClrBits; - pbih->biCompression = BI_RGB; - pbih->biSizeImage = 0; - pbih->biClrImportant = 0; - - /* let GetDIBits fill the size field, calc it ourselves if it didn't */ - hdc = CreateCompatibleDC(NULL); - if ( !hdc ) { - wxLogLastError(_T("CreateCompatibleDC(NULL)")); - - goto cleanup; - } - - (void)GetDIBits(hdc, hBmp, 0, pbih->biHeight, NULL, pbmi, DIB_RGB_COLORS); - if ( !pbih->biSizeImage ) - pbih->biSizeImage = (pbih->biWidth + 15) / 16 * pbih->biHeight * nClrBits; - - /* - get the data from the bitmap - */ - bmpData = malloc(pbih->biSizeImage); - if ( !bmpData ) { - OutOfMemory(pbih->biSizeImage); - - goto cleanup; - } - - if ( !GetDIBits(hdc, hBmp, - 0, pbih->biHeight, - bmpData, pbmi, DIB_RGB_COLORS) ) { - wxLogLastError(_T("GetDIBits")); - - goto cleanup; - } - - /* - write the data to the file - */ - - /* write the file header */ - sizeColTable = pbih->biClrUsed * sizeof(RGBQUAD); - hdr.bfType = 0x4d42; /* "BM" string */ - hdr.bfSize = sizeof(BITMAPFILEHEADER) + - pbih->biSize + sizeColTable + pbih->biSizeImage; - hdr.bfReserved1 = 0; - hdr.bfReserved2 = 0; - hdr.bfOffBits = hdr.bfSize - pbih->biSizeImage; - - if ( !stream.Write(&hdr, sizeof(hdr)) ) { - if ( verbose ) - wxLogError(_("Couldn't write the BMP file header.")); - - goto cleanup; - } - - /* write the bitmap header to the file */ - if ( !stream.Write(pbih, sizeof(BITMAPINFOHEADER) + sizeColTable) ) { - if ( verbose ) - wxLogError(_("Couldn't write the bitmap header.")); - - goto cleanup; - } - - /* write the data to the file */ - if ( !stream.Write(bmpData, pbih->biSizeImage) ) { - if ( verbose ) - wxLogError(_("Couldn't write bitmap data.")); - - goto cleanup; - } - - /* success */ - rc = 1; - -cleanup: - free(bmpData); - free(pbmi); - if ( hdc ) - DeleteDC(hdc); - - if ( !rc ) { - wxLogError(_("Failed to save the bitmap.")); - + if (!image->Ok()) + { + if (verbose) wxLogError(_("BMP: Couldn't save invalid image.")); return FALSE; } + unsigned width = image->GetWidth(); + unsigned row_width = width * 3 + + (((width % 4) == 0) ? 0 : (4 - (width * 3) % 4)); + // each row must be aligned to dwords + struct + { + // BitmapHeader: + wxUint16 magic; // format magic, always 'BM' + wxUint32 filesize; // total file size, inc. headers + wxUint32 reserved; // for future use + wxUint32 data_offset; // image data offset in the file + + // BitmapInfoHeader: + wxUint32 bih_size; // 2nd part's size + wxUint32 width, height; // bitmap's dimensions + wxUint16 planes; // num of planes + wxUint16 bpp; // bits per pixel + wxUint32 compression; // compression method + wxUint32 size_of_bmp; // size of the bitmap + wxUint32 h_res, v_res; // image resolution in dpi + wxUint32 num_clrs; // number of colors used + wxUint32 num_signif_clrs;// number of significant colors + } hdr; + wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; + + hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); + hdr.filesize = wxUINT32_SWAP_ON_BE( + hdr_size + + row_width * image->GetHeight() + ); + hdr.reserved = 0; + hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size); + + hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14); + hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth()); + hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight()); + hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane + hdr.bpp = wxUINT16_SWAP_ON_BE(24); // always TrueColor + hdr.compression = 0; // RGB uncompressed + hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); + hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard + hdr.num_clrs = 0; // maximal possible = 2^24 + hdr.num_signif_clrs = 0; // all colors are significant + + if (// VS: looks ugly but compilers tend to do ugly things with structs, + // like aligning hdr.filesize's ofset to dword :( + !stream.Write(&hdr.magic, 2) || + !stream.Write(&hdr.filesize, 4) || + !stream.Write(&hdr.reserved, 4) || + !stream.Write(&hdr.data_offset, 4) || + !stream.Write(&hdr.bih_size, 4) || + !stream.Write(&hdr.width, 4) || + !stream.Write(&hdr.height, 4) || + !stream.Write(&hdr.planes, 2) || + !stream.Write(&hdr.bpp, 2) || + !stream.Write(&hdr.compression, 4) || + !stream.Write(&hdr.size_of_bmp, 4) || + !stream.Write(&hdr.h_res, 4) || + !stream.Write(&hdr.v_res, 4) || + !stream.Write(&hdr.num_clrs, 4) || + !stream.Write(&hdr.num_signif_clrs, 4) + ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write the file header.")); + return FALSE; + } + + wxUint8 *data = (wxUint8*) image->GetData(); + wxUint8 *buffer = new wxUint8[row_width]; + wxUint8 tmpvar; + memset(buffer, 0, row_width); + int y; unsigned x; + + for (y = image->GetHeight() -1 ; y >= 0; y--) + { + memcpy(buffer, data + y * 3 * width, 3 * width); + for (x = 0; x < width; x++) + { + tmpvar = buffer[3 * x + 0]; + buffer[3 * x + 0] = buffer[3 * x + 2]; + buffer[3 * x + 2] = tmpvar; + } + + if (!stream.Write(buffer, row_width)) + { + if (verbose) + wxLogError(_("BMP: Couldn't write data.")); + delete[] buffer; + return FALSE; + } + } + delete[] buffer; + return TRUE; } -#endif // __WIN32__ -#if wxUSE_STREAMS + #ifndef BI_RGB #define BI_RGB 0 @@ -240,6 +188,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose } *cmap = NULL; off_t start_offset = stream.TellI(); + if (start_offset == wxInvalidOffset) start_offset = 0; image->Destroy();