Chinaunix首页 | 论坛 | 博客
  • 博客访问: 64106
  • 博文数量: 29
  • 博客积分: 1250
  • 博客等级: 中尉
  • 技术积分: 292
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-30 13:04
文章分类

全部博文(29)

文章存档

2009年(24)

2008年(5)

我的朋友

分类:

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(screen, image, topLeft, region);

        return;

    case QImage::Format_RGB16:

        blit_template(screen, image, topLeft, region);

        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(screen, image, topLeft, region);

        return;

    case QImage::Format_RGB16:

        blit_template(screen, image, topLeft, region);

        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(data), width, height, 0, format, true);

}

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;

...

}

 

阅读(1087) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~