194 implied warranty. |
194 implied warranty. |
195 */ |
195 */ |
196 |
196 |
197 QImage QImageSmoothScaler::scale() |
197 QImage QImageSmoothScaler::scale() |
198 { |
198 { |
199 long SCALE; |
199 long SCALE; |
200 long HALFSCALE; |
200 long HALFSCALE; |
201 QRgb *xelrow = 0; |
201 QRgb *xelrow = 0; |
202 QRgb *tempxelrow = 0; |
202 QRgb *tempxelrow = 0; |
203 QRgb *xP; |
203 QRgb *xP; |
204 QRgb *nxP; |
204 QRgb *nxP; |
205 int row, rowsread; |
205 int row, rowsread; |
206 int col, needtoreadrow; |
206 int col, needtoreadrow; |
207 uchar maxval = 255; |
207 uchar maxval = 255; |
208 qreal xscale, yscale; |
208 qreal xscale, yscale; |
209 long sxscale, syscale; |
209 long sxscale, syscale; |
210 long fracrowtofill, fracrowleft; |
210 long fracrowtofill, fracrowleft; |
211 long *as; |
211 long *as; |
212 long *rs; |
212 long *rs; |
213 long *gs; |
213 long *gs; |
214 long *bs; |
214 long *bs; |
215 int rowswritten = 0; |
215 int rowswritten = 0; |
216 QImage dst; |
216 QImage dst; |
217 |
217 |
218 if (d->cols > 4096) { |
218 if (d->cols > 4096) { |
219 SCALE = 4096; |
219 SCALE = 4096; |
220 HALFSCALE = 2048; |
220 HALFSCALE = 2048; |
221 } else { |
221 } else { |
222 int fac = 4096; |
222 int fac = 4096; |
223 while (d->cols * fac > 4096) { |
223 while (d->cols * fac > 4096) |
224 fac /= 2; |
224 fac /= 2; |
225 } |
225 |
226 |
226 SCALE = fac * d->cols; |
227 SCALE = fac * d->cols; |
227 HALFSCALE = fac * d->cols / 2; |
228 HALFSCALE = fac * d->cols / 2; |
228 } |
229 } |
229 |
230 |
230 xscale = (qreal)d->newcols / (qreal)d->cols; |
231 xscale = (qreal) d->newcols / (qreal) d->cols; |
231 yscale = (qreal)d->newrows / (qreal)d->rows; |
232 yscale = (qreal) d->newrows / (qreal) d->rows; |
|
233 sxscale = (long)(xscale * SCALE); |
232 sxscale = (long)(xscale * SCALE); |
234 syscale = (long)(yscale * SCALE); |
233 syscale = (long)(yscale * SCALE); |
235 |
234 |
236 if ( d->newrows != d->rows ) /* shortcut Y scaling if possible */ |
235 // shortcut Y scaling if possible |
237 tempxelrow = new QRgb[d->cols]; |
236 if (d->newrows != d->rows) |
238 |
237 tempxelrow = new QRgb[d->cols]; |
239 if ( d->hasAlpha ) { |
238 |
240 as = new long[d->cols]; |
239 if (d->hasAlpha) { |
241 for ( col = 0; col < d->cols; ++col ) |
240 as = new long[d->cols]; |
242 as[col] = HALFSCALE; |
241 for (col = 0; col < d->cols; ++col) |
|
242 as[col] = HALFSCALE; |
243 } else { |
243 } else { |
244 as = 0; |
244 as = 0; |
245 } |
245 } |
246 rs = new long[d->cols]; |
246 rs = new long[d->cols]; |
247 gs = new long[d->cols]; |
247 gs = new long[d->cols]; |
248 bs = new long[d->cols]; |
248 bs = new long[d->cols]; |
249 rowsread = 0; |
249 rowsread = 0; |
250 fracrowleft = syscale; |
250 fracrowleft = syscale; |
251 needtoreadrow = 1; |
251 needtoreadrow = 1; |
252 for ( col = 0; col < d->cols; ++col ) |
252 for (col = 0; col < d->cols; ++col) |
253 rs[col] = gs[col] = bs[col] = HALFSCALE; |
253 rs[col] = gs[col] = bs[col] = HALFSCALE; |
254 fracrowtofill = SCALE; |
254 fracrowtofill = SCALE; |
255 |
255 |
256 dst = QImage( d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32 ); |
256 dst = QImage(d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); |
257 |
257 |
258 for ( row = 0; row < d->newrows; ++row ) { |
258 for (row = 0; row < d->newrows; ++row) { |
259 /* First scale Y from xelrow into tempxelrow. */ |
259 // First scale Y from xelrow into tempxelrow. |
260 if ( d->newrows == d->rows ) { |
260 if (d->newrows == d->rows) { |
261 /* shortcut Y scaling if possible */ |
261 // shortcut Y scaling if possible |
262 tempxelrow = xelrow = scanLine(rowsread++, d->src); |
262 tempxelrow = xelrow = scanLine(rowsread++, d->src); |
263 } else { |
263 } else { |
264 while ( fracrowleft < fracrowtofill ) { |
264 while (fracrowleft < fracrowtofill) { |
265 if ( needtoreadrow && rowsread < d->rows ) { |
265 if (needtoreadrow && rowsread < d->rows) |
266 xelrow = scanLine(rowsread++, d->src); |
266 xelrow = scanLine(rowsread++, d->src); |
267 } |
267 for (col = 0, xP = xelrow; col < d->cols; ++col, ++xP) { |
268 for ( col = 0, xP = xelrow; col < d->cols; ++col, ++xP ) { |
268 if (as) { |
269 if (as) { |
269 as[col] += fracrowleft * qAlpha(*xP); |
270 as[col] += fracrowleft * qAlpha( *xP ); |
270 rs[col] += fracrowleft * qRed(*xP) * qAlpha(*xP) / 255; |
271 rs[col] += fracrowleft * qRed( *xP ) * qAlpha( *xP ) / 255; |
271 gs[col] += fracrowleft * qGreen(*xP) * qAlpha(*xP) / 255; |
272 gs[col] += fracrowleft * qGreen( *xP ) * qAlpha( *xP ) / 255; |
272 bs[col] += fracrowleft * qBlue(*xP) * qAlpha(*xP) / 255; |
273 bs[col] += fracrowleft * qBlue( *xP ) * qAlpha( *xP ) / 255; |
273 } else { |
274 } else { |
274 rs[col] += fracrowleft * qRed(*xP); |
275 rs[col] += fracrowleft * qRed( *xP ); |
275 gs[col] += fracrowleft * qGreen(*xP); |
276 gs[col] += fracrowleft * qGreen( *xP ); |
276 bs[col] += fracrowleft * qBlue(*xP); |
277 bs[col] += fracrowleft * qBlue( *xP ); |
277 } |
278 } |
278 } |
279 } |
279 fracrowtofill -= fracrowleft; |
280 fracrowtofill -= fracrowleft; |
280 fracrowleft = syscale; |
281 fracrowleft = syscale; |
281 needtoreadrow = 1; |
282 needtoreadrow = 1; |
282 } |
283 } |
283 // Now fracrowleft is >= fracrowtofill, so we can produce a row. |
284 /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */ |
284 if (needtoreadrow && rowsread < d->rows) { |
285 if ( needtoreadrow && rowsread < d->rows) { |
285 xelrow = scanLine(rowsread++, d->src); |
286 xelrow = scanLine(rowsread++, d->src); |
286 needtoreadrow = 0; |
287 needtoreadrow = 0; |
287 } |
288 } |
288 for (col = 0, xP = xelrow, nxP = tempxelrow; col < d->cols; ++col, ++xP, ++nxP) { |
289 for ( col = 0, xP = xelrow, nxP = tempxelrow; |
289 register long a, r, g, b; |
290 col < d->cols; ++col, ++xP, ++nxP ) |
290 |
291 { |
291 if (as) { |
292 register long a, r, g, b; |
292 r = rs[col] + fracrowtofill * qRed(*xP) * qAlpha(*xP) / 255; |
293 |
293 g = gs[col] + fracrowtofill * qGreen(*xP) * qAlpha(*xP) / 255; |
294 if ( as ) { |
294 b = bs[col] + fracrowtofill * qBlue(*xP) * qAlpha(*xP) / 255; |
295 r = rs[col] + fracrowtofill * qRed( *xP ) * qAlpha( *xP ) / 255; |
295 a = as[col] + fracrowtofill * qAlpha(*xP); |
296 g = gs[col] + fracrowtofill * qGreen( *xP ) * qAlpha( *xP ) / 255; |
296 if (a) { |
297 b = bs[col] + fracrowtofill * qBlue( *xP ) * qAlpha( *xP ) / 255; |
297 r = r * 255 / a * SCALE; |
298 a = as[col] + fracrowtofill * qAlpha( *xP ); |
298 g = g * 255 / a * SCALE; |
299 if ( a ) { |
299 b = b * 255 / a * SCALE; |
300 r = r * 255 / a * SCALE; |
300 } |
301 g = g * 255 / a * SCALE; |
301 } else { |
302 b = b * 255 / a * SCALE; |
302 r = rs[col] + fracrowtofill * qRed(*xP); |
303 } |
303 g = gs[col] + fracrowtofill * qGreen(*xP); |
304 } else { |
304 b = bs[col] + fracrowtofill * qBlue(*xP); |
305 r = rs[col] + fracrowtofill * qRed( *xP ); |
305 a = 0; // unwarn |
306 g = gs[col] + fracrowtofill * qGreen( *xP ); |
306 } |
307 b = bs[col] + fracrowtofill * qBlue( *xP ); |
307 r /= SCALE; |
308 a = 0; // unwarn |
308 if (r > maxval) |
309 } |
309 r = maxval; |
310 r /= SCALE; |
310 g /= SCALE; |
311 if ( r > maxval ) r = maxval; |
311 if (g > maxval) |
312 g /= SCALE; |
312 g = maxval; |
313 if ( g > maxval ) g = maxval; |
313 b /= SCALE; |
314 b /= SCALE; |
314 if (b > maxval) |
315 if ( b > maxval ) b = maxval; |
315 b = maxval; |
316 if ( as ) { |
316 if (as) { |
317 a /= SCALE; |
317 a /= SCALE; |
318 if ( a > maxval ) a = maxval; |
318 if (a > maxval) |
319 *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); |
319 a = maxval; |
320 as[col] = HALFSCALE; |
320 *nxP = qRgba((int)r, (int)g, (int)b, (int)a); |
321 } else { |
321 as[col] = HALFSCALE; |
322 *nxP = qRgb( (int)r, (int)g, (int)b ); |
322 } else { |
323 } |
323 *nxP = qRgb((int)r, (int)g, (int)b); |
324 rs[col] = gs[col] = bs[col] = HALFSCALE; |
324 } |
325 } |
325 rs[col] = gs[col] = bs[col] = HALFSCALE; |
326 fracrowleft -= fracrowtofill; |
326 } |
327 if ( fracrowleft == 0 ) { |
327 fracrowleft -= fracrowtofill; |
328 fracrowleft = syscale; |
328 if (fracrowleft == 0) { |
329 needtoreadrow = 1; |
329 fracrowleft = syscale; |
330 } |
330 needtoreadrow = 1; |
331 fracrowtofill = SCALE; |
331 } |
332 } |
332 fracrowtofill = SCALE; |
333 |
333 } |
334 /* Now scale X from tempxelrow into dst and write it out. */ |
334 |
335 if ( d->newcols == d->cols ) { |
335 // Now scale X from tempxelrow into dst and write it out. |
336 /* shortcut X scaling if possible */ |
336 if (d->newcols == d->cols) { |
337 memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols*4); |
337 // shortcut X scaling if possible |
338 } else { |
338 memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols * 4); |
339 register long a, r, g, b; |
339 } else { |
340 register long fraccoltofill, fraccolleft = 0; |
340 register long a, r, g, b; |
341 register int needcol; |
341 register long fraccoltofill, fraccolleft = 0; |
342 |
342 register int needcol; |
343 nxP = (QRgb*)dst.scanLine(rowswritten++); |
343 |
344 fraccoltofill = SCALE; |
344 nxP = (QRgb *)dst.scanLine(rowswritten++); |
345 a = r = g = b = HALFSCALE; |
345 QRgb *nxPEnd = nxP + d->newcols; |
346 needcol = 0; |
346 fraccoltofill = SCALE; |
347 for ( col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP ) { |
347 a = r = g = b = HALFSCALE; |
348 fraccolleft = sxscale; |
348 needcol = 0; |
349 while ( fraccolleft >= fraccoltofill ) { |
349 for (col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP) { |
350 if ( needcol ) { |
350 fraccolleft = sxscale; |
351 ++nxP; |
351 while (fraccolleft >= fraccoltofill) { |
352 a = r = g = b = HALFSCALE; |
352 if (needcol) { |
353 } |
353 ++nxP; |
354 if ( as ) { |
354 a = r = g = b = HALFSCALE; |
355 r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255; |
355 } |
356 g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255; |
356 if (as) { |
357 b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255; |
357 r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; |
358 a += fraccoltofill * qAlpha( *xP ); |
358 g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; |
359 if ( a ) { |
359 b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; |
360 r = r * 255 / a * SCALE; |
360 a += fraccoltofill * qAlpha(*xP); |
361 g = g * 255 / a * SCALE; |
361 if (a) { |
362 b = b * 255 / a * SCALE; |
362 r = r * 255 / a * SCALE; |
363 } |
363 g = g * 255 / a * SCALE; |
364 } else { |
364 b = b * 255 / a * SCALE; |
365 r += fraccoltofill * qRed( *xP ); |
365 } |
366 g += fraccoltofill * qGreen( *xP ); |
366 } else { |
367 b += fraccoltofill * qBlue( *xP ); |
367 r += fraccoltofill * qRed(*xP); |
368 } |
368 g += fraccoltofill * qGreen(*xP); |
369 r /= SCALE; |
369 b += fraccoltofill * qBlue(*xP); |
370 if ( r > maxval ) r = maxval; |
370 } |
371 g /= SCALE; |
371 r /= SCALE; |
372 if ( g > maxval ) g = maxval; |
372 if (r > maxval) |
373 b /= SCALE; |
373 r = maxval; |
374 if ( b > maxval ) b = maxval; |
374 g /= SCALE; |
375 if (as) { |
375 if (g > maxval) |
376 a /= SCALE; |
376 g = maxval; |
377 if ( a > maxval ) a = maxval; |
377 b /= SCALE; |
378 *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); |
378 if (b > maxval) |
379 } else { |
379 b = maxval; |
380 *nxP = qRgb( (int)r, (int)g, (int)b ); |
380 if (as) { |
381 } |
381 a /= SCALE; |
382 fraccolleft -= fraccoltofill; |
382 if (a > maxval) |
383 fraccoltofill = SCALE; |
383 a = maxval; |
384 needcol = 1; |
384 *nxP = qRgba((int)r, (int)g, (int)b, (int)a); |
385 } |
385 } else { |
386 if ( fraccolleft > 0 ) { |
386 *nxP = qRgb((int)r, (int)g, (int)b); |
387 if ( needcol ) { |
387 } |
388 ++nxP; |
388 fraccolleft -= fraccoltofill; |
389 a = r = g = b = HALFSCALE; |
389 fraccoltofill = SCALE; |
390 needcol = 0; |
390 needcol = 1; |
391 } |
391 } |
392 if (as) { |
392 if (fraccolleft > 0) { |
393 a += fraccolleft * qAlpha( *xP ); |
393 if (needcol) { |
394 r += fraccolleft * qRed( *xP ) * qAlpha( *xP ) / 255; |
394 ++nxP; |
395 g += fraccolleft * qGreen( *xP ) * qAlpha( *xP ) / 255; |
395 a = r = g = b = HALFSCALE; |
396 b += fraccolleft * qBlue( *xP ) * qAlpha( *xP ) / 255; |
396 needcol = 0; |
397 } else { |
397 } |
398 r += fraccolleft * qRed( *xP ); |
398 if (as) { |
399 g += fraccolleft * qGreen( *xP ); |
399 a += fraccolleft * qAlpha(*xP); |
400 b += fraccolleft * qBlue( *xP ); |
400 r += fraccolleft * qRed(*xP) * qAlpha(*xP) / 255; |
401 } |
401 g += fraccolleft * qGreen(*xP) * qAlpha(*xP) / 255; |
402 fraccoltofill -= fraccolleft; |
402 b += fraccolleft * qBlue(*xP) * qAlpha(*xP) / 255; |
403 } |
403 } else { |
404 } |
404 r += fraccolleft * qRed(*xP); |
405 if ( fraccoltofill > 0 ) { |
405 g += fraccolleft * qGreen(*xP); |
406 --xP; |
406 b += fraccolleft * qBlue(*xP); |
407 if (as) { |
407 } |
408 a += fraccolleft * qAlpha( *xP ); |
408 fraccoltofill -= fraccolleft; |
409 r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255; |
409 } |
410 g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255; |
410 } |
411 b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255; |
411 if (fraccoltofill > 0) { |
412 if ( a ) { |
412 --xP; |
413 r = r * 255 / a * SCALE; |
413 if (as) { |
414 g = g * 255 / a * SCALE; |
414 a += fraccolleft * qAlpha(*xP); |
415 b = b * 255 / a * SCALE; |
415 r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; |
416 } |
416 g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; |
417 } else { |
417 b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; |
418 r += fraccoltofill * qRed( *xP ); |
418 if (a) { |
419 g += fraccoltofill * qGreen( *xP ); |
419 r = r * 255 / a * SCALE; |
420 b += fraccoltofill * qBlue( *xP ); |
420 g = g * 255 / a * SCALE; |
421 } |
421 b = b * 255 / a * SCALE; |
422 } |
422 } |
423 if ( ! needcol ) { |
423 } else { |
424 r /= SCALE; |
424 r += fraccoltofill * qRed(*xP); |
425 if ( r > maxval ) r = maxval; |
425 g += fraccoltofill * qGreen(*xP); |
426 g /= SCALE; |
426 b += fraccoltofill * qBlue(*xP); |
427 if ( g > maxval ) g = maxval; |
427 } |
428 b /= SCALE; |
428 } |
429 if ( b > maxval ) b = maxval; |
429 if (nxP < nxPEnd) { |
430 if (as) { |
430 r /= SCALE; |
431 a /= SCALE; |
431 if (r > maxval) |
432 if ( a > maxval ) a = maxval; |
432 r = maxval; |
433 *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); |
433 g /= SCALE; |
434 } else { |
434 if (g > maxval) |
435 *nxP = qRgb( (int)r, (int)g, (int)b ); |
435 g = maxval; |
436 } |
436 b /= SCALE; |
437 } |
437 if (b > maxval) |
438 } |
438 b = maxval; |
439 } |
439 if (as) { |
440 |
440 a /= SCALE; |
441 if ( d->newrows != d->rows && tempxelrow )// Robust, tempxelrow might be 0 1 day |
441 if (a > maxval) |
442 delete [] tempxelrow; |
442 a = maxval; |
443 if ( as ) // Avoid purify complaint |
443 *nxP = qRgba((int)r, (int)g, (int)b, (int)a); |
444 delete [] as; |
444 } else { |
445 if ( rs ) // Robust, rs might be 0 one day |
445 *nxP = qRgb((int)r, (int)g, (int)b); |
446 delete [] rs; |
446 } |
447 if ( gs ) // Robust, gs might be 0 one day |
447 while (++nxP != nxPEnd) |
448 delete [] gs; |
448 nxP[0] = nxP[-1]; |
449 if ( bs ) // Robust, bs might be 0 one day |
449 } |
450 delete [] bs; |
450 } |
|
451 } |
|
452 |
|
453 if (d->newrows != d->rows && tempxelrow)// Robust, tempxelrow might be 0 1 day |
|
454 delete [] tempxelrow; |
|
455 if (as) // Avoid purify complaint |
|
456 delete [] as; |
|
457 if (rs) // Robust, rs might be 0 one day |
|
458 delete [] rs; |
|
459 if (gs) // Robust, gs might be 0 one day |
|
460 delete [] gs; |
|
461 if (bs) // Robust, bs might be 0 one day |
|
462 delete [] bs; |
451 |
463 |
452 return dst; |
464 return dst; |
453 } |
465 } |
454 |
466 |
455 class jpegSmoothScaler : public QImageSmoothScaler |
467 class jpegSmoothScaler : public QImageSmoothScaler |