最近在项目中实现壁纸预览功能时,遇到了图片无法正常加载的问题。开始策略是在重绘事件中直接加载硬盘中的图片文件,代码如下:
void YourClass::paintEvent(QPaintEvent* event)
{
QPainter p(this);
p.drawPixmap(0, 0, width(), height(), QPixmap("E:/c++proj/testBlog/StockSnap_3C5NLBSRKD.jpg").scaled(width(), height(), Qt::KeepAspectRatio));
}
当图片较大的时候,主机性能较差时,界面显示白屏,无法正常加载图片。效果如下:

之后变选择使用imagereader的方法读取图片:代码如下:
void YourClass::paintEvent(QPaintEvent* event)
{
QPainter p(this);
QImageReader reader;
QImage image;
reader.setDecideFormatFromContent(true);
reader.setScaledSize(QSize(width(), height()));
reader.setFileName("E:/c++proj/testBlog/Image/StockSnap_3C5NLBSRKD.jpg");
if (reader.canRead())
{
if (!reader.read(&image))
{
QImageReader::ImageReaderError error = reader.error();
QString strError = reader.errorString();
printf("last error:%s\n", strError.toStdString().c_str());
return;
}
}
p.drawPixmap(0, 0, width(), height(), QPixmap::fromImage(image)/*.scaled(width(), height(), Qt::KeepAspectRatio)*/);
}
此时可正常显示:

但遇到一个100M的BMP图片无法加载的问题,查阅资料得知加载时较大的图片会因内存不足无法加载,显示一片空白,此时可通过分段读取的方法解决。
具体代码如下:
QBmpLoader.h
#pragma once
#include <QtGui/QImageIOHandler>
struct BMP_FILEHDR { // BMP file header
char bfType[2]; // "BM"
qint32 bfSize; // size of file
qint16 bfReserved1;
qint16 bfReserved2;
qint32 bfOffBits; // pointer to the pixmap bits
};
struct BMP_INFOHDR { // BMP information header
qint32 biSize; // size of this struct
qint32 biWidth; // pixmap width
qint32 biHeight; // pixmap height
qint16 biPlanes; // should be 1
qint16 biBitCount; // number of bits per pixel
qint32 biCompression; // compression method
qint32 biSizeImage; // size of image
qint32 biXPelsPerMeter; // horizontal resolution
qint32 biYPelsPerMeter; // vertical resolution
qint32 biClrUsed; // number of colors used
qint32 biClrImportant; // number of important colors
};
namespace setting
{
class QBmpLoader
{
public:
enum State {
Ready,
ReadHeader,
Error
};
QIODevice* device();
void setDevice(QIODevice *device);
QBmpLoader();
bool setImagePath(QString imagePath);
bool read(QImage *image);
bool read(QImage *image, const QRect& rc);
bool read(QImage *image, const QRect& range
, double dScalX
, double dScalY);
bool isOk() { return state != Error; }
BMP_FILEHDR fileHeader;
BMP_INFOHDR infoHeader;
private:
bool readHeader();
int startpos;
QString imagePath;
State state;
QIODevice *m_device;
};
}
QBmpLoader.cpp
#include "QBmploader.h"
#include <qimage.h>
#include <qvariant.h>
#include <qvector.h>
#include <QFile>
#include <QDebug>
#include <qmath.h>
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 +

在项目中实现壁纸预览功能时,遇到大图片导致的界面白屏问题。首先尝试在重绘事件中直接加载图片,但当图片过大时,主机性能较差的设备会出现内存不足。为了解决这个问题,改为使用QImageReader进行图片读取,能正常显示图片。然而,对于100MB的BMP图片,仍然无法加载。于是,通过自定义QBmpLoader类实现了分段读取BMP图片的方法,有效处理了大图加载问题,避免了内存不足的情况。
最低0.47元/天 解锁文章
2536

被折叠的 条评论
为什么被折叠?



