src/plugins/imageformats/jpeg/qjpeghandler.cpp
changeset 30 5dc02b23752f
parent 19 fcece45ef507
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    42 #include "qjpeghandler.h"
    42 #include "qjpeghandler.h"
    43 
    43 
    44 #include <qimage.h>
    44 #include <qimage.h>
    45 #include <qvariant.h>
    45 #include <qvariant.h>
    46 #include <qvector.h>
    46 #include <qvector.h>
       
    47 #include <qbuffer.h>
    47 
    48 
    48 #include <stdio.h>      // jpeglib needs this to be pre-included
    49 #include <stdio.h>      // jpeglib needs this to be pre-included
    49 #include <setjmp.h>
    50 #include <setjmp.h>
    50 
    51 
    51 #ifdef FAR
    52 #ifdef FAR
    52 #undef FAR
    53 #undef FAR
    53 #endif
    54 #endif
    54 
       
    55 // hw: optimize smoothscaler for returning 24-bit images
       
    56 
    55 
    57 // including jpeglib.h seems to be a little messy
    56 // including jpeglib.h seems to be a little messy
    58 extern "C" {
    57 extern "C" {
    59 // mingw includes rpcndr.h but does not define boolean
    58 // mingw includes rpcndr.h but does not define boolean
    60 #if defined(Q_OS_WIN) && defined(Q_CC_GNU)
    59 #if defined(Q_OS_WIN) && defined(Q_CC_GNU)
    74 #endif
    73 #endif
    75 }
    74 }
    76 
    75 
    77 QT_BEGIN_NAMESPACE
    76 QT_BEGIN_NAMESPACE
    78 
    77 
    79 //#define QT_NO_IMAGE_SMOOTHSCALE
       
    80 #ifndef QT_NO_IMAGE_SMOOTHSCALE
       
    81 class QImageSmoothScalerPrivate;
       
    82 class QImageSmoothScaler
       
    83 {
       
    84 public:
       
    85     QImageSmoothScaler(const int w, const int h, const QImage &src);
       
    86     QImageSmoothScaler(const int srcWidth, const int srcHeight,
       
    87                        const int dstWidth, const int dstHeight);
       
    88 
       
    89     virtual ~QImageSmoothScaler(void);
       
    90 
       
    91     QImage  scale();
       
    92 
       
    93 private:
       
    94     QImageSmoothScalerPrivate	*d;
       
    95     virtual QRgb *scanLine(const int line = 0, const QImage *src = 0);
       
    96 };
       
    97 
       
    98 class QImageSmoothScalerPrivate
       
    99 {
       
   100 public:
       
   101     int	    cols;
       
   102     int	    newcols;
       
   103     int	    rows;
       
   104     int	    newrows;
       
   105     bool    hasAlpha;
       
   106 
       
   107     const QImage  *src;
       
   108 
       
   109     void setup(const int srcWidth, const int srcHeight, const int dstWidth,
       
   110                const int dstHeight, bool hasAlphaChannel);
       
   111 };
       
   112 
       
   113 QImageSmoothScaler::QImageSmoothScaler(const int w, const int h,
       
   114                                        const QImage &src)
       
   115 {
       
   116     d = new QImageSmoothScalerPrivate;
       
   117 
       
   118     d->setup(src.width(), src.height(), w, h, src.hasAlphaChannel() );
       
   119     this->d->src = &src;
       
   120 }
       
   121 
       
   122 QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight,
       
   123                                        const int dstWidth, const int dstHeight)
       
   124 {
       
   125     d = new QImageSmoothScalerPrivate;
       
   126     d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0);
       
   127 }
       
   128 
       
   129 void QImageSmoothScalerPrivate::setup(const int srcWidth, const int srcHeight,
       
   130                                       const int dstWidth, const int dstHeight,
       
   131                                       bool hasAlphaChannel)
       
   132 {
       
   133     cols = srcWidth;
       
   134     rows = srcHeight;
       
   135     newcols = dstWidth;
       
   136     newrows = dstHeight;
       
   137     hasAlpha = hasAlphaChannel;
       
   138 }
       
   139 
       
   140 QImageSmoothScaler::~QImageSmoothScaler()
       
   141 {
       
   142     delete d;
       
   143 }
       
   144 
       
   145 inline QRgb *QImageSmoothScaler::scanLine(const int line, const QImage *src)
       
   146 {
       
   147     return (QRgb*)src->scanLine(line);
       
   148 }
       
   149 
       
   150 /*
       
   151   This function uses code based on pnmscale.c by Jef Poskanzer.
       
   152 
       
   153   pnmscale.c - read a portable anymap and scale it
       
   154 
       
   155   Copyright (C) 1989, 1991 by Jef Poskanzer.
       
   156 
       
   157   Permission to use, copy, modify, and distribute this software and its
       
   158   documentation for any purpose and without fee is hereby granted, provided
       
   159   that the above copyright notice appear in all copies and that both that
       
   160   copyright notice and this permission notice appear in supporting
       
   161   documentation.  This software is provided "as is" without express or
       
   162   implied warranty.
       
   163 */
       
   164 
       
   165 QImage QImageSmoothScaler::scale()
       
   166 {
       
   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;
       
   185 
       
   186     if (d->cols > 4096) {
       
   187         SCALE = 4096;
       
   188         HALFSCALE = 2048;
       
   189     } else {
       
   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;
       
   200     sxscale = (long)(xscale * SCALE);
       
   201     syscale = (long)(yscale * SCALE);
       
   202 
       
   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;
       
   211     } else {
       
   212         as = 0;
       
   213     }
       
   214     rs = new long[d->cols];
       
   215     gs = new long[d->cols];
       
   216     bs = new long[d->cols];
       
   217     rowsread = 0;
       
   218     fracrowleft = syscale;
       
   219     needtoreadrow = 1;
       
   220     for (col = 0; col < d->cols; ++col)
       
   221         rs[col] = gs[col] = bs[col] = HALFSCALE;
       
   222     fracrowtofill = SCALE;
       
   223 
       
   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;
       
   431 
       
   432     return dst;
       
   433 }
       
   434 
       
   435 class jpegSmoothScaler : public QImageSmoothScaler
       
   436 {
       
   437 public:
       
   438     jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect)
       
   439         : QImageSmoothScaler(clipRect.width(), clipRect.height(),
       
   440                              dstSize.width(), dstSize.height())
       
   441     {
       
   442         cinfo = info;
       
   443         clip = clipRect;
       
   444         imageCache = QImage(info->output_width, 1, QImage::Format_RGB32);
       
   445     }
       
   446 
       
   447 private:
       
   448     QRect   clip;
       
   449     QImage  imageCache;
       
   450     struct jpeg_decompress_struct *cinfo;
       
   451 
       
   452     QRgb *scanLine(const int line = 0, const QImage *src = 0)
       
   453     {
       
   454 	QRgb    *out;
       
   455 	uchar	*in;
       
   456 
       
   457 	Q_UNUSED(line);
       
   458 	Q_UNUSED(src);
       
   459 
       
   460         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().
       
   469 	jpeg_read_scanlines(cinfo, &data, 1);
       
   470         if (cinfo->output_scanline == cinfo->output_height)
       
   471             jpeg_finish_decompress(cinfo);
       
   472 
       
   473 	out = ((QRgb*)data) + clip.x();
       
   474 
       
   475 	//
       
   476 	// The smooth scale algorithm only works on 32-bit images;
       
   477 	// convert from (8|24) bits to 32.
       
   478 	//
       
   479 	if (cinfo->output_components == 1) {
       
   480 	    in = data + clip.right();
       
   481 	    for (int i = clip.width(); i--; ) {
       
   482 		out[i] = qRgb(*in, *in, *in);
       
   483 		in--;
       
   484 	    }
       
   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]);
       
   496 		in -= 3;
       
   497 	    }
       
   498 	}
       
   499 
       
   500 	return out;
       
   501     }
       
   502 
       
   503 };
       
   504 #endif
       
   505 
       
   506 struct my_error_mgr : public jpeg_error_mgr {
    78 struct my_error_mgr : public jpeg_error_mgr {
   507     jmp_buf setjmp_buffer;
    79     jmp_buf setjmp_buffer;
   508 };
    80 };
   509 
    81 
   510 #if defined(Q_C_CALLBACKS)
    82 #if defined(Q_C_CALLBACKS)
   529 
   101 
   530 struct my_jpeg_source_mgr : public jpeg_source_mgr {
   102 struct my_jpeg_source_mgr : public jpeg_source_mgr {
   531     // Nothing dynamic - cannot rely on destruction over longjump
   103     // Nothing dynamic - cannot rely on destruction over longjump
   532     QIODevice *device;
   104     QIODevice *device;
   533     JOCTET buffer[max_buf];
   105     JOCTET buffer[max_buf];
       
   106     const QBuffer *memDevice;
   534 
   107 
   535 public:
   108 public:
   536     my_jpeg_source_mgr(QIODevice *device);
   109     my_jpeg_source_mgr(QIODevice *device);
   537 };
   110 };
   538 
   111 
   544 {
   117 {
   545 }
   118 }
   546 
   119 
   547 static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
   120 static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
   548 {
   121 {
   549     int num_read;
       
   550     my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
   122     my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
       
   123     if (src->memDevice) {
       
   124         src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
       
   125         src->bytes_in_buffer = (size_t)(src->memDevice->data().size() - src->memDevice->pos());
       
   126         return true;
       
   127     }
   551     src->next_input_byte = src->buffer;
   128     src->next_input_byte = src->buffer;
   552     num_read = src->device->read((char*)src->buffer, max_buf);
   129     int num_read = src->device->read((char*)src->buffer, max_buf);
   553     if (num_read <= 0) {
   130     if (num_read <= 0) {
   554         // Insert a fake EOI marker - as per jpeglib recommendation
   131         // Insert a fake EOI marker - as per jpeglib recommendation
   555         src->buffer[0] = (JOCTET) 0xFF;
   132         src->buffer[0] = (JOCTET) 0xFF;
   556         src->buffer[1] = (JOCTET) JPEG_EOI;
   133         src->buffer[1] = (JOCTET) JPEG_EOI;
   557         src->bytes_in_buffer = 2;
   134         src->bytes_in_buffer = 2;
   574     /* Just a dumb implementation for now.  Could use fseek() except
   151     /* Just a dumb implementation for now.  Could use fseek() except
   575      * it doesn't work on pipes.  Not clear that being smart is worth
   152      * it doesn't work on pipes.  Not clear that being smart is worth
   576      * any trouble anyway --- large skips are infrequent.
   153      * any trouble anyway --- large skips are infrequent.
   577      */
   154      */
   578     if (num_bytes > 0) {
   155     if (num_bytes > 0) {
   579         while (num_bytes > (long) src->bytes_in_buffer) {
   156         while (num_bytes > (long) src->bytes_in_buffer) {  // Should not happen in case of memDevice
   580             num_bytes -= (long) src->bytes_in_buffer;
   157             num_bytes -= (long) src->bytes_in_buffer;
   581             (void) qt_fill_input_buffer(cinfo);
   158             (void) qt_fill_input_buffer(cinfo);
   582             /* note we assume that qt_fill_input_buffer will never return false,
   159             /* note we assume that qt_fill_input_buffer will never return false,
   583             * so suspension need not be handled.
   160             * so suspension need not be handled.
   584             */
   161             */
   590 
   167 
   591 static void qt_term_source(j_decompress_ptr cinfo)
   168 static void qt_term_source(j_decompress_ptr cinfo)
   592 {
   169 {
   593     my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
   170     my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
   594     if (!src->device->isSequential())
   171     if (!src->device->isSequential())
   595         src->device->seek(src->device->pos() - src->bytes_in_buffer);
   172     {
       
   173         // read() isn't used for memDevice, so seek past everything that was used
       
   174         if (src->memDevice)
       
   175             src->device->seek(src->device->pos() + (src->memDevice->data().size() - src->memDevice->pos() - src->bytes_in_buffer));
       
   176         else
       
   177             src->device->seek(src->device->pos() - src->bytes_in_buffer);
       
   178     }
   596 }
   179 }
   597 
   180 
   598 #if defined(Q_C_CALLBACKS)
   181 #if defined(Q_C_CALLBACKS)
   599 }
   182 }
   600 #endif
   183 #endif
   605     jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
   188     jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
   606     jpeg_source_mgr::skip_input_data = qt_skip_input_data;
   189     jpeg_source_mgr::skip_input_data = qt_skip_input_data;
   607     jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
   190     jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
   608     jpeg_source_mgr::term_source = qt_term_source;
   191     jpeg_source_mgr::term_source = qt_term_source;
   609     this->device = device;
   192     this->device = device;
       
   193     memDevice = qobject_cast<QBuffer *>(device);
   610     bytes_in_buffer = 0;
   194     bytes_in_buffer = 0;
   611     next_input_byte = buffer;
   195     next_input_byte = buffer;
   612 }
   196 }
   613 
   197 
   614 
   198 
   615 static bool read_jpeg_size(QIODevice *device, int &w, int &h)
   199 inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
   616 {
   200 {
   617     bool rt = false;
   201     (void) jpeg_calc_output_dimensions(cinfo);
   618     struct jpeg_decompress_struct cinfo;
   202 
   619 
   203     w = cinfo->output_width;
   620     struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device);
   204     h = cinfo->output_height;
   621     struct my_error_mgr jerr;
   205     return true;
   622 
       
   623     jpeg_create_decompress(&cinfo);
       
   624 
       
   625     cinfo.src = iod_src;
       
   626 
       
   627     cinfo.err = jpeg_std_error(&jerr);
       
   628     jerr.error_exit = my_error_exit;
       
   629 
       
   630     if (!setjmp(jerr.setjmp_buffer)) {
       
   631 #if defined(Q_OS_UNIXWARE)
       
   632         (void) jpeg_read_header(&cinfo, B_TRUE);
       
   633 #else
       
   634         (void) jpeg_read_header(&cinfo, true);
       
   635 #endif
       
   636         (void) jpeg_calc_output_dimensions(&cinfo);
       
   637 
       
   638         w = cinfo.output_width;
       
   639         h = cinfo.output_height;
       
   640         rt = true;
       
   641     }
       
   642     jpeg_destroy_decompress(&cinfo);
       
   643     delete iod_src;
       
   644     return rt;
       
   645 }
   206 }
   646 
   207 
   647 #define HIGH_QUALITY_THRESHOLD 50
   208 #define HIGH_QUALITY_THRESHOLD 50
   648 
   209 
   649 static bool read_jpeg_format(QIODevice *device, QImage::Format &format)
   210 inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
   650 {
   211 {
   651     bool result = false;
   212 
   652     struct jpeg_decompress_struct cinfo;
   213     bool result = true;
   653 
   214     switch (cinfo->output_components) {
   654     struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device);
   215     case 1:
   655     struct my_error_mgr jerr;
   216         format = QImage::Format_Indexed8;
   656 
   217         break;
   657     jpeg_create_decompress(&cinfo);
   218     case 3:
   658 
   219     case 4:
   659     cinfo.src = iod_src;
   220         format = QImage::Format_RGB32;
   660 
   221         break;
   661     cinfo.err = jpeg_std_error(&jerr);
   222     default:
   662     jerr.error_exit = my_error_exit;
   223         result = false;
   663 
   224         break;
   664     if (!setjmp(jerr.setjmp_buffer)) {
   225     }
   665 #if defined(Q_OS_UNIXWARE)
   226     cinfo->output_scanline = cinfo->output_height;
   666         (void) jpeg_read_header(&cinfo, B_TRUE);
       
   667 #else
       
   668         (void) jpeg_read_header(&cinfo, true);
       
   669 #endif
       
   670         // This does not allocate memory for the whole image
       
   671         // or such, so we are safe.
       
   672         (void) jpeg_start_decompress(&cinfo);
       
   673         result = true;
       
   674         switch (cinfo.output_components) {
       
   675         case 1:
       
   676             format = QImage::Format_Indexed8;
       
   677             break;
       
   678         case 3:
       
   679         case 4:
       
   680             format = QImage::Format_RGB32;
       
   681             break;
       
   682         default:
       
   683             result = false;
       
   684             break;
       
   685         }
       
   686         cinfo.output_scanline = cinfo.output_height;
       
   687         (void) jpeg_finish_decompress(&cinfo);
       
   688     }
       
   689     jpeg_destroy_decompress(&cinfo);
       
   690     delete iod_src;
       
   691     return result;
   227     return result;
   692 }
   228 }
   693 
   229 
   694 static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
   230 static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
   695                              const QSize& size)
   231                              const QSize& size)
   718     }
   254     }
   719 
   255 
   720     return !dest->isNull();
   256     return !dest->isNull();
   721 }
   257 }
   722 
   258 
   723 static bool read_jpeg_image(QIODevice *device, QImage *outImage,
   259 static bool read_jpeg_image(QImage *outImage,
   724                             QSize scaledSize, QRect scaledClipRect,
   260                             QSize scaledSize, QRect scaledClipRect,
   725                             QRect clipRect, int inQuality )
   261                             QRect clipRect, int inQuality, j_decompress_ptr info, struct my_error_mgr* err  )
   726 {
   262 {
   727     struct jpeg_decompress_struct cinfo;
   263     if (!setjmp(err->setjmp_buffer)) {
   728 
       
   729     struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device);
       
   730     struct my_error_mgr jerr;
       
   731 
       
   732     jpeg_create_decompress(&cinfo);
       
   733 
       
   734     cinfo.src = iod_src;
       
   735 
       
   736     cinfo.err = jpeg_std_error(&jerr);
       
   737     jerr.error_exit = my_error_exit;
       
   738 
       
   739     if (!setjmp(jerr.setjmp_buffer)) {
       
   740 #if defined(Q_OS_UNIXWARE)
       
   741         (void) jpeg_read_header(&cinfo, B_TRUE);
       
   742 #else
       
   743         (void) jpeg_read_header(&cinfo, true);
       
   744 #endif
       
   745 
       
   746         // -1 means default quality.
   264         // -1 means default quality.
   747         int quality = inQuality;
   265         int quality = inQuality;
   748         if (quality < 0)
   266         if (quality < 0)
   749             quality = 75;
   267             quality = 75;
   750 
   268 
   762                 clipRect = scaledClipRect.intersected(clipRect);
   280                 clipRect = scaledClipRect.intersected(clipRect);
   763                 scaledClipRect = QRect();
   281                 scaledClipRect = QRect();
   764             } else if (clipRect.isEmpty()) {
   282             } else if (clipRect.isEmpty()) {
   765                 // No clipping, but scaling: if we can map back to an
   283                 // No clipping, but scaling: if we can map back to an
   766                 // integer pixel boundary, then clip before scaling.
   284                 // integer pixel boundary, then clip before scaling.
   767                 if ((cinfo.image_width % scaledSize.width()) == 0 &&
   285                 if ((info->image_width % scaledSize.width()) == 0 &&
   768                         (cinfo.image_height % scaledSize.height()) == 0) {
   286                         (info->image_height % scaledSize.height()) == 0) {
   769                     int x = scaledClipRect.x() * cinfo.image_width /
   287                     int x = scaledClipRect.x() * info->image_width /
   770                             scaledSize.width();
   288                             scaledSize.width();
   771                     int y = scaledClipRect.y() * cinfo.image_height /
   289                     int y = scaledClipRect.y() * info->image_height /
   772                             scaledSize.height();
   290                             scaledSize.height();
   773                     int width = (scaledClipRect.right() + 1) *
   291                     int width = (scaledClipRect.right() + 1) *
   774                                 cinfo.image_width / scaledSize.width() - x;
   292                                 info->image_width / scaledSize.width() - x;
   775                     int height = (scaledClipRect.bottom() + 1) *
   293                     int height = (scaledClipRect.bottom() + 1) *
   776                                  cinfo.image_height / scaledSize.height() - y;
   294                                  info->image_height / scaledSize.height() - y;
   777                     clipRect = QRect(x, y, width, height);
   295                     clipRect = QRect(x, y, width, height);
   778                     scaledSize = scaledClipRect.size();
   296                     scaledSize = scaledClipRect.size();
   779                     scaledClipRect = QRect();
   297                     scaledClipRect = QRect();
   780                 }
   298                 }
   781             } else {
   299             } else {
   785         }
   303         }
   786 
   304 
   787         // Determine the scale factor to pass to libjpeg for quick downscaling.
   305         // Determine the scale factor to pass to libjpeg for quick downscaling.
   788         if (!scaledSize.isEmpty()) {
   306         if (!scaledSize.isEmpty()) {
   789             if (clipRect.isEmpty()) {
   307             if (clipRect.isEmpty()) {
   790                 cinfo.scale_denom =
   308                 info->scale_denom =
   791                     qMin(cinfo.image_width / scaledSize.width(),
   309                     qMin(info->image_width / scaledSize.width(),
   792                          cinfo.image_height / scaledSize.height());
   310                          info->image_height / scaledSize.height());
   793             } else {
   311             } else {
   794                 cinfo.scale_denom =
   312                 info->scale_denom =
   795                     qMin(clipRect.width() / scaledSize.width(),
   313                     qMin(clipRect.width() / scaledSize.width(),
   796                          clipRect.height() / scaledSize.height());
   314                          clipRect.height() / scaledSize.height());
   797             }
   315             }
   798             if (cinfo.scale_denom < 2) {
   316             if (info->scale_denom < 2) {
   799                 cinfo.scale_denom = 1;
   317                 info->scale_denom = 1;
   800             } else if (cinfo.scale_denom < 4) {
   318             } else if (info->scale_denom < 4) {
   801                 cinfo.scale_denom = 2;
   319                 info->scale_denom = 2;
   802             } else if (cinfo.scale_denom < 8) {
   320             } else if (info->scale_denom < 8) {
   803                 cinfo.scale_denom = 4;
   321                 info->scale_denom = 4;
   804             } else {
   322             } else {
   805                 cinfo.scale_denom = 8;
   323                 info->scale_denom = 8;
   806             }
   324             }
   807             cinfo.scale_num = 1;
   325             info->scale_num = 1;
   808             if (!clipRect.isEmpty()) {
   326             if (!clipRect.isEmpty()) {
   809                 // Correct the scale factor so that we clip accurately.
   327                 // Correct the scale factor so that we clip accurately.
   810                 // It is recommended that the clip rectangle be aligned
   328                 // It is recommended that the clip rectangle be aligned
   811                 // on an 8-pixel boundary for best performance.
   329                 // on an 8-pixel boundary for best performance.
   812                 while (cinfo.scale_denom > 1 &&
   330                 while (info->scale_denom > 1 &&
   813                        ((clipRect.x() % cinfo.scale_denom) != 0 ||
   331                        ((clipRect.x() % info->scale_denom) != 0 ||
   814                         (clipRect.y() % cinfo.scale_denom) != 0 ||
   332                         (clipRect.y() % info->scale_denom) != 0 ||
   815                         (clipRect.width() % cinfo.scale_denom) != 0 ||
   333                         (clipRect.width() % info->scale_denom) != 0 ||
   816                         (clipRect.height() % cinfo.scale_denom) != 0)) {
   334                         (clipRect.height() % info->scale_denom) != 0)) {
   817                     cinfo.scale_denom /= 2;
   335                     info->scale_denom /= 2;
   818                 }
   336                 }
   819             }
   337             }
   820         }
   338         }
   821 
   339 
   822         // If high quality not required, use fast decompression
   340         // If high quality not required, use fast decompression
   823         if( quality < HIGH_QUALITY_THRESHOLD ) {
   341         if( quality < HIGH_QUALITY_THRESHOLD ) {
   824             cinfo.dct_method = JDCT_IFAST;
   342             info->dct_method = JDCT_IFAST;
   825             cinfo.do_fancy_upsampling = FALSE;
   343             info->do_fancy_upsampling = FALSE;
   826         }
   344         }
   827 
   345 
   828         (void) jpeg_calc_output_dimensions(&cinfo);
   346         (void) jpeg_calc_output_dimensions(info);
   829 
   347 
   830         // Determine the clip region to extract.
   348         // Determine the clip region to extract.
   831         QRect imageRect(0, 0, cinfo.output_width, cinfo.output_height);
   349         QRect imageRect(0, 0, info->output_width, info->output_height);
   832         QRect clip;
   350         QRect clip;
   833         if (clipRect.isEmpty()) {
   351         if (clipRect.isEmpty()) {
   834             clip = imageRect;
   352             clip = imageRect;
   835         } else if (cinfo.scale_denom == 1) {
   353         } else if (info->scale_denom == info->scale_num) {
   836             clip = clipRect.intersected(imageRect);
   354             clip = clipRect.intersected(imageRect);
   837         } else {
   355         } else {
   838             // The scale factor was corrected above to ensure that
   356             // The scale factor was corrected above to ensure that
   839             // we don't miss pixels when we scale the clip rectangle.
   357             // we don't miss pixels when we scale the clip rectangle.
   840             clip = QRect(clipRect.x() / int(cinfo.scale_denom),
   358             clip = QRect(clipRect.x() / int(info->scale_denom),
   841                          clipRect.y() / int(cinfo.scale_denom),
   359                          clipRect.y() / int(info->scale_denom),
   842                          clipRect.width() / int(cinfo.scale_denom),
   360                          clipRect.width() / int(info->scale_denom),
   843                          clipRect.height() / int(cinfo.scale_denom));
   361                          clipRect.height() / int(info->scale_denom));
   844             clip = clip.intersected(imageRect);
   362             clip = clip.intersected(imageRect);
   845         }
   363         }
   846 
   364 
   847 #ifndef QT_NO_IMAGE_SMOOTHSCALE
   365         // Allocate memory for the clipped QImage.
   848         if (scaledSize.isValid() && scaledSize != clip.size()
   366         if (!ensureValidImage(outImage, info, clip.size()))
   849             && quality >= HIGH_QUALITY_THRESHOLD) {
   367             longjmp(err->setjmp_buffer, 1);
   850 
   368 
   851             (void) jpeg_start_decompress(&cinfo);
   369         // Avoid memcpy() overhead if grayscale with no clipping.
   852 
   370         bool quickGray = (info->output_components == 1 &&
   853             jpegSmoothScaler scaler(&cinfo, scaledSize, clip);
   371                           clip == imageRect);
   854             *outImage = scaler.scale();
   372         if (!quickGray) {
   855         } else
   373             // Ask the jpeg library to allocate a temporary row.
   856 #endif
   374             // The library will automatically delete it for us later.
   857         {
   375             // The libjpeg docs say we should do this before calling
   858             // Allocate memory for the clipped QImage.
   376             // jpeg_start_decompress().  We can't use "new" here
   859             if (!ensureValidImage(outImage, &cinfo, clip.size()))
   377             // because we are inside the setjmp() block and an error
   860                 longjmp(jerr.setjmp_buffer, 1);
   378             // in the jpeg input stream would cause a memory leak.
   861 
   379             JSAMPARRAY rows = (info->mem->alloc_sarray)
   862             // Avoid memcpy() overhead if grayscale with no clipping.
   380                               ((j_common_ptr)info, JPOOL_IMAGE,
   863             bool quickGray = (cinfo.output_components == 1 &&
   381                                info->output_width * info->output_components, 1);
   864                               clip == imageRect);
   382 
   865             if (!quickGray) {
   383             (void) jpeg_start_decompress(info);
   866                 // Ask the jpeg library to allocate a temporary row.
   384 
   867                 // The library will automatically delete it for us later.
   385             while (info->output_scanline < info->output_height) {
   868                 // The libjpeg docs say we should do this before calling
   386                 int y = int(info->output_scanline) - clip.y();
   869                 // jpeg_start_decompress().  We can't use "new" here
   387                 if (y >= clip.height())
   870                 // because we are inside the setjmp() block and an error
   388                     break;      // We've read the entire clip region, so abort.
   871                 // in the jpeg input stream would cause a memory leak.
   389 
   872                 JSAMPARRAY rows = (cinfo.mem->alloc_sarray)
   390                 (void) jpeg_read_scanlines(info, rows, 1);
   873                     ((j_common_ptr)&cinfo, JPOOL_IMAGE,
   391 
   874                      cinfo.output_width * cinfo.output_components, 1);
   392                 if (y < 0)
   875 
   393                     continue;   // Haven't reached the starting line yet.
   876                 (void) jpeg_start_decompress(&cinfo);
   394 
   877 
   395                 if (info->output_components == 3) {
   878                 while (cinfo.output_scanline < cinfo.output_height) {
   396                     // Expand 24->32 bpp.
   879                     int y = int(cinfo.output_scanline) - clip.y();
   397                     uchar *in = rows[0] + clip.x() * 3;
   880                     if (y >= clip.height())
   398                     QRgb *out = (QRgb*)outImage->scanLine(y);
   881                         break;      // We've read the entire clip region, so abort.
   399                     for (int i = 0; i < clip.width(); ++i) {
   882 
   400                         *out++ = qRgb(in[0], in[1], in[2]);
   883                     (void) jpeg_read_scanlines(&cinfo, rows, 1);
   401                         in += 3;
   884 
       
   885                     if (y < 0)
       
   886                         continue;   // Haven't reached the starting line yet.
       
   887 
       
   888                     if (cinfo.output_components == 3) {
       
   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]);
       
   894                             in += 3;
       
   895                         }
       
   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;
       
   905                         }
       
   906                     } else if (cinfo.output_components == 1) {
       
   907                         // Grayscale.
       
   908                         memcpy(outImage->scanLine(y),
       
   909                                rows[0] + clip.x(), clip.width());
       
   910                     }
   402                     }
   911                 }
   403                 } else if (info->out_color_space == JCS_CMYK) {
   912             } else {
   404                     // Convert CMYK->RGB.
   913                 // Load unclipped grayscale data directly into the QImage.
   405                     uchar *in = rows[0] + clip.x() * 4;
   914                 (void) jpeg_start_decompress(&cinfo);
   406                     QRgb *out = (QRgb*)outImage->scanLine(y);
   915                 while (cinfo.output_scanline < cinfo.output_height) {
   407                     for (int i = 0; i < clip.width(); ++i) {
   916                     uchar *row = outImage->scanLine(cinfo.output_scanline);
   408                         int k = in[3];
   917                     (void) jpeg_read_scanlines(&cinfo, &row, 1);
   409                         *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
       
   410                                       k * in[2] / 255);
       
   411                         in += 4;
       
   412                     }
       
   413                 } else if (info->output_components == 1) {
       
   414                     // Grayscale.
       
   415                     memcpy(outImage->scanLine(y),
       
   416                            rows[0] + clip.x(), clip.width());
   918                 }
   417                 }
   919             }
   418             }
   920 
   419         } else {
   921             if (cinfo.output_scanline == cinfo.output_height)
   420             // Load unclipped grayscale data directly into the QImage.
   922                 (void) jpeg_finish_decompress(&cinfo);
   421             (void) jpeg_start_decompress(info);
   923 
   422             while (info->output_scanline < info->output_height) {
   924             if (cinfo.density_unit == 1) {
   423                 uchar *row = outImage->scanLine(info->output_scanline);
   925                 outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54));
   424                 (void) jpeg_read_scanlines(info, &row, 1);
   926                 outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54));
       
   927             } else if (cinfo.density_unit == 2) {
       
   928                 outImage->setDotsPerMeterX(int(100. * cinfo.X_density));
       
   929                 outImage->setDotsPerMeterY(int(100. * cinfo.Y_density));
       
   930             }
   425             }
   931 
   426         }
   932             if (scaledSize.isValid() && scaledSize != clip.size())
   427 
   933                 *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation);
   428         if (info->output_scanline == info->output_height)
   934         }
   429             (void) jpeg_finish_decompress(info);
   935     }
   430 
   936 
   431         if (info->density_unit == 1) {
   937     jpeg_destroy_decompress(&cinfo);
   432             outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
   938     delete iod_src;
   433             outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
   939     if (!scaledClipRect.isEmpty())
   434         } else if (info->density_unit == 2) {
   940         *outImage = outImage->copy(scaledClipRect);
   435             outImage->setDotsPerMeterX(int(100. * info->X_density));
   941     return !outImage->isNull();
   436             outImage->setDotsPerMeterY(int(100. * info->Y_density));
   942 }
   437         }
   943 
   438 
       
   439         if (scaledSize.isValid() && scaledSize != clip.size()) {
       
   440             *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
       
   441         }
       
   442 
       
   443         if (!scaledClipRect.isEmpty())
       
   444             *outImage = outImage->copy(scaledClipRect);
       
   445         return !outImage->isNull();
       
   446     }
       
   447     else
       
   448         return false;
       
   449 }
   944 
   450 
   945 struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
   451 struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
   946     // Nothing dynamic - cannot rely on destruction over longjump
   452     // Nothing dynamic - cannot rely on destruction over longjump
   947     QIODevice *device;
   453     QIODevice *device;
   948     JOCTET buffer[max_buf];
   454     JOCTET buffer[max_buf];
  1000     this->device = device;
   506     this->device = device;
  1001     next_output_byte = buffer;
   507     next_output_byte = buffer;
  1002     free_in_buffer = max_buf;
   508     free_in_buffer = max_buf;
  1003 }
   509 }
  1004 
   510 
       
   511 static bool can_write_format(QImage::Format fmt)
       
   512 {
       
   513     switch (fmt) {
       
   514     case QImage::Format_Mono:
       
   515     case QImage::Format_MonoLSB:
       
   516     case QImage::Format_Indexed8:
       
   517     case QImage::Format_RGB888:
       
   518     case QImage::Format_RGB32:
       
   519     case QImage::Format_ARGB32:
       
   520     case QImage::Format_ARGB32_Premultiplied:
       
   521         return true;
       
   522         break;
       
   523     default:
       
   524         break;
       
   525     }
       
   526     return false;
       
   527 }
  1005 
   528 
  1006 static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality)
   529 static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality)
  1007 {
   530 {
  1008     bool success = false;
   531     bool success = false;
  1009     const QImage image = sourceImage;
   532     const QImage image = can_write_format(sourceImage.format()) ?
       
   533                          sourceImage : sourceImage.convertToFormat(QImage::Format_RGB888);
  1010     const QVector<QRgb> cmap = image.colorTable();
   534     const QVector<QRgb> cmap = image.colorTable();
  1011 
   535 
  1012     struct jpeg_compress_struct cinfo;
   536     struct jpeg_compress_struct cinfo;
  1013     JSAMPROW row_pointer[1];
   537     JSAMPROW row_pointer[1];
  1014     row_pointer[0] = 0;
   538     row_pointer[0] = 0;
  1165     delete iod_dest;
   689     delete iod_dest;
  1166     delete [] row_pointer[0];
   690     delete [] row_pointer[0];
  1167     return success;
   691     return success;
  1168 }
   692 }
  1169 
   693 
       
   694 class QJpegHandlerPrivate
       
   695 {
       
   696 public:
       
   697     enum State {
       
   698         Ready,
       
   699         ReadHeader,
       
   700         Error
       
   701     };
       
   702 
       
   703     QJpegHandlerPrivate(QJpegHandler *qq)
       
   704         : quality(75), iod_src(0), state(Ready), q(qq)
       
   705     {}
       
   706 
       
   707     ~QJpegHandlerPrivate()
       
   708     {
       
   709         if(iod_src)
       
   710         {
       
   711             jpeg_destroy_decompress(&info);
       
   712             delete iod_src;
       
   713             iod_src = 0;
       
   714         }
       
   715     }
       
   716 
       
   717     bool readJpegHeader(QIODevice*);
       
   718     bool read(QImage *image);
       
   719 
       
   720     int quality;
       
   721     QVariant size;
       
   722     QImage::Format format;
       
   723     QSize scaledSize;
       
   724     QRect scaledClipRect;
       
   725     QRect clipRect;
       
   726     struct jpeg_decompress_struct info;
       
   727     struct my_jpeg_source_mgr * iod_src;
       
   728     struct my_error_mgr err;
       
   729 
       
   730     State state;
       
   731 
       
   732     QJpegHandler *q;
       
   733 };
       
   734 
       
   735 /*!
       
   736     \internal
       
   737 */
       
   738 bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
       
   739 {
       
   740     if(state == Ready)
       
   741     {
       
   742         state = Error;
       
   743         iod_src = new my_jpeg_source_mgr(device);
       
   744 
       
   745         jpeg_create_decompress(&info);
       
   746         info.src = iod_src;
       
   747         info.err = jpeg_std_error(&err);
       
   748         err.error_exit = my_error_exit;
       
   749 
       
   750         if (!setjmp(err.setjmp_buffer)) {
       
   751     #if defined(Q_OS_UNIXWARE)
       
   752             (void) jpeg_read_header(&info, B_TRUE);
       
   753     #else
       
   754             (void) jpeg_read_header(&info, true);
       
   755     #endif
       
   756 
       
   757             int width = 0;
       
   758             int height = 0;
       
   759             read_jpeg_size(width, height, &info);
       
   760             size = QSize(width, height);
       
   761 
       
   762             format = QImage::Format_Invalid;
       
   763             read_jpeg_format(format, &info);
       
   764             state = ReadHeader;
       
   765             return true;
       
   766         }
       
   767         else
       
   768         {
       
   769             return false;
       
   770         }
       
   771     }
       
   772     else if(state == Error)
       
   773         return false;
       
   774     return true;
       
   775 }
       
   776 
       
   777 bool QJpegHandlerPrivate::read(QImage *image)
       
   778 {
       
   779     if(state == Ready)
       
   780         readJpegHeader(q->device());
       
   781 
       
   782     if(state == ReadHeader)
       
   783     {
       
   784         bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality,  &info, &err);
       
   785         state = success ? Ready : Error;
       
   786         return success;
       
   787     }
       
   788 
       
   789     return false;
       
   790 
       
   791 }
       
   792 
  1170 QJpegHandler::QJpegHandler()
   793 QJpegHandler::QJpegHandler()
  1171 {
   794     : d(new QJpegHandlerPrivate(this))
  1172     quality = 75;
   795 {
       
   796 }
       
   797 
       
   798 QJpegHandler::~QJpegHandler()
       
   799 {
       
   800     delete d;
  1173 }
   801 }
  1174 
   802 
  1175 bool QJpegHandler::canRead() const
   803 bool QJpegHandler::canRead() const
  1176 {
   804 {
  1177     if (canRead(device())) {
   805     if(d->state == QJpegHandlerPrivate::Ready) {
       
   806         if (!canRead(device()))
       
   807             return false;
  1178         setFormat("jpeg");
   808         setFormat("jpeg");
  1179         return true;
   809         return true;
  1180     }
   810     }
  1181     return false;
   811     return d->state != QJpegHandlerPrivate::Error;
  1182 }
   812 }
  1183 
   813 
  1184 bool QJpegHandler::canRead(QIODevice *device)
   814 bool QJpegHandler::canRead(QIODevice *device)
  1185 {
   815 {
  1186     if (!device) {
   816     if (!device) {
  1189     }
   819     }
  1190 
   820 
  1191     char buffer[2];
   821     char buffer[2];
  1192     if (device->peek(buffer, 2) != 2)
   822     if (device->peek(buffer, 2) != 2)
  1193         return false;
   823         return false;
  1194 
       
  1195     return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
   824     return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
  1196 }
   825 }
  1197 
   826 
  1198 bool QJpegHandler::read(QImage *image)
   827 bool QJpegHandler::read(QImage *image)
  1199 {
   828 {
  1200     if (!canRead())
   829     if (!canRead())
  1201         return false;
   830         return false;
  1202     return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality);
   831     return d->read(image);
  1203 }
   832 }
  1204 
   833 
  1205 bool QJpegHandler::write(const QImage &image)
   834 bool QJpegHandler::write(const QImage &image)
  1206 {
   835 {
  1207     return write_jpeg_image(image, device(), quality);
   836     return write_jpeg_image(image, device(), d->quality);
  1208 }
   837 }
  1209 
   838 
  1210 bool QJpegHandler::supportsOption(ImageOption option) const
   839 bool QJpegHandler::supportsOption(ImageOption option) const
  1211 {
   840 {
  1212     return option == Quality
   841     return option == Quality
  1217         || option == ImageFormat;
   846         || option == ImageFormat;
  1218 }
   847 }
  1219 
   848 
  1220 QVariant QJpegHandler::option(ImageOption option) const
   849 QVariant QJpegHandler::option(ImageOption option) const
  1221 {
   850 {
  1222     if (option == Quality) {
   851     switch(option) {
  1223         return quality;
   852     case Quality:
  1224     } else if  (option == ScaledSize) {
   853         return d->quality;
  1225         return scaledSize;
   854     case ScaledSize:
  1226     } else if  (option == ScaledClipRect) {
   855         return d->scaledSize;
  1227         return scaledClipRect;
   856     case ScaledClipRect:
  1228     } else if  (option == ClipRect) {
   857         return d->scaledClipRect;
  1229         return clipRect;
   858     case ClipRect:
  1230     } else if (option == Size) {
   859         return d->clipRect;
  1231         if (canRead() && !device()->isSequential()) {
   860     case Size:
  1232             qint64 pos = device()->pos();
   861         d->readJpegHeader(device());
  1233             int width = 0;
   862         return d->size;
  1234             int height = 0;
   863     case ImageFormat:
  1235             read_jpeg_size(device(), width, height);
   864         d->readJpegHeader(device());
  1236             device()->seek(pos);
   865         return d->format;
  1237             return QSize(width, height);
   866     default:
  1238         }
   867         return QVariant();
  1239     } else if (option == ImageFormat) {
   868     }
  1240         if (canRead() && !device()->isSequential()) {
       
  1241             qint64 pos = device()->pos();
       
  1242             QImage::Format format = QImage::Format_Invalid;
       
  1243             read_jpeg_format(device(), format);
       
  1244             device()->seek(pos);
       
  1245             return format;
       
  1246         }
       
  1247         return QImage::Format_Invalid;
       
  1248     }
       
  1249     return QVariant();
       
  1250 }
   869 }
  1251 
   870 
  1252 void QJpegHandler::setOption(ImageOption option, const QVariant &value)
   871 void QJpegHandler::setOption(ImageOption option, const QVariant &value)
  1253 {
   872 {
  1254     if (option == Quality)
   873     switch(option) {
  1255         quality = value.toInt();
   874     case Quality:
  1256     else if ( option == ScaledSize )
   875         d->quality = value.toInt();
  1257         scaledSize = value.toSize();
   876         break;
  1258     else if ( option == ScaledClipRect )
   877     case ScaledSize:
  1259         scaledClipRect = value.toRect();
   878         d->scaledSize = value.toSize();
  1260     else if ( option == ClipRect )
   879         break;
  1261         clipRect = value.toRect();
   880     case ScaledClipRect:
       
   881         d->scaledClipRect = value.toRect();
       
   882         break;
       
   883     case ClipRect:
       
   884         d->clipRect = value.toRect();
       
   885         break;
       
   886     default:
       
   887         break;
       
   888     }
  1262 }
   889 }
  1263 
   890 
  1264 QByteArray QJpegHandler::name() const
   891 QByteArray QJpegHandler::name() const
  1265 {
   892 {
  1266     return "jpeg";
   893     return "jpeg";
  1267 }
   894 }
  1268 
   895 
       
   896 
       
   897 
       
   898 
  1269 QT_END_NAMESPACE
   899 QT_END_NAMESPACE