分类:
2008-11-07 18:06:04
Darw different color format image on an certain screen
When draw image on simulator, it using qvfb, if draw on target, it using linuxfb.
In Qtopia when draw screen, it will using blit function. this function should accroding current screen color format.
In Qtopin inner, when using QImage, it will send QImage class color format (any support are ok).
So the image color format is not related to the screen color format.
Hence, when draw an ARGB8888 image to RGB565 screen, the cover will be in blit function. blit function should draw the different color format image to current supported screen.
1. Simulator
In Qtopia, when build for Simulator, it will using next funcitons: When simulating, it accroding to current defined.
in Qscreenvfb_qws.cpp
class Q_GUI_EXPORT QVFbScreen : public QScreen {
};
bool QVFbScreen::connect(const QString &displaySpec) {
...
key_t key = ftok(QByteArray(QT_VFB_MOUSE_PIPE).replace("%1", QByteArray::number(displayId)), 'b');
...
int shmId = shmget(key, 0, 0);
d_ptr->shmrgn = (unsigned char *)shmat(shmId, 0, 0);
d_ptr->hdr = (QVFbHeader *)d_ptr->shmrgn;
data = d_ptr->shmrgn + d_ptr->hdr->dataoffset;
dw = w = d_ptr->hdr->width;
dh = h = d_ptr->hdr->height;
d = d_ptr->hdr->depth;
switch (d) {
case 16:
setPixelFormat(QImage::Format_RGB16);
break;
case 32:
setPixelFormat(QImage::Format_ARGB32_Premultiplied);
break;
}
...
}
2. Target
If build for Target, it will using next functions: It will set color format based on device info, according to linux framebuffer function
In qscreenlinuxfb_qws.cpp:
class Q_GUI_EXPORT QLinuxFbScreen : public QScreen {
};
bool QLinuxFbScreen::connect(const QString &displaySpec)
{
fb_var_screeninfo vinfo;
/* Get variable screen information */
if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
perror("QLinuxFbScreen::connect");
qWarning("Error reading variable information");
return false;
}
d = vinfo.bits_per_pixel;
...
}
void QLinuxFbScreen::setPixelFormat(struct fb_var_screeninfo info)
{
const fb_bitfield rgba[4] = { info.red, info.green,
info.blue, info.transp };
QImage::Format format = QImage::Format_Invalid;
// TODO: big endian
switch (d) {
case 32: {
const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0},
{0, 8, 0}, {24, 8, 0}};
if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0)
format = QImage::Format_ARGB32;
else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0)
format = QImage::Format_RGB32;
break;
}
case 16: {
const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0},
{0, 5, 0}, {0, 0, 0}};
if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0)
format = QImage::Format_RGB16;
break;
}
case 8:
break;
case 1:
format = QImage::Format_Mono; //###: LSB???
break;
default:
break;
}
QScreen::setPixelFormat(format);
}
So we need only make FB driver can return right value of bits_per_pixel, Qtopia will handle the right format, RGB565, RGB888, ARGB8888.
3. Draw to sceen
In QScreen class: blit function will draw sceen.
void QScreen::blit(QWSWindow *win, const QRegion &clip)
{
QWSWindowSurface *surface = win->windowSurface();
const QImage &img = surface->image();
const QRegion rgn = clip & win->paintedRegion();
...
surface->lock();
blit(img, win->requestedRegion().boundingRect().topLeft(), rgn);
surface->unlock();
}
void QScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion ®)
{
const QRect bound = (region() & QRect(topLeft, img.size())).boundingRect();
QWSDisplay::grab();
d_ptr->blit(this, img, topLeft - offset(), (reg & bound).translated(-topLeft));
QWSDisplay::ungrab();
}
QScreenPrivate::QScreenPrivate(QScreen *parent)
: pixelFormat(QImage::Format_Invalid), q_ptr(parent)
{
solidFill = qt_solidFill_setup;
blit = qt_blit_setup;
}
void qt_blit_setup(QScreen *screen, const QImage &image,
const QPoint &topLeft, const QRegion ®ion)
{
switch (screen->depth()) {
case 32:
screen->d_ptr->blit = blit_32;
break;
case 16:
screen->d_ptr->blit = blit_16;
break;
}
screen->d_ptr->blit(screen, image, topLeft, region);
}
static void blit_32(QScreen *screen, const QImage &image,
const QPoint &topLeft, const QRegion ®ion)
{
switch (image.format()) {
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
blit_template
return;
case QImage::Format_RGB16:
blit_template
return;
}
}
static void blit_16(QScreen *screen, const QImage &image,
const QPoint &topLeft, const QRegion ®ion)
{
switch (image.format()) {
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
blit_template
return;
case QImage::Format_RGB16:
blit_template
return;
}
}
4. QImage
QImage is a QPaintDevice:
In qimage.h:
class Q_GUI_EXPORT QImage : public QPaintDevice {
};
Create Image has two methods:
3.1 create null image: It will create an new image buffer, buffer size if calculate with picture format
QImage::QImage(int width, int height, Format format)
: QPaintDevice()
{
d = QImageData::create(QSize(width, height), format, 0);
}
QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors)
{
...
uint width = size.width();
uint height = size.height();
uint depth = 0;
switch(format) {
...
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
depth = 32;
numColors = 0;
break;
case QImage::Format_RGB16:
depth = 16;
numColors = 0;
break;
}
const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 8)
...
QImageData *d = new QImageData;
...
d->nbytes = d->bytes_per_line*height;
d->data = (uchar *)malloc(d->nbytes);
...
}
3.2 create image with data: It will use origional data point.
QImage::QImage(const uchar* data, int width, int height, Format format)
: QPaintDevice()
{
d = QImageData::create(const_cast
}
QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly)
{
...
const int depth = depthForFormat(format);
const int calc_bytes_per_line = ((width * depth + 31)/32) * 4;
const int min_bytes_per_line = (width * depth + 7)/8;
...
d = new QImageData;
...
d->data = data;
d->nbytes = d->bytes_per_line * height;
...
}