javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/library/graphics/qt/imagebase.cpp
author hgs
Fri, 15 Oct 2010 12:29:39 +0300
changeset 80 d6dafc5d983f
permissions -rw-r--r--
v2.2.19_1

/*******************************************************************************
 * Copyright (c) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Nokia Corporation - initial API and implementation
 *******************************************************************************/

#include "imagebase.h"
#include "gfxlog.h"

namespace Java { namespace GFX {

ImageBase::ImageBase() : mAlpha(-1), mHasMask(false)
    {
    }

ImageBase::~ImageBase()
    {
    }

void ImageBase::doGetRgb(QImage& image, int* aRgbdata, int aOffset, int aScanlength, 
                         int aX, int aY, int aWidth, int aHeight)
    {
    GFX_LOG_FUNC_CALL();

    if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height())
        {
        image = image.copy(aX, aY, aWidth, aHeight);
        if(image.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "copying from original image failed");
            }
        }

    // If image is not 32bpp we need to convert it
    if(image.format() != QImage::Format_RGB32 &&
       image.format() != QImage::Format_ARGB32)
        {
        image = image.convertToFormat(QImage::Format_ARGB32);
        if(image.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "format convertion to 32bpp failed");
            }
        }

    // Temporary storage for pixels
    QRgb* pixel = NULL;

    // dataArray index, start from offset
    int targetIndex = aOffset;
    // Iterate through lines
    for(int b = 0; b < aHeight; ++b)
        {
        // Obtain pointer to start of current line (y)
        const unsigned char* lineStart = image.scanLine(b);
        // Iterate through pixels on each line
        for (int a = 0; a < aWidth; ++a)
            {
            // Set the current pixel, relative to line start
            pixel = ((QRgb*)lineStart) + a;
            // Move target pointer to the next slot
            targetIndex = aOffset + a + (b * aScanlength);
            // Shift pixels to correct places, needed for 32-bit format
            // as the bits order in memory may vary between systems
            aRgbdata[targetIndex] =  ((qAlpha(*pixel) & 0xff) << 24) |
                                     ((qRed(*pixel)   & 0xff) << 16) |
                                     ((qGreen(*pixel) & 0xff) << 8 ) |
                                     ((qBlue(*pixel)  & 0xff));
            }
        }
    }

void ImageBase::doGetRgb(QImage& image, char* aRgbdata, char* aTransparencyMask,int aOffset, 
                         int aScanlength, int aX, int aY, int aWidth, int aHeight, int aFormat)
    {
    GFX_LOG_FUNC_CALL();

    if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height())
        {
        image = image.copy(aX, aY, aWidth, aHeight);
        if(image.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "copying from original image failed");
            }
        }

    if(aScanlength < 0)
        {
         image = image.mirrored(false, true);
         if(image.isNull())
             {
             throw GfxException(EGfxErrorNoMemory, "Mirroring failed");
             }
        }

    // If image is not monochrome we need to convert it
    if(image.format() != QImage::Format_Mono)
    {
        image = image.convertToFormat(QImage::Format_Mono);
        if(image.isNull())
        {
            throw GfxException(EGfxErrorNoMemory, "Format conversion to 8bpp failed");
        }
    }

    // dataArray index, start from offset
    int targetIndex = aOffset;

    const unsigned char* imageStart = image.bits();
    QImage mask = image.alphaChannel();
    const unsigned char* maskStart = mask.bits();

    // Find the number of full bytes
    int fullBytes = aWidth/8;
    int bpl = image.bytesPerLine();

    if(bpl == fullBytes)
        {
        memcpy(aRgbdata+targetIndex, imageStart, bpl*aHeight);
        memcpy(aTransparencyMask+targetIndex, maskStart, bpl*aHeight);
        }
    else
        {
        memcpy(aRgbdata+targetIndex, imageStart, fullBytes*aHeight + aHeight);
        memcpy(aTransparencyMask+targetIndex, maskStart, fullBytes*aHeight + aHeight);
        }
    }

void ImageBase::doGetRgb(QImage& image, short* aRgbdata, int aOffset, int aScanlength, 
                         int aX, int aY, int aWidth, int aHeight, int aFormat)
    {
    GFX_LOG_FUNC_CALL();

    // Match format to QT
    int format;
    switch (aFormat) {
        case EFormatRGB555:
            format = QImage::Format_RGB555;
            break;
        case EFormatRGB16:
            format = QImage::Format_RGB16;
            break;
         case EFormatRGB444:
            format = QImage::Format_RGB444;
            break;
         case EFormatARGB4444Premultiplied:
            format = QImage::Format_ARGB4444_Premultiplied;
            break;
         default:
            format = QImage::Format_RGB16;
    }

    if(aX != 0 || aY != 0 || aWidth < image.width() || aHeight < image.height())
        {
        image = image.copy(aX, aY, aWidth, aHeight);
        if(image.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "copying from original image failed");
            }
        }

    // If image is not format we need, convert it
    if(image.format() != format)
        {
        image = image.convertToFormat((QImage::Format)format);
        if(image.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "format convertion to 16bpp failed");
            }
        }

    // Temporary storage for pixels
    short* pixel = NULL;
    // dataArray index, start from offset
    int targetIndex = aOffset;

    // Iterate through lines
    for(int b=0; b < aHeight; b++)
        {
        // Obtain pointer to start of current line (y)
        const unsigned char* lineStart = image.scanLine(b);
        // Iterate through pixels on each line
        for(int a=0; a < aWidth; a++)
            {
            // Set the current pixel, relative to line start
            pixel = ((short*)lineStart) + a;
            // Move target pointer to the next slot
            targetIndex = aOffset + a + (b * aScanlength);
            aRgbdata[targetIndex] =  *pixel;
            }
        }
    }

QTransform ImageBase::generateTransformMatrix(TTransform aTransform)
    {
    GFX_LOG_FUNC_CALL();

    // In case there's both mirror and rotate is requested, the angle of rotation
    // must be negative since when the transform is applied the z-axis is processed
    // before y-axis, while the spec mandates reverse order. So by having negative  
    // degrees for rotation along z-axis here, gives correct output.
    QTransform transform;
    switch(aTransform) 
        {
        case ETransNone:
            // No transform or mirror
            break;
        case ETransRot90:
            transform.rotate(90, Qt::ZAxis);
            break;
        case ETransRot180:
            transform.rotate(180, Qt::ZAxis);
            break;
        case ETransRot270:
            transform.rotate(270, Qt::ZAxis);
            break;
        case ETransMirror:
            transform.rotate(180,Qt::YAxis);
            break;
        case ETransMirrorRot90:
            transform.rotate(180, Qt::YAxis);
            transform.rotate(-90, Qt::ZAxis);
            break;
        case ETransMirrorRot180:
            transform.rotate(180, Qt::YAxis);
            transform.rotate(-180, Qt::ZAxis);
            break;
        case ETransMirrorRot270:
            transform.rotate(180, Qt::YAxis);
            transform.rotate(-270, Qt::ZAxis);
            break;
        default:
            Q_ASSERT_X(false, "Graphics", "Transform type not recognized");
        }
    return transform;
    }

int ImageBase::getAlpha() 
    {
    return mAlpha;
    }

bool ImageBase::hasMask()
    {
    return mHasMask;
    }

QImage ImageBase::imageDataToQImage(ImageDataWrapper* aData)
    {
    if(aData->getDepth() != 32)
        {
        // Java side always converts the ImageData to 32 bit before passing it
        // to native side, bail out if we get something else
        throw GfxException(EGfxErrorNoMemory, "Only 32 bit ImageData is supported in Image creation");
        }

    int bpp = 4; // bit depth = 32, 4 bytes per pixel
    int size = aData->getWidth()*aData->getHeight()*bpp;
    char* pixelData = aData->getData(ImageDataWrapper::EPixelData);

    for(int index = 0; index < size; index += bpp)
        {
        int pixel = *(reinterpret_cast<int*>(pixelData+index));

        pixelData[index]   = (uchar)(pixel >> 24) & 0xFF;
        pixelData[index+1] = (uchar)(pixel >> 16) & 0xFF;
        pixelData[index+2] = (uchar)(pixel >> 8) & 0xFF;
        pixelData[index+3] = 0xFF; // Set alpha to opaque here, alpha channel data will be handled later
        }

    QImage image(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EPixelData)),
                                              aData->getWidth(),
                                              aData->getHeight(),
                                              aData->getBytesPerLine(),
                                              QImage::Format_ARGB32);
    if(image.isNull())
        {
        throw GfxException(EGfxErrorNoMemory, "Image creation failed");
        }

    // Set indexed palette (if one is set)
    if(!aData->isDirect())
        {
        image.setColorTable(*aData->getPaletteData()->getIndexedPalette());
        }

    mHasMask = false;
    mAlpha = aData->getAlpha();

    if(aData->getData(ImageDataWrapper::EMaskData))
        {
        QImage mask(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EMaskData)),
                                             aData->getWidth(),
                                             aData->getHeight(),
                                             QImage::Format_Mono);
        if(mask.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed");
            }
        image.setAlphaChannel(mask);
        mHasMask = true;
        }
    else if(mAlpha != -1)
        {
        // Global alpha is set, overrides alpha channel data
        QImage alpha(aData->getWidth(), aData->getHeight(), QImage::Format_Indexed8);
        if(alpha.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed");
            }

        alpha.fill(aData->getAlpha());
        image.setAlphaChannel(alpha);
        }
    else if(aData->getData(ImageDataWrapper::EAlphaData))
        {
        // Alpha channel data is set
        const int w = aData->getWidth();
        QImage alpha(reinterpret_cast<uchar*>(aData->getData(ImageDataWrapper::EAlphaData)),
                                              w,
                                              aData->getHeight(),
                                              w,
                                              QImage::Format_Indexed8);
        QVector<QRgb> colors(255);
        for(int i=0; i<255; i++)
            {
            colors[i] = qRgb(i, i, i);
            }
        alpha.setColorTable(colors);
        colors.clear();

        if(alpha.isNull())
            {
            throw GfxException(EGfxErrorNoMemory, "Image alpha channel creation failed");
            }
        image.setAlphaChannel(alpha);
        }
    return image;
    }


QImage::Format ImageBase::mapInternalFormatToQt(TImageFormat internalImageFormat)
    {
    switch (internalImageFormat) 
        {
        case EFormatARGB32:
            return QImage::Format_ARGB32;
        case EFormatRGB32:
            return QImage::Format_RGB32;
        case EFormatARGB32Premultiplied:
            return QImage::Format_ARGB32_Premultiplied;
         case EFormatRGB16:
            return QImage::Format_RGB16;
         case EFormatRGB555:
            return QImage::Format_RGB555;
         case EFormatRGB444:
            return QImage::Format_RGB444;
         case EFormatARGB4444Premultiplied:
            return QImage::Format_ARGB4444_Premultiplied;
         case EFormatMONO:
            return QImage::Format_Mono;
         default:
            return QImage::Format_Invalid;
        }
    }

TImageFormat ImageBase::mapQtFormatToInternal(QImage::Format qtImageFormat)
    {
    switch (qtImageFormat) 
        {
        case QImage::Format_ARGB32:
            return EFormatARGB32;
        case QImage::Format_RGB32:
            return EFormatRGB32;
        case QImage::Format_ARGB32_Premultiplied:
            return EFormatARGB32Premultiplied;
         case QImage::Format_RGB16:
            return EFormatRGB16;
         case QImage::Format_RGB555:
            return EFormatRGB555;
         case QImage::Format_RGB444:
            return EFormatRGB444;
         case QImage::Format_ARGB4444_Premultiplied:
            return EFormatARGB4444Premultiplied;
         case QImage::Format_Mono:
            return EFormatMONO;
         default:
            return EFormatNone;
        }
    }

} // namespace GFX
} // namespace Java