#include "qbmploader.h"
#include <qimage.h>
#include <qvariant.h>
#include <qvector.h>
#include <QFile>
#include <QDebug>
#include <qmath.h>
namespace StoreBitmap{
static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels
{
int i;
if (image->depth() == 1 && image->colorCount() == 2) {
register uint *p = (uint *)image->bits();
int nbytes = image->byteCount();
for (i=0; i<nbytes/4; i++) {
*p = ~*p;
p++;
}
uchar *p2 = (uchar *)p;
for (i=0; i<(nbytes&3); i++) {
*p2 = ~*p2;
p2++;
}
QRgb t = image->color(0); // swap color 0 and 1
image->setColor(0, image->color(1));
image->setColor(1, t);
}
}
/*
QImageIO::defineIOHandler("BMP", "^BM", 0,
read_bmp_image, write_bmp_image);
*/
/*****************************************************************************
BMP (DIB) image read/write functions
*****************************************************************************/
const int BMP_FILEHDR_SIZE = 14; // size of BMP_FILEHDR data
static QDataStream &operator>>(QDataStream &s, BMP_FILEHDR &bf)
{ // read file header
s.readRawData(bf.bfType, 2);
s >> bf.bfSize >> bf.bfReserved1 >> bf.bfReserved2 >> bf.bfOffBits;
return s;
}
static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf)
{ // write file header
s.writeRawData(bf.bfType, 2);
s << bf.bfSize << bf.bfReserved1 << bf.bfReserved2 << bf.bfOffBits;
return s;
}
const int BMP_OLD = 12; // old Windows/OS2 BMP size
const int BMP_WIN = 40; // Windows BMP v3 size
const int BMP_OS2 = 64; // new OS/2 BMP size
const int BMP_WIN4 = 108; // Windows BMP v4 size
const int BMP_WIN5 = 124; // Windows BMP v5 size
const int BMP_RGB = 0; // no compression
const int BMP_RLE8 = 1; // run-length encoded, 8 bits
const int BMP_RLE4 = 2; // run-length encoded, 4 bits
const int BMP_BITFIELDS = 3; // RGB values encoded in data as bit-fields
static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi)
{
s >> bi.biSize;
if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) {
s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
s >> bi.biCompression >> bi.biSizeImage;
s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
s >> bi.biClrUsed >> bi.biClrImportant;
}
else { // probably old Windows format
qint16 w, h;
s >> w >> h >> bi.biPlanes >> bi.biBitCount;
bi.biWidth = w;
bi.biHeight = h;
bi.biCompression = BMP_RGB; // no compression
bi.biSizeImage = 0;
bi.biXPelsPerMeter = bi.biYPelsPerMeter = 0;
bi.biClrUsed = bi.biClrImportant = 0;
}
return s;
}
static QDataStream &operator<<(QDataStream &s, const BMP_INFOHDR &bi)
{
s << bi.biSize;
s << bi.biWidth << bi.biHeight;
s << bi.biPlanes;
s << bi.biBitCount;
s << bi.biCompression;
s << bi.biSizeImage;
s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
s << bi.biClrUsed << bi.biClrImportant;
return s;
}
static int calc_shift(int mask)
{
int result = 0;
while (mask && !(mask & 1)) {
result++;
mask >>= 1;
}
return result;
}
static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf)
{
// read BMP file header
s >> bf;
if (s.status() != QDataStream::Ok)
return false;
// check header
if (qstrncmp(bf.bfType,"BM",2) != 0)
return false;
return true;
}
static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
{
s >> bi; // read BMP info header
if (s.status() != QDataStream::Ok)
return false;
int nbits = bi.biBitCount;
int comp = bi.biCompression;
if (!(nbits == 1 || nbits == 4 || nbits == 8 || nbits == 16 || nbits == 24 || nbits == 32) ||
bi.biPlanes != 1 || comp > BMP_BITFIELDS)
return false; // weird BMP image
if (!(comp == BMP_RGB || (nbits == 4 && comp == BMP_RLE4) ||
(nbits == 8 && comp == BMP_RLE8) || ((nbits == 16 || nbits == 32) && comp == BMP_BITFIELDS)))
return false; // weird compression type
return true;
}
static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int startpos, QImage &image)
{
QIODevice* d = s.device();
if (d->atEnd()) // end of stream/file
return false;
#if 0
qDebug("offset...........%d", offset);
qDebug("startpos.........%d", startpos);
qDebug("biSize...........%d", bi.biSize);
qDebug("biWidth..........%d", bi.biWidth);
qDebug("biHeight.........%d", bi.biHeight);
qDebug("biPlanes.........%d", bi.biPlanes);
qDebug("biBitCount.......%d", bi.biBitCount);
qDebug("biCompression....%d", bi.biCompression);
qDebug("biSizeImage......%d", bi.biSizeImage);
qDebug("biXPelsPerMeter..%d", bi.biXPelsPerMeter);
qDebug("biYPelsPerMeter..%d", bi.biYPelsPerMeter);
qDebug("biClrUsed........%d", bi.biClrUsed);
qDebug("biClrImportant...%d", bi.biClrImportant);
#endif
int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
int t = bi.biSize, comp = bi.biCompression;
int red_mask = 0;
int green_mask = 0;
int blue_mask = 0;
int red_shift = 0;
int green_shift = 0;
int blue_shift = 0;
int red_scale = 0;
int green_scale = 0;
int blue_scale = 0;
int ncols = 0;
int depth = 0;
QImage::Format format;
switch (nbits) {
case 32:
case 24:
case 16:
depth = 32;
format = QImage::Format_RGB32;
break;
case 8:
case 4:
depth = 8;
format = QImage::Format_Indexed8;
break;
default:
depth = 1;
format = QImage::Format_Mono;
}
if (bi.biHeight < 0)
h = -h; // support images with negative height
if (image.size() != QSize(w, h) || image.format() != format) {
image = QImage(w, h, format);
if (image.isNull()) // could not create image
return false;
}
if (depth != 32) {
ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
if (ncols > 256) // sanity check - don't run out of mem if color table is broken
return false;
image.setColorCount(ncols);
}
image.setDotsPerMeterX(bi.biXPelsPerMeter);
image.setDotsPerMeterY(bi.biYPelsPerMeter);
if (!d->isSequential())
d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
return false;
if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
return false;
// Read BMP v4+ header
if (bi.biSize >= BMP_WIN4) {
int alpha_mask = 0;
int CSType =