Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
25 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/plugins/imageformats/gif/gif.pro

    r2 r561  
    99target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    1010INSTALLS += target
     11
     12symbian:TARGET.UID3=0x2001E61A
  • trunk/src/plugins/imageformats/gif/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/gif/qgifhandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5454
    5555#define Q_TRANSPARENT 0x00ffffff
     56
     57// avoid going through QImage::scanLine() which calls detach
     58#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
     59
    5660
    5761/*
     
    136140    bool out_of_bounds;
    137141    bool digress;
    138     void nextY(QImage *image);
     142    void nextY(unsigned char *bits, int bpl);
    139143    void disposePrevious(QImage *image);
    140144};
     
    233237    //    CompuServe Incorporated."
    234238
     239    image->detach();
     240    int bpl = image->bytesPerLine();
     241    unsigned char *bits = image->bits();
     242
    235243#define LM(l, m) (((m)<<8)|l)
    236244    digress = false;
    237     int initial = length;
     245    const int initial = length;
    238246    while (!digress && length) {
    239247        length--;
     
    334342
    335343                QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
    336                 if (image->isNull() || (image->size() != QSize(swidth, sheight)) || image->format() != format) {
     344                if (image->isNull()) {
    337345                    (*image) = QImage(swidth, sheight, format);
    338                     memset(image->bits(), 0, image->numBytes());
     346                    bpl = image->bytesPerLine();
     347                    bits = image->bits();
     348                    memset(bits, 0, image->byteCount());
    339349
    340350                    // ### size of the upcoming frame, should rather
     
    394404                                              qMax(backingstore.height(), h),
    395405                                              QImage::Format_RGB32);
    396                         memset(image->bits(), 0, image->numBytes());
     406                        memset(bits, 0, image->byteCount());
    397407                    }
     408                    const int dest_bpl = backingstore.bytesPerLine();
     409                    unsigned char *dest_data = backingstore.bits();
    398410                    for (int ln=0; ln<h; ln++) {
    399                         memcpy(backingstore.scanLine(ln),
    400                                image->scanLine(t+ln)+l, w*sizeof(QRgb));
     411                        memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
     412                               FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
    401413                    }
    402414                }
     
    471483                        firstcode=oldcode=code;
    472484                        if (!out_of_bounds && image->height() > y && firstcode!=trans_index)
    473                             ((QRgb*)image->scanLine(y))[x] = color(firstcode);
     485                            ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
    474486                        x++;
    475487                        if (x>=swidth) out_of_bounds = true;
     
    478490                            x=left;
    479491                            out_of_bounds = left>=swidth || y>=sheight;
    480                             nextY(image);
     492                            nextY(bits, bpl);
    481493                        }
    482494                    } else {
     
    516528                        QRgb *line = 0;
    517529                        if (!out_of_bounds && h > y)
    518                             line = (QRgb*)image->scanLine(y);
     530                            line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
    519531                        while (sp>stack) {
    520532                            const uchar index = *(--sp);
     
    530542                                x=left;
    531543                                out_of_bounds = left>=swidth || y>=sheight;
    532                                 nextY(image);
     544                                nextY(bits, bpl);
    533545                                if (!out_of_bounds && h > y)
    534                                     line = (QRgb*)image->scanLine(y);
     546                                    line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
    535547                            }
    536548                        }
     
    645657}
    646658
    647 void QGIFFormat::nextY(QImage *image)
     659void QGIFFormat::nextY(unsigned char *bits, int bpl)
    648660{
    649661    int my;
     
    661673        if (trans_index < 0) {
    662674            for (i=1; i<=my; i++) {
    663                 memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb),
     675                memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
    664676                       (right-left+1)*sizeof(QRgb));
    665677            }
     
    690702        if (trans_index < 0) {
    691703            for (i=1; i<=my; i++) {
    692                 memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb),
     704                memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
    693705                       (right-left+1)*sizeof(QRgb));
    694706            }
     
    714726        if (trans_index < 0) {
    715727            for (i=1; i<=my; i++) {
    716                 memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb),
     728                memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
    717729                       (right-left+1)*sizeof(QRgb));
    718730            }
  • trunk/src/plugins/imageformats/gif/qgifhandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/ico/ico.pro

    r2 r561  
    1111target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    1212INSTALLS += target
     13
     14symbian:TARGET.UID3=0x2001E616
  • trunk/src/plugins/imageformats/ico/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/ico/qicohandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5858typedef struct
    5959{
    60     quint8      bWidth;               // Width of the image
    61     quint8      bHeight;              // Height of the image (times 2)
    62     quint8      bColorCount;          // Number of colors in image (0 if >=8bpp) [ not ture ]
    63     quint8      bReserved;            // Reserved
    64     quint16     wPlanes;              // Color Planes
    65     quint16     wBitCount;            // Bits per pixel
    66     quint32     dwBytesInRes;         // how many bytes in this resource?
    67     quint32     dwImageOffset;        // where in the file is this image
     60    quint8  bWidth;               // Width of the image
     61    quint8  bHeight;              // Height of the image (times 2)
     62    quint8  bColorCount;          // Number of colors in image (0 if >=8bpp) [ not ture ]
     63    quint8  bReserved;            // Reserved
     64    quint16 wPlanes;              // Color Planes
     65    quint16 wBitCount;            // Bits per pixel
     66    quint32 dwBytesInRes;         // how many bytes in this resource?
     67    quint32 dwImageOffset;        // where in the file is this image
    6868} ICONDIRENTRY, *LPICONDIRENTRY;
    6969#define ICONDIRENTRY_SIZE 16
     
    7171typedef struct
    7272{
    73     quint16     idReserved;   // Reserved
    74     quint16     idType;       // resource type (1 for icons)
    75     quint16     idCount;      // how many images?
    76     ICONDIRENTRY        idEntries[1]; // the entries for each image
     73    quint16 idReserved;   // Reserved
     74    quint16 idType;       // resource type (1 for icons)
     75    quint16 idCount;      // how many images?
     76    ICONDIRENTRY    idEntries[1]; // the entries for each image
    7777} ICONDIR, *LPICONDIR;
    7878#define ICONDIR_SIZE    6       // Exclude the idEntries field
    7979
    80 typedef struct {                                // BMP information header
    81     quint32  biSize;                            // size of this struct
    82     quint32  biWidth;                           // pixmap width
    83     quint32  biHeight;                          // pixmap height
    84     quint16  biPlanes;                          // should be 1
    85     quint16  biBitCount;                        // number of bits per pixel
    86     quint32  biCompression;                     // compression method
    87     quint32  biSizeImage;                               // size of image
    88     quint32  biXPelsPerMeter;                   // horizontal resolution
    89     quint32  biYPelsPerMeter;           // vertical resolution
    90     quint32  biClrUsed;                         // number of colors used
    91     quint32  biClrImportant;                    // number of important colors
     80typedef struct {                    // BMP information header
     81    quint32 biSize;                // size of this struct
     82    quint32 biWidth;               // pixmap width
     83    quint32 biHeight;              // pixmap height     (specifies the combined height of the XOR and AND masks)
     84    quint16 biPlanes;              // should be 1
     85    quint16 biBitCount;            // number of bits per pixel
     86    quint32 biCompression;         // compression method
     87    quint32 biSizeImage;           // size of image
     88    quint32 biXPelsPerMeter;       // horizontal resolution
     89    quint32 biYPelsPerMeter;       // vertical resolution
     90    quint32 biClrUsed;             // number of colors used
     91    quint32 biClrImportant;        // number of important colors
    9292} BMP_INFOHDR ,*LPBMP_INFOHDR;
    9393#define BMP_INFOHDR_SIZE 40
     
    109109    bool readIconEntry(int index, ICONDIRENTRY * iconEntry);
    110110
    111     bool readBMPHeader(ICONDIRENTRY & iconEntry, BMP_INFOHDR * header);
     111    bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header);
    112112    void findColorInfo(QImage & image);
    113113    void readColorTable(QImage & image);
     
    255255{
    256256    if (readHeader())
    257         return iconDir.idCount;
     257        return iconDir.idCount;
    258258    return 0;
    259259}
     
    269269            qint64 readBytes = ICONDIR_SIZE;
    270270            if (readIconDirEntry(iodev, &ikonDir.idEntries[0])) {
    271                 readBytes += ICONDIRENTRY_SIZE;
    272                 // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file.
    273                 if (   ikonDir.idReserved == 0
    274                     && ikonDir.idType == 1
    275                     && ikonDir.idEntries[0].bReserved == 0
    276                     && ikonDir.idEntries[0].wPlanes <= 1
    277                     && ikonDir.idEntries[0].wBitCount <= 32     // Bits per pixel
    278                     && ikonDir.idEntries[0].dwBytesInRes >= 40  // Must be over 40, since sizeof (infoheader) == 40
    279                     ) {
    280                     isProbablyICO = true;
    281                 }
     271                readBytes += ICONDIRENTRY_SIZE;
     272                // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file.
     273                if (   ikonDir.idReserved == 0
     274                    && ikonDir.idType == 1
     275                    && ikonDir.idEntries[0].bReserved == 0
     276                    && ikonDir.idEntries[0].wPlanes <= 1
     277                    && ikonDir.idEntries[0].wBitCount <= 32     // Bits per pixel
     278                    && ikonDir.idEntries[0].dwBytesInRes >= 40  // Must be over 40, since sizeof (infoheader) == 40
     279                    ) {
     280                    isProbablyICO = true;
     281                }
    282282
    283283                if (iodev->isSequential()) {
     
    324324                iodev->ungetChar(tmp & 0xff);
    325325            }
    326 
    327         }
     326        }
    328327        if (!iodev->isSequential()) iodev->seek(oldPos);
    329328    }
     
    335334{
    336335    if (iod && !headerRead) {
    337         startpos = iod->pos();
    338         if (readIconDir(iod, &iconDir)) {
    339             if (iconDir.idReserved == 0 || iconDir.idType == 1)
    340                 headerRead = true;
    341         }
     336        startpos = iod->pos();
     337        if (readIconDir(iod, &iconDir)) {
     338            if (iconDir.idReserved == 0 || iconDir.idType == 1)
     339            headerRead = true;
     340        }
    342341    }
    343342
     
    345344}
    346345
    347 bool ICOReader::readIconEntry(int index, ICONDIRENTRY * iconEntry)
     346bool ICOReader::readIconEntry(int index, ICONDIRENTRY *iconEntry)
    348347{
    349348    if (iod) {
    350         if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) {
    351             return readIconDirEntry(iod, iconEntry);
     349        if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) {
     350            return readIconDirEntry(iod, iconEntry);
    352351        }
    353352    }
     
    357356
    358357
    359 bool ICOReader::readBMPHeader(ICONDIRENTRY & iconEntry, BMP_INFOHDR * header)
    360 {
    361     memset(&icoAttrib, 0, sizeof(IcoAttrib));
     358bool ICOReader::readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header)
     359{
    362360    if (iod) {
    363         if (iod->seek(startpos + iconEntry.dwImageOffset)) {
    364             if (readBMPInfoHeader(iod, header)) {
    365 
    366                 icoAttrib.nbits = header->biBitCount ? header->biBitCount : iconEntry.wBitCount;
    367                 icoAttrib.h = header->biHeight / 2; // this height is always double the iconEntry height (for the mask)
    368                 icoAttrib.w = header->biWidth;
    369 
    370                 switch (icoAttrib.nbits) {
    371                 case 32:
    372                 case 24:
    373                 case 16:
    374                     icoAttrib.depth = 32;
    375                     break;
    376                 case 8:
    377                 case 4:
    378                     icoAttrib.depth = 8;
    379                     break;
    380                 default:
    381                     icoAttrib.depth = 1;
    382                 }
    383 
    384                 if ( icoAttrib.depth == 32 )                            // there's no colormap
    385                     icoAttrib.ncolors = 0;
    386                 else                                    // # colors used
    387                     icoAttrib.ncolors = header->biClrUsed ? header->biClrUsed : 1 << icoAttrib.nbits;
    388                 //qDebug() << "Bits:" << icoAttrib.nbits << "Depth:" << icoAttrib.depth << "Ncols:" << icoAttrib.ncolors;
    389                 return TRUE;
    390             }
    391         }
     361        if (iod->seek(startpos + imageOffset)) {
     362            if (readBMPInfoHeader(iod, header)) {
     363                return TRUE;
     364            }
     365        }
    392366    }
    393367    return FALSE;
     
    396370void ICOReader::findColorInfo(QImage & image)
    397371{
    398     if (icoAttrib.ncolors > 0) {                                // set color table
    399         readColorTable(image);
     372    if (icoAttrib.ncolors > 0) {                // set color table
     373        readColorTable(image);
    400374    } else if (icoAttrib.nbits == 16) { // don't support RGB values for 15/16 bpp
    401         image = QImage();
     375        image = QImage();
    402376    }
    403377}
     
    406380{
    407381    if (iod) {
    408         image.setNumColors(icoAttrib.ncolors);
    409         uchar rgb[4];
    410         for (int i=0; i<icoAttrib.ncolors; i++) {
    411             if (iod->read((char*)rgb, 4) != 4) {
    412                 image = QImage();
    413                 break;
    414             }
    415             image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
    416         }
     382        image.setColorCount(icoAttrib.ncolors);
     383        uchar rgb[4];
     384        for (int i=0; i<icoAttrib.ncolors; i++) {
     385            if (iod->read((char*)rgb, 4) != 4) {
     386            image = QImage();
     387            break;
     388            }
     389            image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
     390        }
    417391    } else {
    418         image = QImage();
     392        image = QImage();
    419393    }
    420394}
     
    422396void ICOReader::readBMP(QImage & image)
    423397{
    424     if (icoAttrib.nbits == 1) {                         // 1 bit BMP image
    425         read1BitBMP(image);
    426     } else if (icoAttrib.nbits == 4) {                  // 4 bit BMP image
    427         read4BitBMP(image);
     398    if (icoAttrib.nbits == 1) {                // 1 bit BMP image
     399        read1BitBMP(image);
     400    } else if (icoAttrib.nbits == 4) {            // 4 bit BMP image
     401        read4BitBMP(image);
    428402    } else if (icoAttrib.nbits == 8) {
    429         read8BitBMP(image);
     403        read8BitBMP(image);
    430404    } else if (icoAttrib.nbits == 16 || icoAttrib.nbits == 24 || icoAttrib.nbits == 32 ) { // 16,24,32 bit BMP image
    431         read16_24_32BMP(image);
     405        read16_24_32BMP(image);
    432406    }
    433407}
     
    443417    if (iod) {
    444418
    445         int h = image.height();
    446         int bpl = image.bytesPerLine();
    447 
    448         while (--h >= 0) {
    449             if (iod->read((char*)image.scanLine(h),bpl) != bpl) {
    450                 image = QImage();
    451                 break;
    452             }
    453         }
     419        int h = image.height();
     420        int bpl = image.bytesPerLine();
     421
     422        while (--h >= 0) {
     423            if (iod->read((char*)image.scanLine(h),bpl) != bpl) {
     424                image = QImage();
     425                break;
     426            }
     427        }
    454428    } else {
    455         image = QImage();
     429        image = QImage();
    456430    }
    457431}
     
    461435    if (iod) {
    462436
    463         int h = icoAttrib.h;
    464         int buflen = ((icoAttrib.w+7)/8)*4;
    465         uchar *buf = new uchar[buflen];
    466         Q_CHECK_PTR(buf);
    467 
    468         while (--h >= 0) {
    469             if (iod->read((char*)buf,buflen) != buflen) {
    470                 image = QImage();
    471                 break;
    472             }
    473             register uchar *p = image.scanLine(h);
    474             uchar *b = buf;
    475             for (int i=0; i<icoAttrib.w/2; i++) {       // convert nibbles to bytes
    476                 *p++ = *b >> 4;
    477                 *p++ = *b++ & 0x0f;
    478             }
    479             if (icoAttrib.w & 1)                        // the last nibble
    480                 *p = *b >> 4;
    481         }
    482 
    483         delete [] buf;
     437        int h = icoAttrib.h;
     438        int buflen = ((icoAttrib.w+7)/8)*4;
     439        uchar *buf = new uchar[buflen];
     440        Q_CHECK_PTR(buf);
     441
     442        while (--h >= 0) {
     443            if (iod->read((char*)buf,buflen) != buflen) {
     444                image = QImage();
     445                break;
     446            }
     447            register uchar *p = image.scanLine(h);
     448            uchar *b = buf;
     449            for (int i=0; i<icoAttrib.w/2; i++) {   // convert nibbles to bytes
     450                *p++ = *b >> 4;
     451                *p++ = *b++ & 0x0f;
     452            }
     453            if (icoAttrib.w & 1)                    // the last nibble
     454                *p = *b >> 4;
     455        }
     456
     457        delete [] buf;
    484458
    485459    } else {
    486         image = QImage();
     460        image = QImage();
    487461    }
    488462}
     
    492466    if (iod) {
    493467
    494         int h = icoAttrib.h;
    495         int bpl = image.bytesPerLine();
    496 
    497         while (--h >= 0) {
    498             if (iod->read((char *)image.scanLine(h), bpl) != bpl) {
    499                 image = QImage();
    500                 break;
    501             }
    502         }
     468        int h = icoAttrib.h;
     469        int bpl = image.bytesPerLine();
     470
     471        while (--h >= 0) {
     472            if (iod->read((char *)image.scanLine(h), bpl) != bpl) {
     473                image = QImage();
     474                break;
     475            }
     476        }
    503477    } else {
    504         image = QImage();
     478        image = QImage();
    505479    }
    506480}
     
    509483{
    510484    if (iod) {
    511 
    512         int h = icoAttrib.h;
    513         register QRgb *p;
    514         QRgb  *end;
    515         uchar *buf = new uchar[image.bytesPerLine()];
    516         int    bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4;
    517         uchar *b;
    518 
    519         while (--h >= 0) {
    520             p = (QRgb *)image.scanLine(h);
    521             end = p + icoAttrib.w;
    522             if (iod->read((char *)buf, bpl) != bpl) {
    523                 image = QImage();
    524                 break;
    525             }
    526             b = buf;
    527             while (p < end) {
     485        int h = icoAttrib.h;
     486        register QRgb *p;
     487        QRgb  *end;
     488        uchar *buf = new uchar[image.bytesPerLine()];
     489        int    bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4;
     490        uchar *b;
     491
     492        while (--h >= 0) {
     493            p = (QRgb *)image.scanLine(h);
     494            end = p + icoAttrib.w;
     495            if (iod->read((char *)buf, bpl) != bpl) {
     496                image = QImage();
     497                break;
     498            }
     499            b = buf;
     500            while (p < end) {
    528501                if (icoAttrib.nbits == 24)
    529502                    *p++ = qRgb(*(b+2), *(b+1), *b);
    530503                else if (icoAttrib.nbits == 32)
    531504                    *p++ = qRgba(*(b+2), *(b+1), *b, *(b+3));
    532                 b += icoAttrib.nbits/8;
    533             }
    534         }
    535 
    536         delete[] buf;
     505                b += icoAttrib.nbits/8;
     506            }
     507        }
     508
     509        delete[] buf;
    537510
    538511    } else {
    539         image = QImage();
     512        image = QImage();
    540513    }
    541514}
     
    550523        if (readIconEntry(index, &iconEntry)) {
    551524
     525            static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
     526
     527            iod->seek(iconEntry.dwImageOffset);
     528
     529            const QByteArray pngMagic = QByteArray::fromRawData((char*)pngMagicData, sizeof(pngMagicData));
     530            const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic);
     531
     532            if (isPngImage) {
     533                iod->seek(iconEntry.dwImageOffset);
     534                return QImage::fromData(iod->read(iconEntry.dwBytesInRes), "png");
     535            }
     536
    552537            BMP_INFOHDR header;
    553             if (readBMPHeader(iconEntry, &header)) {
     538            if (readBMPHeader(iconEntry.dwImageOffset, &header)) {
     539                icoAttrib.nbits = header.biBitCount ? header.biBitCount : iconEntry.wBitCount;
     540
     541                switch (icoAttrib.nbits) {
     542                case 32:
     543                case 24:
     544                case 16:
     545                    icoAttrib.depth = 32;
     546                    break;
     547                case 8:
     548                case 4:
     549                    icoAttrib.depth = 8;
     550                    break;
     551                default:
     552                    icoAttrib.depth = 1;
     553                }
     554                if (icoAttrib.depth == 32)                // there's no colormap
     555                    icoAttrib.ncolors = 0;
     556                else                    // # colors used
     557                    icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits;
     558                icoAttrib.w = iconEntry.bWidth;
     559                icoAttrib.h = iconEntry.bHeight;
    554560
    555561                QImage::Format format = QImage::Format_ARGB32;
     
    569575                            QImage mask(image.width(), image.height(), QImage::Format_Mono);
    570576                            if (!mask.isNull()) {
    571                                 mask.setNumColors(2);
     577                                mask.setColorCount(2);
    572578                                mask.setColor(0, qRgba(255,255,255,0xff));
    573579                                mask.setColor(1, qRgba(0  ,0  ,0  ,0xff));
     
    606612
    607613    ICOReader reader(device);
    608     for (int i=0; i<reader.count(); i++)
    609         images += reader.iconAt(i);
     614    for (int i = 0; i < reader.count(); i++)
     615        images += reader.iconAt(i);
    610616
    611617    return images;
     
    660666            maskImage = maskImage.convertToFormat(QImage::Format_Mono);
    661667
    662             int nbits = 32;
    663             int bpl_bmp = ((image.width()*nbits+31)/32)*4;
     668            int    nbits = 32;
     669            int    bpl_bmp = ((image.width()*nbits+31)/32)*4;
    664670
    665671            entries[i].bColorCount = 0;
     
    671677                + (maskImage.bytesPerLine() * maskImage.height());
    672678            entries[i].wPlanes = 1;
    673             if (i==0)
     679            if (i == 0)
    674680                entries[i].dwImageOffset = origOffset + ICONDIR_SIZE
    675681                + (id.idCount * ICONDIRENTRY_SIZE);
     
    696702            memset( buf, 0, bpl_bmp );
    697703            int y;
    698             for (y=image.height()-1; y>=0; y--) {       // write the image bits
     704            for (y = image.height() - 1; y >= 0; y--) {    // write the image bits
    699705                // 32 bits
    700706                QRgb *p   = (QRgb *)image.scanLine(y);
     
    718724            maskImage.invertPixels();   // seems as though it needs this
    719725            // NOTE! !! The mask is only flipped vertically - not horizontally !!
    720             for (y=maskImage.height()-1; y>=0; y--)
     726            for (y = maskImage.height() - 1; y >= 0; y--)
    721727                buffer.write((char*)maskImage.scanLine(y), maskImage.bytesPerLine());
    722 
    723         }
    724 
    725 
     728        }
    726729
    727730        if (writeIconDir(device, id)) {
     
    732735            }
    733736            if (bOK) {
    734                 for (i=0; i<id.idCount && bOK; i++) {
     737                for (i = 0; i < id.idCount && bOK; i++) {
    735738                    bOK = writeBMPInfoHeader(device, bmpHeaders[i]);
    736739                    bOK &= (device->write(imageData[i]) == (int) imageData[i].size());
  • trunk/src/plugins/imageformats/ico/qicohandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/jpeg/jpeg.pro

    r2 r561  
    1212        contains(CE_ARCH,x86):CONFIG -= stl exceptions
    1313        contains(CE_ARCH,x86):CONFIG += exceptions_off
     14}
     15
     16symbian: {
     17        #Disable warnings in 3rdparty code due to unused arguments
     18        QMAKE_CXXFLAGS.CW += -W nounusedarg
     19        TARGET.UID3=0x2001E61B
    1420}
    1521
     
    7278target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    7379INSTALLS += target
     80
  • trunk/src/plugins/imageformats/jpeg/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/jpeg/qjpeghandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    8585    QImageSmoothScaler(const int w, const int h, const QImage &src);
    8686    QImageSmoothScaler(const int srcWidth, const int srcHeight,
    87                        const char *parameters);
     87                       const int dstWidth, const int dstHeight);
    8888
    8989    virtual ~QImageSmoothScaler(void);
    9090
    9191    QImage  scale();
    92 
    93 protected:
    94     int scaledWidth(void) const;
    9592
    9693private:
     
    124121
    125122QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight,
    126                                        const char *parameters)
    127 {
    128     char    sModeStr[1024];
    129     int     t1;
    130     int     t2;
    131     int     dstWidth;
    132     int     dstHeight;
    133 
    134     sModeStr[0] = '\0';
    135 
     123                                       const int dstWidth, const int dstHeight)
     124{
    136125    d = new QImageSmoothScalerPrivate;
    137 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
    138     sscanf_s(parameters, "Scale( %i, %i, %1023s )", &dstWidth, &dstHeight, sModeStr, sizeof(sModeStr));
    139 #else
    140     sscanf(parameters, "Scale( %i, %i, %s )", &dstWidth, &dstHeight, sModeStr);
    141 #endif
    142     QString sModeQStr = QString::fromLatin1(sModeStr);
    143 
    144     t1 = srcWidth * dstHeight;
    145     t2 = srcHeight * dstWidth;
    146 
    147     if (((sModeQStr == QLatin1String("ScaleMin")) && (t1 > t2)) || ((sModeQStr == QLatin1String("ScaleMax")) && (t2 < t2))) {
    148         dstHeight = t2 / srcWidth;
    149     } else if (sModeQStr != QLatin1String("ScaleFree")) {
    150         dstWidth = t1 / srcHeight;
    151     }
    152 
    153126    d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0);
    154127}
     
    163136    newrows = dstHeight;
    164137    hasAlpha = hasAlphaChannel;
    165 }
    166 
    167 int QImageSmoothScaler::scaledWidth() const
    168 {
    169     return d->cols;
    170138}
    171139
     
    197165QImage QImageSmoothScaler::scale()
    198166{
    199     long    SCALE;
    200     long    HALFSCALE;
    201     QRgb    *xelrow = 0;
    202     QRgb    *tempxelrow = 0;
    203     QRgb    *xP;
    204     QRgb    *nxP;
    205     int    row, rowsread;
    206     int    col, needtoreadrow;
    207     uchar   maxval = 255;
    208     qreal  xscale, yscale;
    209     long    sxscale, syscale;
    210     long    fracrowtofill, fracrowleft;
    211     long    *as;
    212     long    *rs;
    213     long    *gs;
    214     long    *bs;
    215     int    rowswritten = 0;
    216     QImage  dst;
     167    long SCALE;
     168    long HALFSCALE;
     169    QRgb *xelrow = 0;
     170    QRgb *tempxelrow = 0;
     171    QRgb *xP;
     172    QRgb *nxP;
     173    int row, rowsread;
     174    int col, needtoreadrow;
     175    uchar maxval = 255;
     176    qreal xscale, yscale;
     177    long sxscale, syscale;
     178    long fracrowtofill, fracrowleft;
     179    long *as;
     180    long *rs;
     181    long *gs;
     182    long *bs;
     183    int rowswritten = 0;
     184    QImage dst;
    217185
    218186    if (d->cols > 4096) {
    219         SCALE = 4096;
    220         HALFSCALE = 2048;
     187        SCALE = 4096;
     188        HALFSCALE = 2048;
    221189    } else {
    222         int fac = 4096;
    223         while (d->cols * fac > 4096) {
    224             fac /= 2;
    225         }
    226 
    227         SCALE = fac * d->cols;
    228         HALFSCALE = fac * d->cols / 2;
    229     }
    230 
    231     xscale = (qreal) d->newcols / (qreal) d->cols;
    232     yscale = (qreal) d->newrows / (qreal) d->rows;
     190        int fac = 4096;
     191        while (d->cols * fac > 4096)
     192            fac /= 2;
     193
     194        SCALE = fac * d->cols;
     195        HALFSCALE = fac * d->cols / 2;
     196    }
     197
     198    xscale = (qreal)d->newcols / (qreal)d->cols;
     199    yscale = (qreal)d->newrows / (qreal)d->rows;
    233200    sxscale = (long)(xscale * SCALE);
    234201    syscale = (long)(yscale * SCALE);
    235202
    236     if ( d->newrows != d->rows )        /* shortcut Y scaling if possible */
    237         tempxelrow = new QRgb[d->cols];
    238 
    239     if ( d->hasAlpha ) {
    240         as = new long[d->cols];
    241         for ( col = 0; col < d->cols; ++col )
    242             as[col] = HALFSCALE;
     203    // shortcut Y scaling if possible
     204    if (d->newrows != d->rows)
     205        tempxelrow = new QRgb[d->cols];
     206
     207    if (d->hasAlpha) {
     208        as = new long[d->cols];
     209        for (col = 0; col < d->cols; ++col)
     210            as[col] = HALFSCALE;
    243211    } else {
    244         as = 0;
     212        as = 0;
    245213    }
    246214    rs = new long[d->cols];
     
    250218    fracrowleft = syscale;
    251219    needtoreadrow = 1;
    252     for ( col = 0; col < d->cols; ++col )
    253         rs[col] = gs[col] = bs[col] = HALFSCALE;
     220    for (col = 0; col < d->cols; ++col)
     221        rs[col] = gs[col] = bs[col] = HALFSCALE;
    254222    fracrowtofill = SCALE;
    255223
    256     dst = QImage( d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32 );
    257 
    258     for ( row = 0; row < d->newrows; ++row ) {
    259         /* First scale Y from xelrow into tempxelrow. */
    260         if ( d->newrows == d->rows ) {
    261             /* shortcut Y scaling if possible */
    262             tempxelrow = xelrow = scanLine(rowsread++, d->src);
    263         } else {
    264             while ( fracrowleft < fracrowtofill ) {
    265                 if ( needtoreadrow && rowsread < d->rows ) {
    266                     xelrow = scanLine(rowsread++, d->src);
    267                 }
    268                 for ( col = 0, xP = xelrow; col < d->cols; ++col, ++xP ) {
    269                     if (as) {
    270                         as[col] += fracrowleft * qAlpha( *xP );
    271                         rs[col] += fracrowleft * qRed( *xP ) * qAlpha( *xP ) / 255;
    272                         gs[col] += fracrowleft * qGreen( *xP ) * qAlpha( *xP ) / 255;
    273                         bs[col] += fracrowleft * qBlue( *xP ) * qAlpha( *xP ) / 255;
    274                     } else {
    275                         rs[col] += fracrowleft * qRed( *xP );
    276                         gs[col] += fracrowleft * qGreen( *xP );
    277                         bs[col] += fracrowleft * qBlue( *xP );
    278                     }
    279                 }
    280                 fracrowtofill -= fracrowleft;
    281                 fracrowleft = syscale;
    282                 needtoreadrow = 1;
    283             }
    284             /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */
    285             if ( needtoreadrow && rowsread < d->rows) {
    286                 xelrow = scanLine(rowsread++, d->src);
    287                 needtoreadrow = 0;
    288             }
    289             for ( col = 0, xP = xelrow, nxP = tempxelrow;
    290                   col < d->cols; ++col, ++xP, ++nxP )
    291             {
    292                 register long a, r, g, b;
    293 
    294                 if ( as ) {
    295                     r = rs[col] + fracrowtofill * qRed( *xP ) * qAlpha( *xP ) / 255;
    296                     g = gs[col] + fracrowtofill * qGreen( *xP ) * qAlpha( *xP ) / 255;
    297                     b = bs[col] + fracrowtofill * qBlue( *xP ) * qAlpha( *xP ) / 255;
    298                     a = as[col] + fracrowtofill * qAlpha( *xP );
    299                     if ( a ) {
    300                         r = r * 255 / a * SCALE;
    301                         g = g * 255 / a * SCALE;
    302                         b = b * 255 / a * SCALE;
    303                     }
    304                 } else {
    305                     r = rs[col] + fracrowtofill * qRed( *xP );
    306                     g = gs[col] + fracrowtofill * qGreen( *xP );
    307                     b = bs[col] + fracrowtofill * qBlue( *xP );
    308                     a = 0; // unwarn
    309                 }
    310                 r /= SCALE;
    311                 if ( r > maxval ) r = maxval;
    312                 g /= SCALE;
    313                 if ( g > maxval ) g = maxval;
    314                 b /= SCALE;
    315                 if ( b > maxval ) b = maxval;
    316                 if ( as ) {
    317                     a /= SCALE;
    318                     if ( a > maxval ) a = maxval;
    319                     *nxP = qRgba( (int)r, (int)g, (int)b, (int)a );
    320                     as[col] = HALFSCALE;
    321                 } else {
    322                     *nxP = qRgb( (int)r, (int)g, (int)b );
    323                 }
    324                 rs[col] = gs[col] = bs[col] = HALFSCALE;
    325             }
    326             fracrowleft -= fracrowtofill;
    327             if ( fracrowleft == 0 ) {
    328                 fracrowleft = syscale;
    329                 needtoreadrow = 1;
    330             }
    331             fracrowtofill = SCALE;
    332         }
    333 
    334         /* Now scale X from tempxelrow into dst and write it out. */
    335         if ( d->newcols == d->cols ) {
    336             /* shortcut X scaling if possible */
    337             memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols*4);
    338         } else {
    339             register long a, r, g, b;
    340             register long fraccoltofill, fraccolleft = 0;
    341             register int needcol;
    342 
    343             nxP = (QRgb*)dst.scanLine(rowswritten++);
    344             fraccoltofill = SCALE;
    345             a = r = g = b = HALFSCALE;
    346             needcol = 0;
    347             for ( col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP ) {
    348                 fraccolleft = sxscale;
    349                 while ( fraccolleft >= fraccoltofill ) {
    350                     if ( needcol ) {
    351                         ++nxP;
    352                         a = r = g = b = HALFSCALE;
    353                     }
    354                     if ( as ) {
    355                         r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255;
    356                         g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255;
    357                         b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255;
    358                         a += fraccoltofill * qAlpha( *xP );
    359                         if ( a ) {
    360                             r = r * 255 / a * SCALE;
    361                             g = g * 255 / a * SCALE;
    362                             b = b * 255 / a * SCALE;
    363                         }
    364                     } else {
    365                         r += fraccoltofill * qRed( *xP );
    366                         g += fraccoltofill * qGreen( *xP );
    367                         b += fraccoltofill * qBlue( *xP );
    368                     }
    369                     r /= SCALE;
    370                     if ( r > maxval ) r = maxval;
    371                     g /= SCALE;
    372                     if ( g > maxval ) g = maxval;
    373                     b /= SCALE;
    374                     if ( b > maxval ) b = maxval;
    375                     if (as) {
    376                         a /= SCALE;
    377                         if ( a > maxval ) a = maxval;
    378                         *nxP = qRgba( (int)r, (int)g, (int)b, (int)a );
    379                     } else {
    380                         *nxP = qRgb( (int)r, (int)g, (int)b );
    381                     }
    382                     fraccolleft -= fraccoltofill;
    383                     fraccoltofill = SCALE;
    384                     needcol = 1;
    385                 }
    386                 if ( fraccolleft > 0 ) {
    387                     if ( needcol ) {
    388                         ++nxP;
    389                         a = r = g = b = HALFSCALE;
    390                         needcol = 0;
    391                     }
    392                     if (as) {
    393                         a += fraccolleft * qAlpha( *xP );
    394                         r += fraccolleft * qRed( *xP ) * qAlpha( *xP ) / 255;
    395                         g += fraccolleft * qGreen( *xP ) * qAlpha( *xP ) / 255;
    396                         b += fraccolleft * qBlue( *xP ) * qAlpha( *xP ) / 255;
    397                     } else {
    398                         r += fraccolleft * qRed( *xP );
    399                         g += fraccolleft * qGreen( *xP );
    400                         b += fraccolleft * qBlue( *xP );
    401                     }
    402                     fraccoltofill -= fraccolleft;
    403                 }
    404             }
    405             if ( fraccoltofill > 0 ) {
    406                 --xP;
    407                 if (as) {
    408                     a += fraccolleft * qAlpha( *xP );
    409                     r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255;
    410                     g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255;
    411                     b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255;
    412                     if ( a ) {
    413                         r = r * 255 / a * SCALE;
    414                         g = g * 255 / a * SCALE;
    415                         b = b * 255 / a * SCALE;
    416                     }
    417                 } else {
    418                     r += fraccoltofill * qRed( *xP );
    419                     g += fraccoltofill * qGreen( *xP );
    420                     b += fraccoltofill * qBlue( *xP );
    421                 }
    422             }
    423             if ( ! needcol ) {
    424                 r /= SCALE;
    425                 if ( r > maxval ) r = maxval;
    426                 g /= SCALE;
    427                 if ( g > maxval ) g = maxval;
    428                 b /= SCALE;
    429                 if ( b > maxval ) b = maxval;
    430                 if (as) {
    431                     a /= SCALE;
    432                     if ( a > maxval ) a = maxval;
    433                     *nxP = qRgba( (int)r, (int)g, (int)b, (int)a );
    434                 } else {
    435                     *nxP = qRgb( (int)r, (int)g, (int)b );
    436                 }
    437             }
    438         }
    439     }
    440 
    441     if ( d->newrows != d->rows && tempxelrow )// Robust, tempxelrow might be 0 1 day
    442         delete [] tempxelrow;
    443     if ( as )                           // Avoid purify complaint
    444         delete [] as;
    445     if ( rs )                           // Robust, rs might be 0 one day
    446         delete [] rs;
    447     if ( gs )                           // Robust, gs might be 0 one day
    448         delete [] gs;
    449     if ( bs )                           // Robust, bs might be 0 one day
    450         delete [] bs;
     224    dst = QImage(d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
     225
     226    for (row = 0; row < d->newrows; ++row) {
     227        // First scale Y from xelrow into tempxelrow.
     228        if (d->newrows == d->rows) {
     229            // shortcut Y scaling if possible
     230            tempxelrow = xelrow = scanLine(rowsread++, d->src);
     231        } else {
     232            while (fracrowleft < fracrowtofill) {
     233                if (needtoreadrow && rowsread < d->rows)
     234                    xelrow = scanLine(rowsread++, d->src);
     235                for (col = 0, xP = xelrow; col < d->cols; ++col, ++xP) {
     236                    if (as) {
     237                        as[col] += fracrowleft * qAlpha(*xP);
     238                        rs[col] += fracrowleft * qRed(*xP) * qAlpha(*xP) / 255;
     239                        gs[col] += fracrowleft * qGreen(*xP) * qAlpha(*xP) / 255;
     240                        bs[col] += fracrowleft * qBlue(*xP) * qAlpha(*xP) / 255;
     241                    } else {
     242                        rs[col] += fracrowleft * qRed(*xP);
     243                        gs[col] += fracrowleft * qGreen(*xP);
     244                        bs[col] += fracrowleft * qBlue(*xP);
     245                    }
     246                }
     247                fracrowtofill -= fracrowleft;
     248                fracrowleft = syscale;
     249                needtoreadrow = 1;
     250            }
     251            // Now fracrowleft is >= fracrowtofill, so we can produce a row.
     252            if (needtoreadrow && rowsread < d->rows) {
     253                xelrow = scanLine(rowsread++, d->src);
     254                needtoreadrow = 0;
     255            }
     256            for (col = 0, xP = xelrow, nxP = tempxelrow; col < d->cols; ++col, ++xP, ++nxP) {
     257                register long a, r, g, b;
     258
     259                if (as) {
     260                    r = rs[col] + fracrowtofill * qRed(*xP) * qAlpha(*xP) / 255;
     261                    g = gs[col] + fracrowtofill * qGreen(*xP) * qAlpha(*xP) / 255;
     262                    b = bs[col] + fracrowtofill * qBlue(*xP) * qAlpha(*xP) / 255;
     263                    a = as[col] + fracrowtofill * qAlpha(*xP);
     264                    if (a) {
     265                        r = r * 255 / a * SCALE;
     266                        g = g * 255 / a * SCALE;
     267                        b = b * 255 / a * SCALE;
     268                    }
     269                } else {
     270                    r = rs[col] + fracrowtofill * qRed(*xP);
     271                    g = gs[col] + fracrowtofill * qGreen(*xP);
     272                    b = bs[col] + fracrowtofill * qBlue(*xP);
     273                    a = 0; // unwarn
     274                }
     275                r /= SCALE;
     276                if (r > maxval)
     277                    r = maxval;
     278                g /= SCALE;
     279                if (g > maxval)
     280                    g = maxval;
     281                b /= SCALE;
     282                if (b > maxval)
     283                    b = maxval;
     284                if (as) {
     285                    a /= SCALE;
     286                    if (a > maxval)
     287                        a = maxval;
     288                    *nxP = qRgba((int)r, (int)g, (int)b, (int)a);
     289                    as[col] = HALFSCALE;
     290                } else {
     291                    *nxP = qRgb((int)r, (int)g, (int)b);
     292                }
     293                rs[col] = gs[col] = bs[col] = HALFSCALE;
     294            }
     295            fracrowleft -= fracrowtofill;
     296            if (fracrowleft == 0) {
     297                fracrowleft = syscale;
     298                needtoreadrow = 1;
     299            }
     300            fracrowtofill = SCALE;
     301        }
     302
     303        // Now scale X from tempxelrow into dst and write it out.
     304        if (d->newcols == d->cols) {
     305            // shortcut X scaling if possible
     306            memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols * 4);
     307        } else {
     308            register long a, r, g, b;
     309            register long fraccoltofill, fraccolleft = 0;
     310            register int needcol;
     311
     312            nxP = (QRgb *)dst.scanLine(rowswritten++);
     313            QRgb *nxPEnd = nxP + d->newcols;
     314            fraccoltofill = SCALE;
     315            a = r = g = b = HALFSCALE;
     316            needcol = 0;
     317            for (col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP) {
     318                fraccolleft = sxscale;
     319                while (fraccolleft >= fraccoltofill) {
     320                    if (needcol) {
     321                        ++nxP;
     322                        a = r = g = b = HALFSCALE;
     323                    }
     324                    if (as) {
     325                        r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255;
     326                        g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255;
     327                        b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255;
     328                        a += fraccoltofill * qAlpha(*xP);
     329                        if (a) {
     330                            r = r * 255 / a * SCALE;
     331                            g = g * 255 / a * SCALE;
     332                            b = b * 255 / a * SCALE;
     333                        }
     334                    } else {
     335                        r += fraccoltofill * qRed(*xP);
     336                        g += fraccoltofill * qGreen(*xP);
     337                        b += fraccoltofill * qBlue(*xP);
     338                    }
     339                    r /= SCALE;
     340                    if (r > maxval)
     341                        r = maxval;
     342                    g /= SCALE;
     343                    if (g > maxval)
     344                        g = maxval;
     345                    b /= SCALE;
     346                    if (b > maxval)
     347                        b = maxval;
     348                    if (as) {
     349                        a /= SCALE;
     350                        if (a > maxval)
     351                            a = maxval;
     352                        *nxP = qRgba((int)r, (int)g, (int)b, (int)a);
     353                    } else {
     354                        *nxP = qRgb((int)r, (int)g, (int)b);
     355                    }
     356                    fraccolleft -= fraccoltofill;
     357                    fraccoltofill = SCALE;
     358                    needcol = 1;
     359                }
     360                if (fraccolleft > 0) {
     361                    if (needcol) {
     362                        ++nxP;
     363                        a = r = g = b = HALFSCALE;
     364                        needcol = 0;
     365                    }
     366                    if (as) {
     367                        a += fraccolleft * qAlpha(*xP);
     368                        r += fraccolleft * qRed(*xP) * qAlpha(*xP) / 255;
     369                        g += fraccolleft * qGreen(*xP) * qAlpha(*xP) / 255;
     370                        b += fraccolleft * qBlue(*xP) * qAlpha(*xP) / 255;
     371                    } else {
     372                        r += fraccolleft * qRed(*xP);
     373                        g += fraccolleft * qGreen(*xP);
     374                        b += fraccolleft * qBlue(*xP);
     375                    }
     376                    fraccoltofill -= fraccolleft;
     377                }
     378            }
     379            if (fraccoltofill > 0) {
     380                --xP;
     381                if (as) {
     382                    a += fraccolleft * qAlpha(*xP);
     383                    r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255;
     384                    g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255;
     385                    b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255;
     386                    if (a) {
     387                        r = r * 255 / a * SCALE;
     388                        g = g * 255 / a * SCALE;
     389                        b = b * 255 / a * SCALE;
     390                    }
     391                } else {
     392                    r += fraccoltofill * qRed(*xP);
     393                    g += fraccoltofill * qGreen(*xP);
     394                    b += fraccoltofill * qBlue(*xP);
     395                }
     396            }
     397            if (nxP < nxPEnd) {
     398                r /= SCALE;
     399                if (r > maxval)
     400                    r = maxval;
     401                g /= SCALE;
     402                if (g > maxval)
     403                    g = maxval;
     404                b /= SCALE;
     405                if (b > maxval)
     406                    b = maxval;
     407                if (as) {
     408                    a /= SCALE;
     409                    if (a > maxval)
     410                        a = maxval;
     411                    *nxP = qRgba((int)r, (int)g, (int)b, (int)a);
     412                } else {
     413                    *nxP = qRgb((int)r, (int)g, (int)b);
     414                }
     415                while (++nxP != nxPEnd)
     416                    nxP[0] = nxP[-1];
     417            }
     418        }
     419    }
     420
     421    if (d->newrows != d->rows && tempxelrow)// Robust, tempxelrow might be 0 1 day
     422        delete [] tempxelrow;
     423    if (as)                             // Avoid purify complaint
     424        delete [] as;
     425    if (rs)                             // Robust, rs might be 0 one day
     426        delete [] rs;
     427    if (gs)                             // Robust, gs might be 0 one day
     428        delete [] gs;
     429    if (bs)                             // Robust, bs might be 0 one day
     430        delete [] bs;
    451431
    452432    return dst;
     
    456436{
    457437public:
    458     jpegSmoothScaler(struct jpeg_decompress_struct *info, const char *params):
    459         QImageSmoothScaler(info->output_width, info->output_height, params)
     438    jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect)
     439        : QImageSmoothScaler(clipRect.width(), clipRect.height(),
     440                             dstSize.width(), dstSize.height())
    460441    {
    461         cinfo = info;
    462         cols24Bit = scaledWidth() * 3;
    463 
    464         cacheHeight = 1;
    465         imageCache = QImage( info->output_width, cacheHeight, QImage::Format_RGB32 );
     442        cinfo = info;
     443        clip = clipRect;
     444        imageCache = QImage(info->output_width, 1, QImage::Format_RGB32);
    466445    }
    467446
    468447private:
    469     int     cols24Bit;
     448    QRect   clip;
    470449    QImage  imageCache;
    471     int     cacheHeight;
    472450    struct jpeg_decompress_struct *cinfo;
    473451
     
    481459
    482460        uchar* data = imageCache.bits();
     461
     462        // Read ahead if we haven't reached the first clipped scanline yet.
     463        while (int(cinfo->output_scanline) < clip.y() &&
     464               cinfo->output_scanline < cinfo->output_height)
     465            jpeg_read_scanlines(cinfo, &data, 1);
     466
     467        // Read the next scanline.  We assume that "line"
     468        // will never be >= clip.height().
    483469        jpeg_read_scanlines(cinfo, &data, 1);
    484         out = (QRgb*)imageCache.scanLine(0);
     470        if (cinfo->output_scanline == cinfo->output_height)
     471            jpeg_finish_decompress(cinfo);
     472
     473        out = ((QRgb*)data) + clip.x();
    485474
    486475        //
     
    489478        //
    490479        if (cinfo->output_components == 1) {
    491             in = (uchar*)out + scaledWidth();
    492             for (uint i = scaledWidth(); i--; ) {
     480            in = data + clip.right();
     481            for (int i = clip.width(); i--; ) {
     482                out[i] = qRgb(*in, *in, *in);
    493483                in--;
    494                 out[i] = qRgb(*in, *in, *in);
    495484            }
    496         } else {
    497             in = (uchar*)out + cols24Bit;
    498             for (uint i = scaledWidth(); i--; ) {
     485        } else if (cinfo->out_color_space == JCS_CMYK) {
     486            in = data + clip.right() * 4;
     487            for (int i = clip.width(); i--; ) {
     488                int k = in[3];
     489                out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
     490                in -= 4;
     491            }
     492        } else {
     493            in = data + clip.right() * 3;
     494            for (int i = clip.width(); i--; ) {
     495                out[i] = qRgb(in[0], in[1], in[2]);
    499496                in -= 3;
    500                 out[i] = qRgb(in[0], in[1], in[2]);
    501497            }
    502498        }
     
    616612}
    617613
    618 
    619 static void scaleSize(int &reqW, int &reqH, int imgW, int imgH, Qt::AspectRatioMode mode)
    620 {
    621     if (mode == Qt::IgnoreAspectRatio)
    622         return;
    623     int t1 = imgW * reqH;
    624     int t2 = reqW * imgH;
    625     if ((mode == Qt::KeepAspectRatio && (t1 > t2)) || (mode == Qt::KeepAspectRatioByExpanding && (t1 < t2)))
    626         reqH = t2 / imgW;
    627     else
    628         reqW = t1 / imgH;
    629 }
    630614
    631615static bool read_jpeg_size(QIODevice *device, int &w, int &h)
     
    709693
    710694static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
    711                              bool dummy = false)
     695                             const QSize& size)
    712696{
    713697    QImage::Format format;
     
    724708    }
    725709
    726     const QSize size(info->output_width, info->output_height);
    727710    if (dest->size() != size || dest->format() != format) {
    728         static uchar dummyImage[1];
    729         if (dummy) // Create QImage but don't read the pixels
    730             *dest = QImage(dummyImage, size.width(), size.height(), format);
    731         else
    732             *dest = QImage(size, format);
     711        *dest = QImage(size, format);
    733712
    734713        if (format == QImage::Format_Indexed8) {
    735             dest->setNumColors(256);
     714            dest->setColorCount(256);
    736715            for (int i = 0; i < 256; i++)
    737716                dest->setColor(i, qRgb(i,i,i));
     
    743722
    744723static bool read_jpeg_image(QIODevice *device, QImage *outImage,
    745                             const QByteArray &parameters, QSize scaledSize,
    746                             int inQuality )
    747 {
    748 #ifdef QT_NO_IMAGE_SMOOTHSCALE
    749     Q_UNUSED( scaledSize );
    750 #endif
    751 
     724                            QSize scaledSize, QRect scaledClipRect,
     725                            QRect clipRect, int inQuality )
     726{
    752727    struct jpeg_decompress_struct cinfo;
    753728
     
    774749            quality = 75;
    775750
    776         QString params = QString::fromLatin1(parameters);
    777         params.simplified();
    778         int sWidth = 0, sHeight = 0;
    779         char sModeStr[1024] = "";
    780         Qt::AspectRatioMode sMode;
    781 
    782 #ifndef QT_NO_IMAGE_SMOOTHSCALE
    783         // If high quality not required, shrink image during decompression
    784         if (scaledSize.isValid() && quality < HIGH_QUALITY_THRESHOLD && !params.contains(QLatin1String("GetHeaderInformation")) ) {
    785             cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
    786                                      cinfo.image_width / scaledSize.height());
     751        // If possible, merge the scaledClipRect into either scaledSize
     752        // or clipRect to avoid doing a separate scaled clipping pass.
     753        // Best results are achieved by clipping before scaling, not after.
     754        if (!scaledClipRect.isEmpty()) {
     755            if (scaledSize.isEmpty() && clipRect.isEmpty()) {
     756                // No clipping or scaling before final clip.
     757                clipRect = scaledClipRect;
     758                scaledClipRect = QRect();
     759            } else if (scaledSize.isEmpty()) {
     760                // Clipping, but no scaling: combine the clip regions.
     761                scaledClipRect.translate(clipRect.topLeft());
     762                clipRect = scaledClipRect.intersected(clipRect);
     763                scaledClipRect = QRect();
     764            } else if (clipRect.isEmpty()) {
     765                // No clipping, but scaling: if we can map back to an
     766                // integer pixel boundary, then clip before scaling.
     767                if ((cinfo.image_width % scaledSize.width()) == 0 &&
     768                        (cinfo.image_height % scaledSize.height()) == 0) {
     769                    int x = scaledClipRect.x() * cinfo.image_width /
     770                            scaledSize.width();
     771                    int y = scaledClipRect.y() * cinfo.image_height /
     772                            scaledSize.height();
     773                    int width = (scaledClipRect.right() + 1) *
     774                                cinfo.image_width / scaledSize.width() - x;
     775                    int height = (scaledClipRect.bottom() + 1) *
     776                                 cinfo.image_height / scaledSize.height() - y;
     777                    clipRect = QRect(x, y, width, height);
     778                    scaledSize = scaledClipRect.size();
     779                    scaledClipRect = QRect();
     780                }
     781            } else {
     782                // Clipping and scaling: too difficult to figure out,
     783                // and not a likely use case, so do it the long way.
     784            }
     785        }
     786
     787        // Determine the scale factor to pass to libjpeg for quick downscaling.
     788        if (!scaledSize.isEmpty()) {
     789            if (clipRect.isEmpty()) {
     790                cinfo.scale_denom =
     791                    qMin(cinfo.image_width / scaledSize.width(),
     792                         cinfo.image_height / scaledSize.height());
     793            } else {
     794                cinfo.scale_denom =
     795                    qMin(clipRect.width() / scaledSize.width(),
     796                         clipRect.height() / scaledSize.height());
     797            }
    787798            if (cinfo.scale_denom < 2) {
    788799                cinfo.scale_denom = 1;
     
    795806            }
    796807            cinfo.scale_num = 1;
    797         }
    798 #endif
    799 
     808            if (!clipRect.isEmpty()) {
     809                // Correct the scale factor so that we clip accurately.
     810                // It is recommended that the clip rectangle be aligned
     811                // on an 8-pixel boundary for best performance.
     812                while (cinfo.scale_denom > 1 &&
     813                       ((clipRect.x() % cinfo.scale_denom) != 0 ||
     814                        (clipRect.y() % cinfo.scale_denom) != 0 ||
     815                        (clipRect.width() % cinfo.scale_denom) != 0 ||
     816                        (clipRect.height() % cinfo.scale_denom) != 0)) {
     817                    cinfo.scale_denom /= 2;
     818                }
     819            }
     820        }
    800821
    801822        // If high quality not required, use fast decompression
     
    805826        }
    806827
    807 
    808         (void) jpeg_start_decompress(&cinfo);
    809 
    810         if (params.contains(QLatin1String("GetHeaderInformation"))) {
    811             if (!ensureValidImage(outImage, &cinfo, true))
     828        (void) jpeg_calc_output_dimensions(&cinfo);
     829
     830        // Determine the clip region to extract.
     831        QRect imageRect(0, 0, cinfo.output_width, cinfo.output_height);
     832        QRect clip;
     833        if (clipRect.isEmpty()) {
     834            clip = imageRect;
     835        } else if (cinfo.scale_denom == 1) {
     836            clip = clipRect.intersected(imageRect);
     837        } else {
     838            // The scale factor was corrected above to ensure that
     839            // we don't miss pixels when we scale the clip rectangle.
     840            clip = QRect(clipRect.x() / int(cinfo.scale_denom),
     841                         clipRect.y() / int(cinfo.scale_denom),
     842                         clipRect.width() / int(cinfo.scale_denom),
     843                         clipRect.height() / int(cinfo.scale_denom));
     844            clip = clip.intersected(imageRect);
     845        }
     846
     847#ifndef QT_NO_IMAGE_SMOOTHSCALE
     848        if (scaledSize.isValid() && scaledSize != clip.size()
     849            && quality >= HIGH_QUALITY_THRESHOLD) {
     850
     851            (void) jpeg_start_decompress(&cinfo);
     852
     853            jpegSmoothScaler scaler(&cinfo, scaledSize, clip);
     854            *outImage = scaler.scale();
     855        } else
     856#endif
     857        {
     858            // Allocate memory for the clipped QImage.
     859            if (!ensureValidImage(outImage, &cinfo, clip.size()))
    812860                longjmp(jerr.setjmp_buffer, 1);
    813         } else if (params.contains(QLatin1String("Scale"))) {
    814 #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
    815             sscanf_s(params.toLatin1().data(), "Scale(%i, %i, %1023s)",
    816                      &sWidth, &sHeight, sModeStr, sizeof(sModeStr));
    817 #else
    818             sscanf(params.toLatin1().data(), "Scale(%i, %i, %1023s)",
    819                    &sWidth, &sHeight, sModeStr);
    820 #endif
    821 
    822             QString sModeQStr(QString::fromLatin1(sModeStr));
    823             if (sModeQStr == QLatin1String("IgnoreAspectRatio")) {
    824                 sMode = Qt::IgnoreAspectRatio;
    825             } else if (sModeQStr == QLatin1String("KeepAspectRatio")) {
    826                 sMode = Qt::KeepAspectRatio;
    827             } else if (sModeQStr == QLatin1String("KeepAspectRatioByExpanding")) {
    828                 sMode = Qt::KeepAspectRatioByExpanding;
    829             } else {
    830                 qDebug("read_jpeg_image: invalid aspect ratio mode \"%s\", see QImage::AspectRatioMode documentation", sModeStr);
    831                 sMode = Qt::KeepAspectRatio;
    832             }
    833 
    834 //            qDebug("Parameters ask to scale the image to %i x %i AspectRatioMode: %s", sWidth, sHeight, sModeStr);
    835             scaleSize(sWidth, sHeight, cinfo.output_width, cinfo.output_height, sMode);
    836 //            qDebug("Scaling the jpeg to %i x %i", sWidth, sHeight, sModeStr);
    837 
    838             if (cinfo.output_components == 3 || cinfo.output_components == 4) {
    839                 if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_RGB32)
    840                     *outImage = QImage(sWidth, sHeight, QImage::Format_RGB32);
    841             } else if (cinfo.output_components == 1) {
    842                 if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_Indexed8)
    843                     *outImage = QImage(sWidth, sHeight, QImage::Format_Indexed8);
    844                 outImage->setNumColors(256);
    845                 for (int i = 0; i < 256; ++i)
    846                     outImage->setColor(i, qRgb(i,i,i));
    847             } else {
    848                 // Unsupported format
    849             }
    850             if (outImage->isNull())
    851                 longjmp(jerr.setjmp_buffer, 1);
    852 
    853             if (!outImage->isNull()) {
    854                 QImage tmpImage(cinfo.output_width, 1, QImage::Format_RGB32);
    855                 uchar* inData = tmpImage.bits();
    856                 uchar* outData = outImage->bits();
    857                 int out_bpl = outImage->bytesPerLine();
     861
     862            // Avoid memcpy() overhead if grayscale with no clipping.
     863            bool quickGray = (cinfo.output_components == 1 &&
     864                              clip == imageRect);
     865            if (!quickGray) {
     866                // Ask the jpeg library to allocate a temporary row.
     867                // The library will automatically delete it for us later.
     868                // The libjpeg docs say we should do this before calling
     869                // jpeg_start_decompress().  We can't use "new" here
     870                // because we are inside the setjmp() block and an error
     871                // in the jpeg input stream would cause a memory leak.
     872                JSAMPARRAY rows = (cinfo.mem->alloc_sarray)
     873                    ((j_common_ptr)&cinfo, JPOOL_IMAGE,
     874                     cinfo.output_width * cinfo.output_components, 1);
     875
     876                (void) jpeg_start_decompress(&cinfo);
     877
    858878                while (cinfo.output_scanline < cinfo.output_height) {
    859                     int outputLine = sHeight * cinfo.output_scanline / cinfo.output_height;
    860                     (void) jpeg_read_scanlines(&cinfo, &inData, 1);
     879                    int y = int(cinfo.output_scanline) - clip.y();
     880                    if (y >= clip.height())
     881                        break;      // We've read the entire clip region, so abort.
     882
     883                    (void) jpeg_read_scanlines(&cinfo, rows, 1);
     884
     885                    if (y < 0)
     886                        continue;   // Haven't reached the starting line yet.
     887
    861888                    if (cinfo.output_components == 3) {
    862                         uchar *in = inData;
    863                         QRgb *out = (QRgb*)outData + outputLine * out_bpl;
    864                         for (uint i=0; i<cinfo.output_width; i++) {
    865 // ### Only scaling down an image works, I don't think scaling up will work at the moment
    866 // ### An idea I have to make this a smooth scale is to progressively add the pixel values up
    867 // When scaling down, multiple values are being over drawn in to the output buffer.
    868 // Instead, a weighting based on the distance the line or pixel is from the output pixel determines
    869 // the weight of it when added to the output buffer. At present it is a non-smooth scale which is
    870 // inefficently implemented, it still uncompresses all the jpeg, an optimization for progressive
    871 // jpegs could be made if scaling by say 50% or some other special cases
    872                             out[sWidth * i / cinfo.output_width] = qRgb(in[0], in[1], in[2]);
     889                        // Expand 24->32 bpp.
     890                        uchar *in = rows[0] + clip.x() * 3;
     891                        QRgb *out = (QRgb*)outImage->scanLine(y);
     892                        for (int i = 0; i < clip.width(); ++i) {
     893                            *out++ = qRgb(in[0], in[1], in[2]);
    873894                            in += 3;
    874895                        }
    875                     } else {
    876 // ### Need to test the case where the jpeg is grayscale, need some black and white jpegs to test
    877 // this code. (also only scales down and probably won't scale to a larger size)
    878                         uchar *in = inData;
    879                         uchar *out = outData + outputLine*out_bpl;
    880                         for (uint i=0; i<cinfo.output_width; i++) {
    881                             out[sWidth * i / cinfo.output_width] = in[i];
     896                    } else if (cinfo.out_color_space == JCS_CMYK) {
     897                        // Convert CMYK->RGB.
     898                        uchar *in = rows[0] + clip.x() * 4;
     899                        QRgb *out = (QRgb*)outImage->scanLine(y);
     900                        for (int i = 0; i < clip.width(); ++i) {
     901                            int k = in[3];
     902                            *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
     903                                          k * in[2] / 255);
     904                            in += 4;
    882905                        }
     906                    } else if (cinfo.output_components == 1) {
     907                        // Grayscale.
     908                        memcpy(outImage->scanLine(y),
     909                               rows[0] + clip.x(), clip.width());
    883910                    }
    884911                }
     912            } else {
     913                // Load unclipped grayscale data directly into the QImage.
     914                (void) jpeg_start_decompress(&cinfo);
     915                while (cinfo.output_scanline < cinfo.output_height) {
     916                    uchar *row = outImage->scanLine(cinfo.output_scanline);
     917                    (void) jpeg_read_scanlines(&cinfo, &row, 1);
     918                }
     919            }
     920
     921            if (cinfo.output_scanline == cinfo.output_height)
    885922                (void) jpeg_finish_decompress(&cinfo);
    886             }
    887 #ifndef QT_NO_IMAGE_SMOOTHSCALE
    888         } else if (scaledSize.isValid()) {
    889 
    890             jpegSmoothScaler scaler(&cinfo, QString().sprintf("Scale( %d, %d, ScaleFree )",
    891                                                               scaledSize.width(),
    892                                                               scaledSize.height()).toLatin1().data());
    893             *outImage = scaler.scale();
    894 #endif
    895         } else {
    896             if (!ensureValidImage(outImage, &cinfo))
    897                 longjmp(jerr.setjmp_buffer, 1);
    898 
    899             uchar* data = outImage->bits();
    900             int bpl = outImage->bytesPerLine();
    901             while (cinfo.output_scanline < cinfo.output_height) {
    902                 uchar *d = data + cinfo.output_scanline * bpl;
    903                 (void) jpeg_read_scanlines(&cinfo,
    904                                            &d,
    905                                            1);
    906             }
    907             (void) jpeg_finish_decompress(&cinfo);
    908 
    909             if (cinfo.output_components == 3) {
    910                 // Expand 24->32 bpp.
    911                 for (uint j=0; j<cinfo.output_height; j++) {
    912                     uchar *in = outImage->scanLine(j) + cinfo.output_width * 3;
    913                     QRgb *out = (QRgb*)outImage->scanLine(j);
    914 
    915                     for (uint i=cinfo.output_width; i--;) {
    916                         in-=3;
    917                         out[i] = qRgb(in[0], in[1], in[2]);
    918                     }
    919                 }
    920             } else if (cinfo.out_color_space == JCS_CMYK) {
    921                 for (uint j = 0; j < cinfo.output_height; ++j) {
    922                     uchar *in = outImage->scanLine(j) + cinfo.output_width * 4;
    923                     QRgb *out = (QRgb*)outImage->scanLine(j);
    924 
    925                     for (uint i = cinfo.output_width; i--; ) {
    926                         in-=4;
    927                         int k = in[3];
    928                         out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
    929                     }
    930                 }
    931             }
     923
    932924            if (cinfo.density_unit == 1) {
    933925                outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54));
     
    937929                outImage->setDotsPerMeterY(int(100. * cinfo.Y_density));
    938930            }
     931
     932            if (scaledSize.isValid() && scaledSize != clip.size())
     933                *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation);
    939934        }
    940935    }
     
    942937    jpeg_destroy_decompress(&cinfo);
    943938    delete iod_src;
     939    if (!scaledClipRect.isEmpty())
     940        *outImage = outImage->copy(scaledClipRect);
    944941    return !outImage->isNull();
    945942}
     
    10411038        case QImage::Format_Indexed8:
    10421039            gray = true;
    1043             for (int i = image.numColors(); gray && i--;) {
     1040            for (int i = image.colorCount(); gray && i--;) {
    10441041                gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) &&
    10451042                               qRed(cmap[i]) == qBlue(cmap[i]));
     
    11991196    if (!canRead())
    12001197        return false;
    1201     return read_jpeg_image(device(), image, parameters, scaledSize, quality);
     1198    return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality);
    12021199}
    12031200
     
    12101207{
    12111208    return option == Quality
    1212 #ifndef QT_NO_IMAGE_SMOOTHSCALE
    12131209        || option == ScaledSize
    1214 #endif
     1210        || option == ScaledClipRect
     1211        || option == ClipRect
    12151212        || option == Size
    12161213        || option == ImageFormat;
     
    12211218    if (option == Quality) {
    12221219        return quality;
    1223 #ifndef QT_NO_IMAGE_SMOOTHSCALE
    12241220    } else if  (option == ScaledSize) {
    12251221        return scaledSize;
    1226 #endif
     1222    } else if  (option == ScaledClipRect) {
     1223        return scaledClipRect;
     1224    } else if  (option == ClipRect) {
     1225        return clipRect;
    12271226    } else if (option == Size) {
    12281227        if (canRead() && !device()->isSequential()) {
     
    12511250    if (option == Quality)
    12521251        quality = value.toInt();
    1253 #ifndef QT_NO_IMAGE_SMOOTHSCALE
    12541252    else if ( option == ScaledSize )
    12551253        scaledSize = value.toSize();
    1256 #endif
     1254    else if ( option == ScaledClipRect )
     1255        scaledClipRect = value.toRect();
     1256    else if ( option == ClipRect )
     1257        clipRect = value.toRect();
    12571258}
    12581259
  • trunk/src/plugins/imageformats/jpeg/qjpeghandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4545#include <QtGui/qimageiohandler.h>
    4646#include <QtCore/QSize>
     47#include <QtCore/QRect>
    4748
    4849QT_BEGIN_NAMESPACE
     
    6768private:
    6869    int quality;
    69     QByteArray parameters;
    7070    QSize scaledSize;
     71    QRect scaledClipRect;
     72    QRect clipRect;
    7173};
    7274
  • trunk/src/plugins/imageformats/mng/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/mng/mng.pro

    r2 r561  
    77SOURCES += main.cpp \
    88           qmnghandler.cpp
     9
     10symbian: {
     11        #Disable warnings in 3rdparty code due to unused variables and arguments
     12        QMAKE_CXXFLAGS.CW += -W nounused
     13        TARGET.UID3=0x2001E619
     14}
    915
    1016contains(QT_CONFIG, system-mng) {
     
    4854target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    4955INSTALLS += target
     56
  • trunk/src/plugins/imageformats/mng/qmnghandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    376376QMngHandler::~QMngHandler()
    377377{
    378     Q_D(QMngHandler);
    379     delete d;
    380378}
    381379
  • trunk/src/plugins/imageformats/mng/qmnghandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4343#define QMNGHANDLER_H
    4444
     45#include <QtCore/qscopedpointer.h>
    4546#include <QtGui/qimageiohandler.h>
    4647
     
    7576    private:
    7677    Q_DECLARE_PRIVATE(QMngHandler)
    77     QMngHandlerPrivate *d_ptr;
     78    QScopedPointer<QMngHandlerPrivate> d_ptr;
    7879};
    7980
  • trunk/src/plugins/imageformats/svg/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/svg/qsvgiohandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    6565
    6666    bool load(QIODevice *device);
     67    static bool findSvgTag(QIODevice *device);
    6768
    6869    QSvgRenderer *r;
     
    8788}
    8889
     90bool QSvgIOHandlerPrivate::findSvgTag(QIODevice *device)
     91{
     92    qint64 pos = device->pos();
     93    device->seek(0);
     94    char buffer[256];
     95    const char svg_tag[] = "<svg";
     96
     97    while (1) {
     98        int size = device->read(buffer, 256);
     99        for (int i=0; i<size - 5; ++i) {
     100            if (!memcmp(buffer + i, svg_tag, 4)) {
     101                if (buffer[i+4] == ' ' || buffer[i+4] == '\t'
     102                    || buffer[i+4] == '\n' || buffer[i+4] == '\r')
     103                {
     104                    device->seek(pos);
     105                    return true;
     106                }
     107            }
     108        }
     109        if (device->atEnd())
     110            break;
     111        device->seek(device->pos()-4);
     112    }
     113    device->seek(pos);
     114    return false;
     115}
     116
    89117QSvgIOHandler::QSvgIOHandler()
    90118    : d(new QSvgIOHandlerPrivate())
     
    102130bool QSvgIOHandler::canRead() const
    103131{
    104     QByteArray contents = device()->peek(80);
    105 
    106     return contents.contains("<svg");
     132    return QSvgIOHandlerPrivate::findSvgTag(device());
    107133}
    108134
     
    183209bool QSvgIOHandler::canRead(QIODevice *device)
    184210{
    185     QByteArray contents = device->peek(80);
    186     return contents.contains("<svg");
     211    return QSvgIOHandlerPrivate::findSvgTag(device);
    187212}
    188213
  • trunk/src/plugins/imageformats/svg/qsvgiohandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/svg/svg.pro

    r2 r561  
    1010target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    1111INSTALLS += target
     12
     13symbian:TARGET.UID3=0x2001E618
  • trunk/src/plugins/imageformats/tiff/main.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/tiff/qtiffhandler.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    9999}
    100100
     101// for 32 bits images
     102inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal
     103{
     104    const int height = image->height();
     105    const int width = image->width();
     106    QImage generated(/* width = */ height, /* height = */ width, image->format());
     107    const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits());
     108    uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits());
     109    for (int row=0; row < height; ++row) {
     110        for (int col=0; col < width; ++col) {
     111            int idx = col * height + row;
     112            generatedPixels[idx] = *originalPixel;
     113            ++originalPixel;
     114        }
     115    }
     116    *image = generated;
     117}
     118
     119inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical
     120{
     121    const int height = image->height();
     122    const int width = image->width();
     123    QImage generated(/* width = */ height, /* height = */ width, image->format());
     124    const int lastCol = width - 1;
     125    const int lastRow = height - 1;
     126    const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits());
     127    uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits());
     128    for (int row=0; row < height; ++row) {
     129        for (int col=0; col < width; ++col) {
     130            int idx = (lastCol - col) * height + (lastRow - row);
     131            generatedBits[idx] = *pixel;
     132            ++pixel;
     133        }
     134    }
     135    *image = generated;
     136}
     137
    101138QTiffHandler::QTiffHandler() : QImageIOHandler()
    102139{
     
    132169        return false;
    133170
    134     TIFF *tiff = TIFFClientOpen("foo",
    135                                 "r",
    136                                 this,
    137                                 qtiffReadProc,
    138                                 qtiffWriteProc,
    139                                 qtiffSeekProc,
    140                                 qtiffCloseProc,
    141                                 qtiffSizeProc,
    142                                 qtiffMapProc,
    143                                 qtiffUnmapProc);
    144 
    145     if (tiff) {
    146         uint32 width = 0;
    147         uint32 height = 0;
    148         TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);
    149         TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);
    150         if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32)
    151             *image = QImage(width, height, QImage::Format_ARGB32);
     171    TIFF *const tiff = TIFFClientOpen("foo",
     172                                      "r",
     173                                      this,
     174                                      qtiffReadProc,
     175                                      qtiffWriteProc,
     176                                      qtiffSeekProc,
     177                                      qtiffCloseProc,
     178                                      qtiffSizeProc,
     179                                      qtiffMapProc,
     180                                      qtiffUnmapProc);
     181
     182    if (!tiff) {
     183        return false;
     184    }
     185    uint32 width;
     186    uint32 height;
     187    uint16 photometric;
     188    if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)
     189        || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height)
     190        || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
     191        TIFFClose(tiff);
     192        return false;
     193    }
     194
     195    // BitsPerSample defaults to 1 according to the TIFF spec.
     196    uint16 bitPerSample;
     197    if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
     198        bitPerSample = 1;
     199
     200    bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE;
     201    if (grayscale && bitPerSample == 1) {
     202        if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
     203            *image = QImage(width, height, QImage::Format_Mono);
     204        QVector<QRgb> colortable(2);
     205        if (photometric == PHOTOMETRIC_MINISBLACK) {
     206            colortable[0] = 0xff000000;
     207            colortable[1] = 0xffffffff;
     208        } else {
     209            colortable[0] = 0xffffffff;
     210            colortable[1] = 0xff000000;
     211        }
     212        image->setColorTable(colortable);
     213
    152214        if (!image->isNull()) {
    153             if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, 0)) {
    154                 uint16 resUnit = RESUNIT_NONE;
    155                 float resX = 0;
    156                 float resY = 0;
    157                 TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit);
    158                 TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX);
    159                 TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY);
    160                 switch(resUnit) {
    161                     case RESUNIT_CENTIMETER:
    162                         image->setDotsPerMeterX(qRound(resX * 100));
    163                         image->setDotsPerMeterY(qRound(resY * 100));
    164                         break;
    165                     case RESUNIT_INCH:
    166                         image->setDotsPerMeterX(qRound(resX * (100 / 2.54)));
    167                         image->setDotsPerMeterY(qRound(resY * (100 / 2.54)));
    168                         break;
    169                     default:
    170                         // do nothing as defaults have already
    171                                                 // been set within the QImage class
    172                         break;
    173                 }
    174                 for (uint32 y=0; y<height; ++y)
    175                     convert32BitOrder(image->scanLine(y), width);
    176             } else {
    177                 *image = QImage();
    178             }
    179         }
     215            for (uint32 y=0; y<height; ++y) {
     216                if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
     217                    TIFFClose(tiff);
     218                    return false;
     219                }
     220            }
     221        }
     222    } else {
     223        if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) {
     224            if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8)
     225                *image = QImage(width, height, QImage::Format_Indexed8);
     226            if (!image->isNull()) {
     227                const uint16 tableSize = 256;
     228                QVector<QRgb> qtColorTable(tableSize);
     229                if (grayscale) {
     230                    for (int i = 0; i<tableSize; ++i) {
     231                        const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
     232                        qtColorTable[i] = qRgb(c, c, c);
     233                    }
     234                } else {
     235                    // create the color table
     236                    uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
     237                    uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
     238                    uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
     239                    if (!redTable || !greenTable || !blueTable) {
     240                        TIFFClose(tiff);
     241                        return false;
     242                    }
     243                    if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
     244                        TIFFClose(tiff);
     245                        return false;
     246                    }
     247
     248                    for (int i = 0; i<tableSize ;++i) {
     249                        const int red = redTable[i] / 257;
     250                        const int green = greenTable[i] / 257;
     251                        const int blue = blueTable[i] / 257;
     252                        qtColorTable[i] = qRgb(red, green, blue);
     253                    }
     254                }
     255
     256                image->setColorTable(qtColorTable);
     257                for (uint32 y=0; y<height; ++y) {
     258                    if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
     259                        TIFFClose(tiff);
     260                        return false;
     261                    }
     262                }
     263
     264                // free redTable, greenTable and greenTable done by libtiff
     265            }
     266        } else {
     267            if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32)
     268                *image = QImage(width, height, QImage::Format_ARGB32);
     269            if (!image->isNull()) {
     270                const int stopOnError = 1;
     271                if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) {
     272                    for (uint32 y=0; y<height; ++y)
     273                        convert32BitOrder(image->scanLine(y), width);
     274                } else {
     275                    TIFFClose(tiff);
     276                    return false;
     277                }
     278            }
     279        }
     280    }
     281
     282    if (image->isNull()) {
    180283        TIFFClose(tiff);
    181     }
    182 
    183     if (image->isNull())
    184         return false;
    185 
     284        return false;
     285    }
     286
     287    float resX = 0;
     288    float resY = 0;
     289    uint16 resUnit = RESUNIT_NONE;
     290    if (TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit)
     291        && TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX)
     292        && TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) {
     293
     294        switch(resUnit) {
     295        case RESUNIT_CENTIMETER:
     296            image->setDotsPerMeterX(qRound(resX * 100));
     297            image->setDotsPerMeterY(qRound(resY * 100));
     298            break;
     299        case RESUNIT_INCH:
     300            image->setDotsPerMeterX(qRound(resX * (100 / 2.54)));
     301            image->setDotsPerMeterY(qRound(resY * (100 / 2.54)));
     302            break;
     303        default:
     304            // do nothing as defaults have already
     305            // been set within the QImage class
     306            break;
     307        }
     308    }
     309
     310    // rotate the image if the orientation is defined in the file
     311    uint16 orientationTag;
     312    if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) {
     313        if (image->format() == QImage::Format_ARGB32) {
     314            // TIFFReadRGBAImageOriented() flip the image but does not rotate them
     315            switch (orientationTag) {
     316            case 5:
     317                rotate_right_mirror_horizontal(image);
     318                break;
     319            case 6:
     320                rotate_right_mirror_vertical(image);
     321                break;
     322            case 7:
     323                rotate_right_mirror_horizontal(image);
     324                break;
     325            case 8:
     326                rotate_right_mirror_vertical(image);
     327                break;
     328            }
     329        } else {
     330            switch (orientationTag) {
     331            case 1: // default orientation
     332                break;
     333            case 2: // mirror horizontal
     334                *image = image->mirrored(true, false);
     335                break;
     336            case 3: // mirror both
     337                *image = image->mirrored(true, true);
     338                break;
     339            case 4: // mirror vertical
     340                *image = image->mirrored(false, true);
     341                break;
     342            case 5: // rotate right mirror horizontal
     343                {
     344                    QMatrix transformation;
     345                    transformation.rotate(90);
     346                    *image = image->transformed(transformation);
     347                    *image = image->mirrored(true, false);
     348                    break;
     349                }
     350            case 6: // rotate right
     351                {
     352                    QMatrix transformation;
     353                    transformation.rotate(90);
     354                    *image = image->transformed(transformation);
     355                    break;
     356                }
     357            case 7: // rotate right, mirror vertical
     358                {
     359                    QMatrix transformation;
     360                    transformation.rotate(90);
     361                    *image = image->transformed(transformation);
     362                    *image = image->mirrored(false, true);
     363                    break;
     364                }
     365            case 8: // rotate left
     366                {
     367                    QMatrix transformation;
     368                    transformation.rotate(270);
     369                    *image = image->transformed(transformation);
     370                    break;
     371                }
     372            }
     373        }
     374    }
     375
     376
     377    TIFFClose(tiff);
    186378    return true;
    187379}
    188380
     381static bool checkGrayscale(const QVector<QRgb> &colorTable)
     382{
     383    if (colorTable.size() != 256)
     384        return false;
     385
     386    const bool increasing = (colorTable.at(0) == 0xff000000);
     387    for (int i = 0; i < 256; ++i) {
     388        if (increasing && colorTable.at(i) != qRgb(i, i, i)
     389            || !increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i))
     390            return false;
     391    }
     392    return true;
     393}
     394
    189395bool QTiffHandler::write(const QImage &image)
    190396{
     
    192398        return false;
    193399
    194     TIFF *tiff = TIFFClientOpen("foo",
    195                                 "w",
    196                                 this,
    197                                 qtiffReadProc,
    198                                 qtiffWriteProc,
    199                                 qtiffSeekProc,
    200                                 qtiffCloseProc,
    201                                 qtiffSizeProc,
    202                                 qtiffMapProc,
    203                                 qtiffUnmapProc);
    204 
    205     if (tiff) {
    206         int width = image.width();
    207         int height = image.height();
    208         int depth = 32;
    209 
    210         if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width)
    211                 || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height)
    212                 || !TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
    213                 || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
    214                 || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, depth/8)
    215                 || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
    216                 || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
     400    TIFF *const tiff = TIFFClientOpen("foo",
     401                                      "w",
     402                                      this,
     403                                      qtiffReadProc,
     404                                      qtiffWriteProc,
     405                                      qtiffSeekProc,
     406                                      qtiffCloseProc,
     407                                      qtiffSizeProc,
     408                                      qtiffMapProc,
     409                                      qtiffUnmapProc);
     410    if (!tiff)
     411        return false;
     412
     413    const int width = image.width();
     414    const int height = image.height();
     415
     416    if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width)
     417        || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height)
     418        || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
     419        TIFFClose(tiff);
     420        return false;
     421    }
     422
     423    // set the resolution
     424    bool  resolutionSet = false;
     425    const int dotPerMeterX = image.dotsPerMeterX();
     426    const int dotPerMeterY = image.dotsPerMeterY();
     427    if ((dotPerMeterX % 100) == 0
     428        && (dotPerMeterY % 100) == 0) {
     429        resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER)
     430                        && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0)
     431                        && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0);
     432    } else {
     433        resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)
     434                        && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX()))
     435                        && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY()));
     436    }
     437    if (!resolutionSet) {
     438        TIFFClose(tiff);
     439        return false;
     440    }
     441
     442    // configure image depth
     443    const QImage::Format format = image.format();
     444    if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
     445        uint16 photometric = PHOTOMETRIC_MINISBLACK;
     446        if (image.colorTable().at(0) == 0xffffffff)
     447            photometric = PHOTOMETRIC_MINISWHITE;
     448        if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
     449            || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)
     450            || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) {
    217451            TIFFClose(tiff);
    218452            return false;
    219453        }
    220454
     455        // try to do the conversion in chunks no greater than 16 MB
     456        int chunks = (width * height / (1024 * 1024 * 16)) + 1;
     457        int chunkHeight = qMax(height / chunks, 1);
     458
     459        int y = 0;
     460        while (y < height) {
     461            QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono);
     462
     463            int chunkStart = y;
     464            int chunkEnd = y + chunk.height();
     465            while (y < chunkEnd) {
     466                if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
     467                    TIFFClose(tiff);
     468                    return false;
     469                }
     470                ++y;
     471            }
     472        }
     473        TIFFClose(tiff);
     474    } else if (format == QImage::Format_Indexed8) {
     475        const QVector<QRgb> colorTable = image.colorTable();
     476        bool isGrayscale = checkGrayscale(colorTable);
     477        if (isGrayscale) {
     478            uint16 photometric = PHOTOMETRIC_MINISBLACK;
     479            if (image.colorTable().at(0) == 0xffffffff)
     480                photometric = PHOTOMETRIC_MINISWHITE;
     481            if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
     482                    || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
     483                    || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
     484                TIFFClose(tiff);
     485                return false;
     486            }
     487        } else {
     488            if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE)
     489                    || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
     490                    || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
     491                TIFFClose(tiff);
     492                return false;
     493            }
     494            //// write the color table
     495            // allocate the color tables
     496            uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
     497            uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
     498            uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
     499            if (!redTable || !greenTable || !blueTable) {
     500                TIFFClose(tiff);
     501                return false;
     502            }
     503
     504            // set the color table
     505            const int tableSize = colorTable.size();
     506            Q_ASSERT(tableSize <= 256);
     507            for (int i = 0; i<tableSize; ++i) {
     508                const QRgb color = colorTable.at(i);
     509                redTable[i] = qRed(color) * 257;
     510                greenTable[i] = qGreen(color) * 257;
     511                blueTable[i] = qBlue(color) * 257;
     512            }
     513
     514            const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable);
     515
     516            qFree(redTable);
     517            qFree(greenTable);
     518            qFree(blueTable);
     519
     520            if (!setColorTableSuccess) {
     521                TIFFClose(tiff);
     522                return false;
     523            }
     524        }
     525
     526        //// write the data
     527        // try to do the conversion in chunks no greater than 16 MB
     528        int chunks = (width * height/ (1024 * 1024 * 16)) + 1;
     529        int chunkHeight = qMax(height / chunks, 1);
     530
     531        int y = 0;
     532        while (y < height) {
     533            QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y));
     534
     535            int chunkStart = y;
     536            int chunkEnd = y + chunk.height();
     537            while (y < chunkEnd) {
     538                if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
     539                    TIFFClose(tiff);
     540                    return false;
     541                }
     542                ++y;
     543            }
     544        }
     545        TIFFClose(tiff);
     546
     547    } else {
     548        if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
     549            || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
     550            || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
     551            || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
     552            TIFFClose(tiff);
     553            return false;
     554        }
    221555        // try to do the ARGB32 conversion in chunks no greater than 16 MB
    222556        int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1;
     
    243577        }
    244578        TIFFClose(tiff);
    245     } else {
    246         return false;
    247     }
     579    }
     580
    248581    return true;
    249582}
  • trunk/src/plugins/imageformats/tiff/qtiffhandler.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the plugins of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
  • trunk/src/plugins/imageformats/tiff/tiff.pro

    r165 r561  
    6060               SOURCES += ../../../corelib/kernel/qfunctions_wince.cpp
    6161            }
     62            symbian*: {
     63               SOURCES += ../../../3rdparty/libtiff/port/lfind.c
     64            }
    6265}
    6366
     
    7275target.path += $$[QT_INSTALL_PLUGINS]/imageformats
    7376INSTALLS += target
     77
     78symbian:TARGET.UID3=0x2001E617
Note: See TracChangeset for help on using the changeset viewer.