从以QBitmap格式存储的原始数据创建XBM,可以很容易地像so QBitmap::fromData(width, height, data, QImage::Format_MonoLSB)那样完成,data是XBM文件的原始数据。
现在,如果这次我们想要创建一个QImage 怎么办?实际上,假设我们想要从相同的XBM原始数据创建一个QImage。不过,还有一个限制:这里不应该使用QBitmap,这意味着将QBitmap转换为获取QImage将不是一个可接受的解决方案。
我尝试了QImage(data, width, height, QImage::Format_MonoLSB),但是它没有产生正确的映像,因为QImage希望位对齐为32位,cf。Qt的4.8文档:
QImage::QImage(数据,int宽度,int高度,格式格式) 构造具有给定宽度、高度和格式的图像,该图像使用现有的内存缓冲区数据。宽度和高度必须以像素为单位,数据必须对齐32位,图像中的每条扫描线也必须是32位对齐的。
问题是XBM是1位对齐(而不是32位对齐),因此QImage(data, width, height, QImage::Format_MonoLSB)生成的QImage(data, width, height, QImage::Format_MonoLSB)是垃圾(未定义的行为,“随机”图像)。
因此,如何从XBM的原始QImage data 创建?
编辑:这里是一个QImage应该使用的XBM文件:
#define x_width 66
#define x_height 27
static char x_bits[] = {
0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, ...
};发布于 2015-10-04 14:14:27
好的,原来Qt alreay实现了一个简单的代码,它从一个QImage的原始数据构建一个XBM。
QImage image(size, monoFormat);
image.setColor(0, QColor(Qt::color0).rgb());
image.setColor(1, QColor(Qt::color1).rgb());
// Need to memcpy each line separatly since QImage is 32bit aligned and
// this data is only byte aligned...
int bytesPerLine = (size.width() + 7) / 8;
for (int y = 0; y < size.height(); ++y)
{
memcpy(image.scanLine(y), bits + bytesPerLine * y, bytesPerLine);
}此代码用于qbitmap.cpp,更具体地说,用于:
QBitmap::fromData(const QSize &size, const uchar *bits, QImage::Format monoFormat)
发布于 2015-08-21 14:43:30
这里有一个实现。它是线程安全的,如果有很多这样的映像,您可以在多个线程上发布这样的映像。它在当时处理32位的输出。
有必要将可用字节数传递给fromLittleEndian,以避免在输入数据结束后读取。

#include <QtWidgets>
#include <cstdint>
inline bool isAlignedTo(const void * p, int bits) {
return (reinterpret_cast<uintptr_t>(p) & ((bits/8)-1)) == 0;
}
inline uint32_t fromLittleEndian(const void *p, int bytes) {
Q_ASSERT(bytes > 0);
uint32_t val;
if (bytes >= 4) {
val = *reinterpret_cast<const uint32_t*>(p);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
val = val >> 24 | (val >> 8 & 0xFF00U) | (val << 8 & 0xFF0000U) | val << 24;
#endif
} else {
auto pp = reinterpret_cast<const uint8_t*>(p);
val = *pp++;
if (bytes > 1) val |= static_cast<uint32_t>(*pp++) << 8;
if (bytes > 2) val |= static_cast<uint32_t>(*pp) << 16;
}
return val;
}
QImage fromXBM(const uchar * data, int width, int height,
QImageCleanupFunction cleanup = 0, void * cleanupData = 0) {
Q_ASSERT(width && height);
if ((width & 31) == 0 && isAlignedTo(data, 32)) // 32-bit aligned
return QImage(data, width, height, QImage::Format_MonoLSB, cleanup, cleanupData);
if ((width & 7) == 0) // 8-bit aligned
return QImage(data, width, height, width/8, QImage::Format_MonoLSB, cleanup, cleanupData);
// Note: Source pixels are stored LSB first, MSB last.
QImage img(width, height, QImage::Format_MonoLSB);
Q_ASSERT((img.bytesPerLine() & 0x3) == 0); // must be 32-bit aligned
uint32_t * dst = reinterpret_cast<uint32_t*>(img.bits());
const int wordsPerRow = width / 32 + ((width & 31) ? 1 : 0);
int shift = 0;
int bytesLeft = (width * height)/8 + ((width * height & 7) ? 1 : 0);
uint32_t src = fromLittleEndian(data, bytesLeft);
bytesLeft -= 4;
data += 4;
while (height--) {
QList<uint32_t> w;
int widthLeft = width;
for (int c = 0; c < wordsPerRow; ++c) {
Q_ASSERT(widthLeft > 0);
uint32_t word = src >> shift;
if (32-shift < widthLeft) {
src = fromLittleEndian(data, bytesLeft);
bytesLeft -= 4;
data += 4;
if (shift) word |= src << (32-shift);
}
widthLeft -= 32;
*dst++ = word;
}
shift = (shift + width) & 31;
}
// Dispose of the data since we've made a copy
if (cleanup) cleanup(cleanupData);
return img;
}
// w = 5 h = 5
// 1...1 0x11,3
// .1.1. 0x40 0x01,6
// ..1.. 0x10,1
// .1.1. 0x00 0x05,4
// 1...1 0x10 0x01,7
// 0x51 0x11 0x15 0x01
const int X_w = 5, X_h = 5;
const uchar X_bits[] = { 0x51, 0x11, 0x15, 0x01 };
// 17 iterations of rule 30 cellular automaton, see
// Stephen Wolfram, The New Kind Of Science
// from https://lost-contact.mit.edu/afs/hep.wisc.edu/apps/Mathematica-7.0/Documentation/English/System/ExampleData/
const int rule30_w = 40, rule30_h = 17;
const uchar rule30_bits[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0xc0,
0x04, 0x00, 0x00, 0x00, 0x60, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x11, 0x00,
0x00, 0x00, 0xd8, 0x3b, 0x00, 0x00, 0x00, 0x4c, 0x48, 0x00, 0x00, 0x00,
0xf6, 0xfc, 0x00, 0x00, 0x00, 0x13, 0x07, 0x01, 0x00, 0x80, 0xbd, 0x89,
0x03, 0x00, 0xc0, 0x84, 0xde, 0x04, 0x00, 0x60, 0xcf, 0x42, 0x0f, 0x00,
0x30, 0x71, 0x66, 0x11, 0x00, 0xd8, 0x9b, 0x3b, 0x3b, 0x00, 0x4c, 0xe8,
0xc8, 0x49, 0x00, 0xf6, 0x2c, 0x7d, 0xfe, 0x00, 0x13, 0xe7, 0x85, 0x03,
0x01
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto X = fromXBM(X_bits, X_w, X_h);
X.invertPixels();
auto bigX = X.scaled(X.size() * 4);
auto rule30 = fromXBM(rule30_bits, rule30_w, rule30_h);
rule30.invertPixels();
auto big30 = rule30.scaled(rule30.size()*2);
QWidget w;
QHBoxLayout layout(&w);
QLabel labelX, label30;
layout.addWidget(&labelX);
layout.addWidget(&label30);
labelX.setPixmap(QPixmap::fromImage(bigX));
label30.setPixmap(QPixmap::fromImage(big30));
w.show();
return a.exec();
}https://stackoverflow.com/questions/32137782
复制相似问题