X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e65ed37acbf64415b66ce91ddae2ad23e93aab78..dbcbe229628c7667da2b6257198467d4f09ab28d:/src/common/imagbmp.cpp?ds=sidebyside diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 05796710b4..e443eb4147 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -7,10 +7,9 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -/* - We don't put pragma implement in this file because it is already present in - src/common/image.cpp -*/ +#ifdef __GNUG__ +#pragma implementation "imagbmp.h" +#endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -19,7 +18,11 @@ #pragma hdrstop #endif -#include "wx/image.h" +#include "wx/defs.h" + +#if wxUSE_IMAGE + +#include "wx/imagbmp.h" #include "wx/bitmap.h" #include "wx/debug.h" #include "wx/log.h" @@ -46,12 +49,125 @@ // wxBMPHandler //----------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARIES IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) -#endif + #if wxUSE_STREAMS + +bool wxBMPHandler::SaveFile(wxImage *image, + wxOutputStream& stream, + bool verbose) +{ + wxCHECK_MSG( image, FALSE, _T("invalid pointer in wxBMPHandler::SaveFile") ); + + 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 :( + // VZ: we should add padding then... + !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; +} + + + + #ifndef BI_RGB #define BI_RGB 0 #define BI_RLE8 1 @@ -64,19 +180,20 @@ IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) #define poffset (line * width * 3 + column * 3) -bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) +bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) { int rshift = 0, gshift = 0, bshift = 0; wxUint8 aByte; wxUint16 aWord; - wxInt32 dbuf[4], aDword, - rmask = 0, gmask = 0, bmask = 0; + wxInt32 dbuf[4]; + wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0; wxInt8 bbuf[4]; struct _cmap { unsigned char r, g, b; } *cmap = NULL; - + off_t start_offset = stream.TellI(); + if (start_offset == wxInvalidOffset) start_offset = 0; image->Destroy(); @@ -84,10 +201,12 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) * Read the BMP header */ - stream.Read( &bbuf, 2 ); + stream.Read( bbuf, 2 ); stream.Read( dbuf, 4 * 4 ); +#if 0 // unused wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] ); +#endif wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] ); stream.Read(dbuf, 4 * 2); @@ -95,15 +214,17 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] ); if (width > 32767) { - wxLogError( _T("Image width > 32767 pixels for file.") ); + if (verbose) + wxLogError( _("BMP: Image width > 32767 pixels for file.") ); return FALSE; } if (height > 32767) { - wxLogError( _T("Image height > 32767 pixels for file.") ); + if (verbose) + wxLogError( _("BMP: Image height > 32767 pixels for file.") ); return FALSE; } - + stream.Read( &aWord, 2 ); /* TODO @@ -113,28 +234,31 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) int bpp = (int)wxUINT16_SWAP_ON_BE( aWord ); if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) { - wxLogError( _T("unknown bitdepth in file.") ); + if (verbose) + wxLogError( _("BMP: Unknown bitdepth in file.") ); return FALSE; } - + stream.Read( dbuf, 4 * 4 ); int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] ); if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS) { - wxLogError( _T("unknown encoding in Windows BMP file.") ); + if (verbose) + wxLogError( _("BMP: Unknown encoding in file.") ); return FALSE; } - + stream.Read( dbuf, 4 * 2 ); int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] ); if (ncolors == 0) ncolors = 1 << bpp; /* some more sanity checks */ - if (((comp == BI_RLE4) && (bpp != 4)) || - ((comp == BI_RLE8) && (bpp != 8)) || - ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) + if (((comp == BI_RLE4) && (bpp != 4)) || + ((comp == BI_RLE8) && (bpp != 8)) || + ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) { - wxLogError( _T("encoding of BMP doesn't match bitdepth.") ); + if (verbose) + wxLogError( _("BMP: Encoding doesn't match bitdepth.") ); return FALSE; } if (bpp < 16) @@ -142,7 +266,8 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors); if (!cmap) { - wxLogError( _T("Cannot allocate RAM for color map in BMP file.") ); + if (verbose) + wxLogError( _("BMP: Couldn't allocate memory.") ); return FALSE; } } @@ -153,7 +278,8 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) unsigned char *ptr = image->GetData(); if (!ptr) { - wxLogError( _T("Cannot allocate RAM for RGB data in file.") ); + if (verbose) + wxLogError( _("BMP: Couldn't allocate memory.") ); if (cmap) free(cmap); return FALSE; @@ -164,13 +290,26 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) */ if (bpp < 16 && ncolors != 0) { + unsigned char* r = new unsigned char[ncolors]; + unsigned char* g = new unsigned char[ncolors]; + unsigned char* b = new unsigned char[ncolors]; for (int j = 0; j < ncolors; j++) { stream.Read( bbuf, 4 ); cmap[j].b = bbuf[0]; cmap[j].g = bbuf[1]; cmap[j].r = bbuf[2]; + + r[j] = cmap[j].r; + g[j] = cmap[j].g; + b[j] = cmap[j].b; } + // Set the palette for the wxImage + image->SetPalette(wxPalette(ncolors, r, g, b)); + + delete[] r; + delete[] g; + delete[] b; } else if (bpp == 16 || bpp == 32) { @@ -229,13 +368,13 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) } ptr = data; } - + int line = 0; int column = 0; int linesize = ((width * bpp + 31) / 32) * 4; /* BMPs are stored upside down */ - for (line = (height - 1); line >= 0; line--) + for (line = (height - 1); line >= 0; line--) { int linepos = 0; for (column = 0; column < width;) @@ -248,7 +387,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) if (bpp == 1) { int bit = 0; - for (bit = 0; bit < 8; bit++) + for (bit = 0; bit < 8 && column < width; bit++) { index = ((aByte & (0x80 >> bit)) ? 1 : 0); ptr[poffset] = cmap[index].r; @@ -261,7 +400,8 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) { if (comp == BI_RLE4) { - wxLogError( _T("Can't deal with 4bit encoded yet.") ); + if (verbose) + wxLogError( _("BMP: Cannot deal with 4bit encoded yet.") ); image->Destroy(); free(cmap); return FALSE; @@ -269,7 +409,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) else { int nibble = 0; - for (nibble = 0; nibble < 2; nibble++) + for (nibble = 0; nibble < 2 && column < width; nibble++) { index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4)); if (index >= 16) @@ -325,7 +465,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) } else { - for (int l = 0; l < first; l++) + for (int l = 0; l < first && column < width; l++) { ptr[poffset ] = cmap[aByte].r; ptr[poffset + 1] = cmap[aByte].g; @@ -341,13 +481,13 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) ptr[poffset + 1] = cmap[aByte].g; ptr[poffset + 2] = cmap[aByte].b; column++; - linepos += size; + // linepos += size; seems to be wrong, RR } } } else if (bpp == 24) { - stream.Read( &bbuf, 3 ); + stream.Read( bbuf, 3 ); linepos += 3; ptr[poffset ] = (unsigned char)bbuf[2]; ptr[poffset + 1] = (unsigned char)bbuf[1]; @@ -358,13 +498,13 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) { unsigned char temp; stream.Read( &aWord, 2 ); - aWord = wxUINT16_SWAP_ON_BE( aWord ); + aWord = wxUINT16_SWAP_ON_BE( aWord ); linepos += 2; temp = (aWord & rmask) >> rshift; ptr[poffset] = temp; temp = (aWord & gmask) >> gshift; ptr[poffset + 1] = temp; - temp = (aWord & bmask) >> gshift; + temp = (aWord & bmask) >> bshift; ptr[poffset + 2] = temp; column++; } @@ -372,7 +512,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) { unsigned char temp; stream.Read( &aDword, 4 ); - aDword = wxINT32_SWAP_ON_BE( aDword ); + aDword = wxINT32_SWAP_ON_BE( aDword ); linepos += 4; temp = (aDword & rmask) >> rshift; ptr[poffset] = temp; @@ -391,7 +531,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) break; } } - if (cmap) + if (cmap) free(cmap); image->SetMask( FALSE ); @@ -399,6 +539,15 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream ) return TRUE; } -#endif // wxUSE_STREAMS +bool wxBMPHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + stream.Read(hdr, 2); + stream.SeekI(-2, wxFromCurrent); + return (hdr[0] == 'B' && hdr[1] == 'M'); +} + +#endif // wxUSE_STREAMS +#endif // wxUSE_IMAGE