00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #define _USE_MATH_DEFINES // for msvc
00038
00039 #include "qimageblitz.h"
00040 #include <QColor>
00041 #include <QVector>
00042 #include <cmath>
00043
00044 QImage Blitz::gradient(const QSize &size, const QColor &ca,
00045 const QColor &cb, GradientType eff)
00046 {
00047 QImage image(size, QImage::Format_RGB32);
00048 if(!size.isValid())
00049 return(image);
00050
00051 int rca, gca, bca, rcb, gcb, bcb;
00052 int rDiff = (rcb = cb.red()) - (rca = ca.red());
00053 int gDiff = (gcb = cb.green()) - (gca = ca.green());
00054 int bDiff = (bcb = cb.blue()) - (bca = ca.blue());
00055 int x, y;
00056 QRgb rgb;
00057
00058 if(eff == VerticalGradient || eff == HorizontalGradient){
00059 register int rl = rca << 16;
00060 register int gl = gca << 16;
00061 register int bl = bca << 16;
00062 QRgb *p;
00063 if(eff == VerticalGradient){
00064 int rcdelta = ((1<<16) / size.height()) * rDiff;
00065 int gcdelta = ((1<<16) / size.height()) * gDiff;
00066 int bcdelta = ((1<<16) / size.height()) * bDiff;
00067 for(y=0; y < size.height(); ++y){
00068 rl += rcdelta;
00069 gl += gcdelta;
00070 bl += bcdelta;
00071 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
00072
00073 p = (QRgb *)image.scanLine(y);
00074 for(x = 0; x < size.width(); ++x)
00075 *p++ = rgb;
00076 }
00077 }
00078 else{
00079 int rcdelta = ((1<<16) / size.width()) * rDiff;
00080 int gcdelta = ((1<<16) / size.width()) * gDiff;
00081 int bcdelta = ((1<<16) / size.width()) * bDiff;
00082 p = (QRgb *)image.scanLine(0);
00083 for(x = 0; x < size.width(); ++x){
00084 rl += rcdelta;
00085 gl += gcdelta;
00086 bl += bcdelta;
00087 *p++ = qRgb((rl>>16), (gl>>16), (bl>>16));
00088 }
00089 p = (QRgb *)image.scanLine(0);
00090 for(y = 1; y < size.height(); ++y)
00091 memcpy(image.scanLine(y), p, size.width()*sizeof(QRgb));
00092 }
00093 }
00094 else{
00095 float rfd, gfd, bfd;
00096 float rd = rca, gd = gca, bd = bca;
00097
00098 int w = size.width(), h = size.height();
00099 int dw = w*2, dh = h*2;
00100 unsigned char *xtable = new unsigned char[w*3];
00101 unsigned char *ytable = new unsigned char[h*3];
00102
00103 if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
00104 rfd = (float)rDiff/dw;
00105 gfd = (float)gDiff/dw;
00106 bfd = (float)bDiff/dw;
00107
00108 int dir;
00109 for(x=0; x < w; x++, rd+=rfd, gd+=gfd, bd+=bfd) {
00110 dir = eff == DiagonalGradient? x : w - x - 1;
00111 xtable[dir*3] = (unsigned char) rd;
00112 xtable[dir*3+1] = (unsigned char) gd;
00113 xtable[dir*3+2] = (unsigned char) bd;
00114 }
00115 rfd = (float)rDiff/dh;
00116 gfd = (float)gDiff/dh;
00117 bfd = (float)bDiff/dh;
00118 rd = gd = bd = 0;
00119 for(y = 0; y < h; y++, rd+=rfd, gd+=gfd, bd+=bfd){
00120 ytable[y*3] = (unsigned char) rd;
00121 ytable[y*3+1] = (unsigned char) gd;
00122 ytable[y*3+2] = (unsigned char) bd;
00123 }
00124
00125 for(y = 0; y < h; y++){
00126 QRgb *p = (QRgb *)image.scanLine(y);
00127 for(x = 0; x < w; x++){
00128 *p++ = qRgb(xtable[x*3] + ytable[y*3],
00129 xtable[x*3+1] + ytable[y*3+1],
00130 xtable[x*3+2] + ytable[y*3+2]);
00131 }
00132 }
00133 }
00134 else{
00135 int rSign = rDiff>0? 1: -1;
00136 int gSign = gDiff>0? 1: -1;
00137 int bSign = bDiff>0? 1: -1;
00138
00139 rfd = (float)rDiff/w;
00140 gfd = (float)gDiff/w;
00141 bfd = (float)bDiff/w;
00142
00143 rd = (float)rDiff/2;
00144 gd = (float)gDiff/2;
00145 bd = (float)bDiff/2;
00146
00147 for(x=0; x < w; x++, rd-=rfd, gd-=gfd, bd-=bfd){
00148 xtable[x*3] = (unsigned char) qAbs((int)rd);
00149 xtable[x*3+1] = (unsigned char) qAbs((int)gd);
00150 xtable[x*3+2] = (unsigned char) qAbs((int)bd);
00151 }
00152
00153 rfd = (float)rDiff/h;
00154 gfd = (float)gDiff/h;
00155 bfd = (float)bDiff/h;
00156
00157 rd = (float)rDiff/2;
00158 gd = (float)gDiff/2;
00159 bd = (float)bDiff/2;
00160
00161 for(y=0; y < h; y++, rd-=rfd, gd-=gfd, bd-=bfd){
00162 ytable[y*3] = (unsigned char) qAbs((int)rd);
00163 ytable[y*3+1] = (unsigned char) qAbs((int)gd);
00164 ytable[y*3+2] = (unsigned char) qAbs((int)bd);
00165 }
00166
00167 dw = (w+1)>>1;
00168 dh = (h+1)>>1;
00169 int x2;
00170 QRgb *sl1, *sl2;
00171 for(y = 0; y < dh; y++){
00172 sl1 = (QRgb *)image.scanLine(y);
00173 sl2 = (QRgb *)image.scanLine(qMax(h-y-1, y));
00174 for(x = 0, x2 = w-1; x < dw; x++, x2--){
00175 switch(eff){
00176 case PyramidGradient:
00177 rgb = qRgb(rcb-rSign*(xtable[x*3]+ytable[y*3]),
00178 gcb-gSign*(xtable[x*3+1]+ytable[y*3+1]),
00179 bcb-bSign*(xtable[x*3+2]+ytable[y*3+2]));
00180 break;
00181 case RectangleGradient:
00182 rgb = qRgb(rcb - rSign *
00183 qMax(xtable[x*3], ytable[y*3]) * 2,
00184 gcb - gSign *
00185 qMax(xtable[x*3+1], ytable[y*3+1]) * 2,
00186 bcb - bSign *
00187 qMax(xtable[x*3+2], ytable[y*3+2]) * 2);
00188 break;
00189 case PipeCrossGradient:
00190 rgb = qRgb(rcb - rSign *
00191 qMin(xtable[x*3], ytable[y*3]) * 2,
00192 gcb - gSign *
00193 qMin(xtable[x*3+1], ytable[y*3+1]) * 2,
00194 bcb - bSign *
00195 qMin(xtable[x*3+2], ytable[y*3+2]) * 2);
00196 break;
00197 case EllipticGradient:
00198 default:
00199 rgb = qRgb(rcb - rSign *
00200 (int)std::sqrt((xtable[x*3]*xtable[x*3] +
00201 ytable[y*3]*ytable[y*3])*2.0f),
00202 gcb - gSign *
00203 (int)std::sqrt((xtable[x*3+1]*xtable[x*3+1] +
00204 ytable[y*3+1]*ytable[y*3+1])*2.0f),
00205 bcb - bSign *
00206 (int)std::sqrt((xtable[x*3+2]*xtable[x*3+2] +
00207 ytable[y*3+2]*ytable[y*3+2])*2.0f));
00208 break;
00209 }
00210 sl1[x] = sl2[x] = rgb;
00211 sl1[x2] = sl2[x2] = rgb;
00212 }
00213 }
00214 }
00215 delete [] xtable;
00216 delete [] ytable;
00217 }
00218 return(image);
00219 }
00220
00221 QImage Blitz::grayGradient(const QSize &size, unsigned char ca,
00222 unsigned char cb, GradientType eff)
00223 {
00224 QImage image(size, QImage::Format_Indexed8);
00225 if(!size.isValid())
00226 return(image);
00227 QVector<QRgb> colorTable(256);
00228 for(int i=0; i < 256; ++i)
00229 colorTable[i] = qRgba(i, i, i, 255);
00230 image.setColorTable(colorTable);
00231
00232 int diff = cb - ca;
00233 int x, y;
00234 unsigned char idx;
00235
00236 if(eff == VerticalGradient || eff == HorizontalGradient){
00237 register int val = ca << 16;
00238 unsigned char *p;
00239 if(eff == VerticalGradient){
00240 int delta = ((1<<16) / size.height()) * diff;
00241 for(y=0; y < size.height(); ++y){
00242 val += delta;
00243 idx = val >> 16;
00244 p = image.scanLine(y);
00245 for(x = 0; x < size.width(); ++x)
00246 *p++ = idx;
00247 }
00248 }
00249 else{
00250 int delta = ((1<<16) / size.width()) * diff;
00251 p = image.scanLine(0);
00252 for(x = 0; x < size.width(); ++x){
00253 val += delta;
00254 *p++ = val >> 16;
00255 }
00256 p = image.scanLine(0);
00257 for(y = 1; y < size.height(); ++y)
00258 memcpy(image.scanLine(y), p, image.bytesPerLine());
00259 }
00260 }
00261 else{
00262 float delta, val=ca;
00263
00264 unsigned int w = size.width(), h = size.height();
00265 unsigned char *xtable = new unsigned char[w];
00266 unsigned char *ytable = new unsigned char[h];
00267 w*=2, h*=2;
00268
00269 if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
00270 delta = (float)diff/w;
00271 int dir;
00272 for(x=0; x < size.width(); x++, val+=delta){
00273 dir = eff == DiagonalGradient? x : size.width() - x - 1;
00274 xtable[dir] = (unsigned char) val;
00275 }
00276 delta = (float)diff/h;
00277 val = 0;
00278 for(y = 0; y < size.height(); y++, val+=delta)
00279 ytable[y] = (unsigned char) val;
00280
00281 for(y = 0; y < size.height(); y++){
00282 unsigned char *p = image.scanLine(y);
00283 for(x = 0; x < size.width(); x++)
00284 *p++ = xtable[x] + ytable[y];
00285 }
00286 }
00287 else{
00288 int sign = diff>0? 1: -1;
00289 delta = (float)diff / size.width();
00290 val = (float)diff/2;
00291 for(x=0; x < size.width(); x++, val-=delta)
00292 xtable[x] = (unsigned char) qAbs((int)val);
00293
00294 delta = (float)diff/size.height();
00295 val = (float)diff/2;
00296 for(y=0; y < size.height(); y++, val-=delta)
00297 ytable[y] = (unsigned char) qAbs((int)val);
00298
00299 int w = (size.width()+1)>>1;
00300 int h = (size.height()+1)>>1;
00301 int x2;
00302 unsigned char *sl1, *sl2;
00303 for(y = 0; y < h; y++){
00304 sl1 = image.scanLine(y);
00305 sl2 = image.scanLine(qMax(size.height()-y-1, y));
00306 for(x = 0, x2 = size.width()-1; x < w; x++, x2--){
00307 switch(eff){
00308 case PyramidGradient:
00309 idx = cb-sign*(xtable[x]+ytable[y]);
00310 break;
00311 case RectangleGradient:
00312 idx = cb-sign*qMax(xtable[x], ytable[y])*2;
00313 break;
00314 case PipeCrossGradient:
00315 idx = cb-sign*qMin(xtable[x], ytable[y])*2;
00316 break;
00317 case EllipticGradient:
00318 default:
00319 idx = cb - sign *
00320 (int)std::sqrt((xtable[x]*xtable[x] +
00321 ytable[y]*ytable[y])*2.0f);
00322 break;
00323 }
00324 sl1[x] = sl2[x] = idx;
00325 sl1[x2] = sl2[x2] = idx;
00326 }
00327 }
00328 }
00329 delete [] xtable;
00330 delete [] ytable;
00331 }
00332 return(image);
00333 }
00334
00335 QImage Blitz::unbalancedGradient(const QSize &size, const QColor &ca,
00336 const QColor &cb, GradientType eff,
00337 int xfactor, int yfactor)
00338 {
00339 QImage image(size, QImage::Format_RGB32);
00340 if(!size.isValid())
00341 return image;
00342
00343 int dir;
00344 bool _xanti = (xfactor < 0);
00345 bool _yanti = (yfactor < 0);
00346 xfactor = qBound(1, qAbs(xfactor), 200);
00347 yfactor = qBound(1, qAbs(yfactor), 200);
00348
00349
00350 float xbal = xfactor/30.0f/size.width();
00351 float ybal = yfactor/30.0f/size.height();
00352 float rat;
00353
00354 register int x, y;
00355 int rca, gca, bca, rcb, gcb, bcb;
00356 int rDiff = (rcb = cb.red()) - (rca = ca.red());
00357 int gDiff = (gcb = cb.green()) - (gca = ca.green());
00358 int bDiff = (bcb = cb.blue()) - (bca = ca.blue());
00359
00360 if(eff == VerticalGradient || eff == HorizontalGradient){
00361 QRgb *p;
00362 if(eff == VerticalGradient){
00363 QRgb rgbRow;
00364 for(y=0; y < size.height(); y++){
00365 dir = _yanti ? y : size.height() - 1 - y;
00366 rat = 1 - std::exp( - (float)y * ybal );
00367 p = (QRgb *) image.scanLine(dir);
00368 rgbRow = qRgb(rcb - (int) ( rDiff * rat ),
00369 gcb - (int) ( gDiff * rat ),
00370 bcb - (int) ( bDiff * rat ));
00371 for(x = 0; x < size.width(); x++)
00372 *p++ = rgbRow;
00373 }
00374 }
00375 else{
00376 p = (QRgb *)image.scanLine(0);
00377 for(x = 0; x < size.width(); x++){
00378 dir = _xanti ? x : size.width() - 1 - x;
00379 rat = 1 - std::exp( - (float)x * xbal );
00380 p[dir] = qRgb(rcb - (int) ( rDiff * rat ),
00381 gcb - (int) ( gDiff * rat ),
00382 bcb - (int) ( bDiff * rat ));
00383 }
00384
00385 p = (QRgb *)image.scanLine(0);
00386 for(y = 1; y < size.height(); ++y){
00387 memcpy(image.scanLine(y), p,
00388 size.width()*sizeof(QRgb));
00389 }
00390 }
00391 }
00392 else{
00393 int w=size.width(), h=size.height();
00394 unsigned char *xtable = new unsigned char[w*3];
00395 unsigned char *ytable = new unsigned char[h*3];
00396 QRgb *p;
00397
00398 if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
00399 for(x = 0; x < w; x++){
00400 dir = _xanti ? x : w - 1 - x;
00401 rat = 1 - std::exp( - (float)x * xbal );
00402
00403 xtable[dir*3] = (unsigned char) ( rDiff/2 * rat );
00404 xtable[dir*3+1] = (unsigned char) ( gDiff/2 * rat );
00405 xtable[dir*3+2] = (unsigned char) ( bDiff/2 * rat );
00406 }
00407
00408 for(y = 0; y < h; y++){
00409 dir = _yanti ? y : h - 1 - y;
00410 rat = 1 - std::exp( - (float)y * ybal );
00411
00412 ytable[dir*3] = (unsigned char) ( rDiff/2 * rat );
00413 ytable[dir*3+1] = (unsigned char) ( gDiff/2 * rat );
00414 ytable[dir*3+2] = (unsigned char) ( bDiff/2 * rat );
00415 }
00416
00417 for(y = 0; y < h; y++){
00418 p = (QRgb *)image.scanLine(y);
00419 for(x = 0; x < w; x++){
00420 *p++ = qRgb(rcb - (xtable[x*3] + ytable[y*3]),
00421 gcb - (xtable[x*3+1] + ytable[y*3+1]),
00422 bcb - (xtable[x*3+2] + ytable[y*3+2]));
00423 }
00424 }
00425 }
00426 else{
00427 int rSign = rDiff>0? 1: -1;
00428 int gSign = gDiff>0? 1: -1;
00429 int bSign = bDiff>0? 1: -1;
00430
00431 for(x = 0; x < w; x++){
00432 dir = _xanti ? x : w - 1 - x;
00433 rat = 1 - std::exp( - (float)x * xbal );
00434
00435 xtable[dir*3] = (unsigned char) qAbs((int)(rDiff*(0.5-rat)));
00436 xtable[dir*3+1] = (unsigned char) qAbs((int)(gDiff*(0.5-rat)));
00437 xtable[dir*3+2] = (unsigned char) qAbs((int)(bDiff*(0.5-rat)));
00438 }
00439
00440 for(y = 0; y < h; y++){
00441 dir = _yanti ? y : h - 1 - y;
00442 rat = 1 - std::exp( - (float)y * ybal );
00443
00444 ytable[dir*3] = (unsigned char) qAbs((int)(rDiff*(0.5-rat)));
00445 ytable[dir*3+1] = (unsigned char) qAbs((int)(gDiff*(0.5-rat)));
00446 ytable[dir*3+2] = (unsigned char) qAbs((int)(bDiff*(0.5-rat)));
00447 }
00448
00449 for(y = 0; y < h; y++){
00450 p = (QRgb *)image.scanLine(y);
00451 for(x = 0; x < w; x++) {
00452 if (eff == PyramidGradient){
00453 *p++ = qRgb(rcb-rSign*(xtable[x*3]+ytable[y*3]),
00454 gcb-gSign*(xtable[x*3+1]+ytable[y*3+1]),
00455 bcb-bSign*(xtable[x*3+2]+ytable[y*3+2]));
00456 }
00457 else if (eff == RectangleGradient){
00458 *p++ = qRgb(rcb - rSign *
00459 qMax(xtable[x*3], ytable[y*3]) * 2,
00460 gcb - gSign *
00461 qMax(xtable[x*3+1], ytable[y*3+1]) * 2,
00462 bcb - bSign *
00463 qMax(xtable[x*3+2], ytable[y*3+2]) * 2);
00464 }
00465 else if (eff == PipeCrossGradient){
00466 *p++ = qRgb(rcb - rSign *
00467 qMin(xtable[x*3], ytable[y*3]) * 2,
00468 gcb - gSign *
00469 qMin(xtable[x*3+1], ytable[y*3+1]) * 2,
00470 bcb - bSign *
00471 qMin(xtable[x*3+2], ytable[y*3+2]) * 2);
00472 }
00473 else if (eff == EllipticGradient){
00474 *p++ = qRgb(rcb - rSign *
00475 (int)std::sqrt((xtable[x*3]*xtable[x*3] +
00476 ytable[y*3]*ytable[y*3])*2.0),
00477 gcb - gSign *
00478 (int)std::sqrt((xtable[x*3+1]*xtable[x*3+1] +
00479 ytable[y*3+1]*ytable[y*3+1])*2.0),
00480 bcb - bSign *
00481 (int)std::sqrt((xtable[x*3+2]*xtable[x*3+2] +
00482 ytable[y*3+2]*ytable[y*3+2])*2.0));
00483 }
00484 }
00485 }
00486 }
00487 delete [] xtable;
00488 delete [] ytable;
00489 }
00490 return(image);
00491 }
00492
00493 QImage Blitz::grayUnbalancedGradient(const QSize &size, unsigned char ca,
00494 unsigned char cb, GradientType eff,
00495 int xfactor, int yfactor)
00496 {
00497 QImage image(size, QImage::Format_Indexed8);
00498 if(!size.isValid())
00499 return(image);
00500 QVector<QRgb> colorTable(256);
00501 for(int i=0; i < 256; ++i)
00502 colorTable[i] = qRgba(i, i, i, 255);
00503 image.setColorTable(colorTable);
00504
00505 int dir;
00506 bool _xanti = (xfactor < 0);
00507 bool _yanti = (yfactor < 0);
00508 xfactor = qBound(1, qAbs(xfactor), 200);
00509 yfactor = qBound(1, qAbs(yfactor), 200);
00510 float xbal = xfactor/30.0f/size.width();
00511 float ybal = yfactor/30.0f/size.height();
00512 float rat;
00513
00514 register int x, y;
00515 int diff = cb-ca;
00516
00517 if(eff == VerticalGradient || eff == HorizontalGradient){
00518 unsigned char *p;
00519 if(eff == VerticalGradient){
00520 unsigned char idx;
00521 for(y=0; y < size.height(); y++){
00522 dir = _yanti ? y : size.height() - 1 - y;
00523 rat = 1 - std::exp( - (float)y * ybal );
00524 p = image.scanLine(dir);
00525 idx = cb - (int)( diff * rat );
00526 for(x = 0; x < size.width(); x++)
00527 *p++ = idx;
00528 }
00529 }
00530 else{
00531 p = image.scanLine(0);
00532 for(x = 0; x < size.width(); x++){
00533 dir = _xanti ? x : size.width() - 1 - x;
00534 rat = 1 - std::exp( - (float)x * xbal );
00535 p[dir] = cb - (int)( diff * rat );
00536 }
00537
00538 p = image.scanLine(0);
00539 for(y = 1; y < size.height(); ++y)
00540 memcpy(image.scanLine(y), p, image.bytesPerLine());
00541 }
00542 }
00543 else{
00544 int w=size.width(), h=size.height();
00545 unsigned char *xtable = new unsigned char[w];
00546 unsigned char *ytable = new unsigned char[h];
00547 unsigned char *p;
00548
00549 if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
00550 for(x = 0; x < w; x++){
00551 dir = _xanti ? x : w - 1 - x;
00552 rat = 1 - std::exp( - (float)x * xbal );
00553 xtable[dir] = (unsigned char) ( diff/2 * rat );
00554 }
00555
00556 for(y = 0; y < h; y++){
00557 dir = _yanti ? y : h - 1 - y;
00558 rat = 1 - std::exp( - (float)y * ybal );
00559 ytable[dir] = (unsigned char) ( diff/2 * rat );
00560 }
00561
00562 for(y = 0; y < h; y++){
00563 p = image.scanLine(y);
00564 for(x = 0; x < w; x++)
00565 *p++ = cb - (xtable[x] + ytable[y]);
00566 }
00567 }
00568 else{
00569 int sign = diff>0? 1: -1;
00570 for(x = 0; x < w; x++){
00571 dir = _xanti ? x : w - 1 - x;
00572 rat = 1 - std::exp( - (float)x * xbal );
00573 xtable[dir] = (unsigned char) qAbs((int)(diff*(0.5-rat)));
00574 }
00575
00576 for(y = 0; y < h; y++){
00577 dir = _yanti ? y : h - 1 - y;
00578 rat = 1 - std::exp( - (float)y * ybal );
00579 ytable[dir] = (unsigned char) qAbs((int)(diff*(0.5-rat)));
00580 }
00581
00582 for(y = 0; y < h; y++){
00583 p = image.scanLine(y);
00584 for(x = 0; x < w; x++) {
00585 if (eff == PyramidGradient)
00586 *p++ = cb-sign*(xtable[x]+ytable[y]);
00587 else if (eff == RectangleGradient)
00588 *p++ = cb -sign*qMax(xtable[x], ytable[y])*2;
00589 else if (eff == PipeCrossGradient)
00590 *p++ = cb-sign*qMin(xtable[x], ytable[y])*2;
00591 else if (eff == EllipticGradient)
00592 *p++ = cb-sign * (int)std::sqrt((xtable[x]*xtable[x] +
00593 ytable[y]*ytable[y])*2.0);
00594 }
00595 }
00596 }
00597 delete [] xtable;
00598 delete [] ytable;
00599 }
00600 return(image);
00601 }
00602