Changeset 561 for trunk/src/plugins/imageformats/jpeg
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
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 200 long 201 QRgb 202 QRgb 203 QRgb 204 QRgb 205 int 206 int 207 uchar 208 qreal 209 long 210 long 211 long 212 long 213 long 214 long 215 int 216 QImage 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 220 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 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 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.