Changeset 561 for trunk/src/plugins/imageformats/jpeg
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
-
. (modified) (1 prop)
-
src/plugins/imageformats/jpeg/jpeg.pro (modified) (2 diffs)
-
src/plugins/imageformats/jpeg/main.cpp (modified) (3 diffs)
-
src/plugins/imageformats/jpeg/qjpeghandler.cpp (modified) (25 diffs)
-
src/plugins/imageformats/jpeg/qjpeghandler.h (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/plugins/imageformats/jpeg/jpeg.pro
r2 r561 12 12 contains(CE_ARCH,x86):CONFIG -= stl exceptions 13 13 contains(CE_ARCH,x86):CONFIG += exceptions_off 14 } 15 16 symbian: { 17 #Disable warnings in 3rdparty code due to unused arguments 18 QMAKE_CXXFLAGS.CW += -W nounusedarg 19 TARGET.UID3=0x2001E61B 14 20 } 15 21 … … 72 78 target.path += $$[QT_INSTALL_PLUGINS]/imageformats 73 79 INSTALLS += target 80 -
trunk/src/plugins/imageformats/jpeg/main.cpp
r2 r561 2 2 ** 3 3 ** 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) 5 6 ** 6 7 ** This file is part of the plugins of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 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. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** 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. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/plugins/imageformats/jpeg/qjpeghandler.cpp
r2 r561 2 2 ** 3 3 ** 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) 5 6 ** 6 7 ** This file is part of the plugins of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 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. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** 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. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 85 85 QImageSmoothScaler(const int w, const int h, const QImage &src); 86 86 QImageSmoothScaler(const int srcWidth, const int srcHeight, 87 const char *parameters);87 const int dstWidth, const int dstHeight); 88 88 89 89 virtual ~QImageSmoothScaler(void); 90 90 91 91 QImage scale(); 92 93 protected:94 int scaledWidth(void) const;95 92 96 93 private: … … 124 121 125 122 QImageSmoothScaler::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 { 136 125 d = new QImageSmoothScalerPrivate; 137 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400138 sscanf_s(parameters, "Scale( %i, %i, %1023s )", &dstWidth, &dstHeight, sModeStr, sizeof(sModeStr));139 #else140 sscanf(parameters, "Scale( %i, %i, %s )", &dstWidth, &dstHeight, sModeStr);141 #endif142 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 153 126 d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0); 154 127 } … … 163 136 newrows = dstHeight; 164 137 hasAlpha = hasAlphaChannel; 165 }166 167 int QImageSmoothScaler::scaledWidth() const168 {169 return d->cols;170 138 } 171 139 … … 197 165 QImage QImageSmoothScaler::scale() 198 166 { 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; 217 185 218 186 if (d->cols > 4096) { 219 SCALE = 4096;220 HALFSCALE = 2048;187 SCALE = 4096; 188 HALFSCALE = 2048; 221 189 } 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; 233 200 sxscale = (long)(xscale * SCALE); 234 201 syscale = (long)(yscale * SCALE); 235 202 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; 243 211 } else { 244 as = 0;212 as = 0; 245 213 } 246 214 rs = new long[d->cols]; … … 250 218 fracrowleft = syscale; 251 219 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; 254 222 fracrowtofill = SCALE; 255 223 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; 451 431 452 432 return dst; … … 456 436 { 457 437 public: 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()) 460 441 { 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); 466 445 } 467 446 468 447 private: 469 int cols24Bit;448 QRect clip; 470 449 QImage imageCache; 471 int cacheHeight;472 450 struct jpeg_decompress_struct *cinfo; 473 451 … … 481 459 482 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(). 483 469 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(); 485 474 486 475 // … … 489 478 // 490 479 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); 493 483 in--; 494 out[i] = qRgb(*in, *in, *in);495 484 } 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]); 499 496 in -= 3; 500 out[i] = qRgb(in[0], in[1], in[2]);501 497 } 502 498 } … … 616 612 } 617 613 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 else628 reqW = t1 / imgH;629 }630 614 631 615 static bool read_jpeg_size(QIODevice *device, int &w, int &h) … … 709 693 710 694 static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, 711 bool dummy = false)695 const QSize& size) 712 696 { 713 697 QImage::Format format; … … 724 708 } 725 709 726 const QSize size(info->output_width, info->output_height);727 710 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); 733 712 734 713 if (format == QImage::Format_Indexed8) { 735 dest->set NumColors(256);714 dest->setColorCount(256); 736 715 for (int i = 0; i < 256; i++) 737 716 dest->setColor(i, qRgb(i,i,i)); … … 743 722 744 723 static bool read_jpeg_image(QIODevice *device, QImage *outImage, 745 const QByteArray ¶meters, 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 { 752 727 struct jpeg_decompress_struct cinfo; 753 728 … … 774 749 quality = 75; 775 750 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 } 787 798 if (cinfo.scale_denom < 2) { 788 799 cinfo.scale_denom = 1; … … 795 806 } 796 807 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 } 800 821 801 822 // If high quality not required, use fast decompression … … 805 826 } 806 827 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())) 812 860 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 858 878 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 861 888 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]); 873 894 in += 3; 874 895 } 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; 882 905 } 906 } else if (cinfo.output_components == 1) { 907 // Grayscale. 908 memcpy(outImage->scanLine(y), 909 rows[0] + clip.x(), clip.width()); 883 910 } 884 911 } 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) 885 922 (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 932 924 if (cinfo.density_unit == 1) { 933 925 outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); … … 937 929 outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); 938 930 } 931 932 if (scaledSize.isValid() && scaledSize != clip.size()) 933 *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation); 939 934 } 940 935 } … … 942 937 jpeg_destroy_decompress(&cinfo); 943 938 delete iod_src; 939 if (!scaledClipRect.isEmpty()) 940 *outImage = outImage->copy(scaledClipRect); 944 941 return !outImage->isNull(); 945 942 } … … 1041 1038 case QImage::Format_Indexed8: 1042 1039 gray = true; 1043 for (int i = image. numColors(); gray && i--;) {1040 for (int i = image.colorCount(); gray && i--;) { 1044 1041 gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && 1045 1042 qRed(cmap[i]) == qBlue(cmap[i])); … … 1199 1196 if (!canRead()) 1200 1197 return false; 1201 return read_jpeg_image(device(), image, parameters, scaledSize, quality);1198 return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality); 1202 1199 } 1203 1200 … … 1210 1207 { 1211 1208 return option == Quality 1212 #ifndef QT_NO_IMAGE_SMOOTHSCALE1213 1209 || option == ScaledSize 1214 #endif 1210 || option == ScaledClipRect 1211 || option == ClipRect 1215 1212 || option == Size 1216 1213 || option == ImageFormat; … … 1221 1218 if (option == Quality) { 1222 1219 return quality; 1223 #ifndef QT_NO_IMAGE_SMOOTHSCALE1224 1220 } else if (option == ScaledSize) { 1225 1221 return scaledSize; 1226 #endif 1222 } else if (option == ScaledClipRect) { 1223 return scaledClipRect; 1224 } else if (option == ClipRect) { 1225 return clipRect; 1227 1226 } else if (option == Size) { 1228 1227 if (canRead() && !device()->isSequential()) { … … 1251 1250 if (option == Quality) 1252 1251 quality = value.toInt(); 1253 #ifndef QT_NO_IMAGE_SMOOTHSCALE1254 1252 else if ( option == ScaledSize ) 1255 1253 scaledSize = value.toSize(); 1256 #endif 1254 else if ( option == ScaledClipRect ) 1255 scaledClipRect = value.toRect(); 1256 else if ( option == ClipRect ) 1257 clipRect = value.toRect(); 1257 1258 } 1258 1259 -
trunk/src/plugins/imageformats/jpeg/qjpeghandler.h
r2 r561 2 2 ** 3 3 ** 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) 5 6 ** 6 7 ** This file is part of the plugins of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 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. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** 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. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 #include <QtGui/qimageiohandler.h> 46 46 #include <QtCore/QSize> 47 #include <QtCore/QRect> 47 48 48 49 QT_BEGIN_NAMESPACE … … 67 68 private: 68 69 int quality; 69 QByteArray parameters;70 70 QSize scaledSize; 71 QRect scaledClipRect; 72 QRect clipRect; 71 73 }; 72 74
Note:
See TracChangeset
for help on using the changeset viewer.
